Какой самый быстрый способ отрисовки форматированного текста в Win32 API?

#c #c #windows #winapi

#c #c #Windows #winapi

Вопрос:

Я внедряю текстовый редактор на C , просто используя vanilla Win32 API, и пытаюсь найти наилучший способ реализации подсветки синтаксиса. Я знаю, что существуют существующие элементы управления, такие как scintilla, но я делаю это ради удовольствия, поэтому хочу выполнить большую часть работы сам. Я также хочу, чтобы он был быстрым и легким.

Из того, что я узнал на данный момент, похоже, что самой низкоуровневой опцией для отрисовки текста в GDI является TextOut функция. Однако, если мне нужно постоянно менять цвет шрифта, это означает, что мне нужно будет выполнить много вызовов TextOut , чтобы отрисовать одно тело текста со смешанным форматированием. Это неэффективно? Когда будут реализованы подсветка синтаксиса и элементы управления форматированным текстом, будут ли они, скорее всего, использоваться TextOut за кулисами или есть какой-то другой способ? Является ли любой другой метод отрисовки текста в GDI просто оболочкой более высокого уровня TextOut ?

Комментарии:

1. Получить его правильно уже непросто. Отображение текста с помощью Uniscribe — хорошее введение в проблемы, которые вам нужно будет решить.

Ответ №1:

И DrawText, и TextOut являются оболочками для ExtTextOut, поэтому ExtTextOut — это низкоуровневый API. По моему опыту, ExtTextOut работает довольно быстро, поэтому я сомневаюсь, что вы увидите какие-либо проблемы с производительностью самого ExtTextOut. Однако создание / выбор шрифтов может быть источником проблем с производительностью, поэтому, если вы переключаетесь между шрифтами, вы можете добиться значительного увеличения производительности за счет кэширования и повторного использования шрифтов (HFONT), а не каждый раз создавать шрифт / SelectObject / DeleteObject. По сути, при первом вызове SelectObject после создания нового шрифта Windows выполнит процесс подбора шрифта, чтобы найти наилучший физический шрифт для запрошенного вами логического шрифта. Это довольно сложный процесс, поэтому вы хотите свести к минимуму количество раз, которое происходит в ситуациях, когда важна производительность.

Много лет назад я разработал расширенный элемент управления редактированием, который, по сути, был мини-версией Microsoft Word. Я использовал ExtTextOut в качестве основной рабочей лошадки для всего текстового вывода. Элемент управления будет поддерживать кэш шрифтов, состоящий из самых последних использованных шрифтов (размер кэша по умолчанию составлял 10 шрифтов). Он поддерживал верстку WYSIWYG, так что фактически он выполнял всю верстку с использованием принтера DC и шрифтов, а затем выводил версию, совместимую с экраном, с использованием screen DC и похожих шрифтов, так что потребовалось много дополнительной работы, которая, вероятно, неприменима к вашей ситуации. Несмотря на это, производительность была превосходной на типичном оборудовании того времени (например, Pentium с частотой 266 МГц).

Комментарии:

1. Это не совсем точно. Например, ExtTextOut в свою очередь использует API, подобные Uniscribe. А это, в свою очередь, может выполнить замену шрифта за вас. Итак, если вы ищете «низкоуровневый» API, Uniscribe может быть лучше. В нем есть примитивы типа ScriptItemize «Разбивает строку Unicode на элементы индивидуальной формы».

2. @MSalters: Это правда, что ExtTextOut может использовать API Uniscribe, но Uniscribe в конечном итоге вызывает ExtTextOut для выполнения фактического рендеринга, поэтому я бы все равно утверждал, что ExtTextOut — это низкоуровневый API (подробности см. По этой ссылке: www.catch22.net/tuts/neatpad/11 ). Тем не менее, Uniscribe может быть лучшим выбором с точки зрения функциональности, но «самый быстрый способ» отрисовки текста — ExtTextOut.

3. «DrawText и TextOut являются оболочками для ExtTextOut»: это верно для Windows 7, но не применимо к Windows XP. Кроме того, PolyTextOut — единственный API отрисовки текста, который не вызывает ExtTextOut. Возможно, было бы интересно протестировать скорость PolyTextOut.

4. Еще одно улучшение скорости заключается в том, что такие API, как GetTextExtentPoint32 и другие, не позволяют измерять строку перед ее отрисовкой. Если вам нужно отрисовать несколько строк одну за другой (например, каждое слово разного цвета), вы можете получить текущую позицию отрисовки с помощью GetCurrentPositionEx и изменить ее с помощью MoveToEx.

5. Как вы кэшируете шрифты, когда вам приходится манипулировать дескрипторами DC в первую очередь? Например, DC, который вы получаете при вызове BeginPaint , копируется из кэшированного DC, в котором выбран шрифт по умолчанию, так как же вы кэшируете шрифт [и выбранный шрифт]? Насколько я понял, когда вы получаете подобный DC, вам приходится полностью выбирать шрифт, даже если у вас уже есть готовый дескриптор шрифта из предыдущего.

Ответ №2:

Вместо того, чтобы размышлять, какая функция «отрисовки текста» самая быстрая, вероятно, гораздо выгоднее подумать о том, «Как я могу вообще свести к минимуму объем текста, который мне нужно отрисовывать», с умом понимая, что перерисовывать / аннулировать при изменении текста или как можно кэшировать отрисованный текст для прокрутки.

Комментарии:

1. Интересный момент. Я не изучал кэширование. Спасибо за идею.

2. Это не ответ на вопрос. Например, если вы выводите большой журнал в окно или список, в нем нет ничего, что можно было бы использовать повторно или опустить.

Ответ №3:

Для сложного использования вы, вероятно, захотите, DrawText поскольку это дает вам больше контроля, чем TextOut . Он имеет некоторую базовую поддержку форматирования, но меньше, чем вам нужно для редактора. Следующий шаг — редактор расширенного текста из библиотеки common controls, который в значительной степени позаботится обо всем этом за вас.

Комментарии:

1. DrawText Это просто удобная функция, которая действует как оболочка вокруг TextOut или она полностью отделена? Я провел несколько очень простых тестов и обнаружил, что TextOut это заметно быстрее. Я знаком с расширенными элементами управления редактированием, такими как класс RICHEDIT window из Riched32.dll но я хочу сам реализовать элемент управления форматированным текстом, если это возможно, используя функции низкого уровня.

2. Win32 API -это в основном «черный ящик», но если вы запишете DrawText вызовы к метафайлу и проверите его, вы увидите последовательность вызовов к ExtTextOutW .