Поделиться через


Шрифты переменных OpenType

В этом разделе описаны шрифты переменных OpenType, их поддержка в DirectWrite и Direct2D и их использование в приложении. 

Что такое шрифты переменных OpenType?

Версия 1.8 спецификации формата шрифта OpenType представила новое расширение для формата, известного как варианты шрифтов OpenType. Шрифты, использующие эти расширения, называются шрифтами переменных OpenType. Шрифт переменной OpenType — это один шрифт, который может вести себя как несколько шрифтов, используя непрерывную интерполяцию между различными макетами, все, определенные в одном шрифте.

Шрифт переменной OpenType может определять непрерывный вариант его дизайна вдоль одной или нескольких независимых осей, таких как вес или ширина:

 

Отображение шрифта переменной OpenType с помощью буквы G и отображения различных вариантов вдоль горизонтальной оси ширины и вертикальной оси веса.

Разработчик шрифта определяет набор осей вариантов, используемых в заданном шрифте. Эти оси могут включать набор известных (или зарегистрированных) осей вариантов, таких как вес и ширина, но они также могут включать произвольные пользовательские оси вариантов, определенные разработчиком шрифтов.  

Выбрав набор осей вариантов для шрифта, разработчик шрифта определяет абстрактное, n-размерное пространство вариантов дизайна для шрифта. Текстовые подсистемы могут указывать потенциально любую позицию или экземпляр в пределах этого непрерывного пространства для размещения и отрисовки текста. 

Разработчик шрифтов также может выбирать и назначать имена определенным экземплярам в пространстве вариантов конструктора; они называются именованными экземплярами. Например, шрифт с вариацией веса может поддерживать непрерывные изменения между очень легкими и очень тяжелыми штрихами, в то время как разработчик шрифта выбрал определенные весы вдоль этого континуума и назначил им имена, такие как "Light", "Regular" и "Semibold". 

Формат шрифта переменной OpenType использует таблицы данных, найденные в традиционных шрифтах OpenType, а также некоторые дополнительные таблицы, описывающие изменение значений различных элементов данных для разных экземпляров. Формат обозначает один экземпляр вариантов как "экземпляр по умолчанию", который использует традиционные таблицы для получения значений по умолчанию. Все остальные экземпляры зависят от данных по умолчанию и других разностных данных. Например, таблица "glyf" может иметь описание кривой Bezier для номинальной глифовой фигуры, которая является фигурой, используемой для экземпляра по умолчанию, в то время как таблица gvar будет описывать, как точки управления Bezier для глифа корректируются для других экземпляров. Аналогичным образом другие значения шрифта могут иметь номинальное значение и разностные данные, описывающие изменение этих значений для разных экземпляров; Например, метрики x-height и другие метрики на уровне шрифта или глиф-привязки меток и корректировки кернинга. 

Так как шрифты переменных могут поддерживать произвольный набор осей вариантов, им требуется расширяемая модель семейств шрифтов, которая более непосредственно отражает, как конструкторы шрифтов создают семейства шрифтов: семейство шрифтов определяется именем семейства шрифтов и определенными характеристиками конструктора, которые являются константными, с произвольным числом (определяемым разработчиком шрифтов) способов, в которых проект может отличаться. Одно семейство шрифтов может быть создано с вариантами для веса, но другое семейство шрифтов может быть создано с вариантами x-height, serif-size, funkiness или независимо от того, что требует разработчик шрифта. В этой модели выбор лица шрифта лучше всего описан с помощью общего или "предпочтительного" или "типографического", имени семейства, а также набора пар "ключ-значение", каждый из которых представляет вид вариации и конкретное значение, с типами вариаций в целом расширяемым набором. Это общее понятие семейства шрифтов может применяться к традиционным, не переменным шрифтам, а также к переменным шрифтам. Например, в рамках этой общей модели типографической семьи семейство "Selawik VF" может иметь вариации для веса, оптического размера и засечек дизайна, с такими экземплярами, как "Semilight Banner Sans". 

Однако некоторые существующие реализации программного обеспечения, включая существующие API DirectWrite, могут быть разработаны при условии, что более ограниченная модель семейств шрифтов. Например, некоторые приложения могут предположить, что семейство шрифтов может иметь в большинстве случаев обычные, полужирные, курсивные и полужирные варианты. Существующие интерфейсы IDWriteFontCollection и IDWriteFontFamily предполагает модель семейства "вес/растянутый/стиль" ("WSS"), что позволяет указывать варианты в семействе с помощью DWRITE_FONT_WEIGHT, DWRITE_FONT_STRETCH или DWRITE_FONT_STYLE перечислений в качестве параметров. Принимая предыдущий пример, оптический размер и засеченные оси не будут рассматриваться как внутренние оси семейства в модели WSS. 

Для полной поддержки шрифтов переменных потребуется API, позволяющие указать член семьи с потенциально несколькими параметрами, как определено шрифтом. Но существующие проекты API могут обеспечить частичную поддержку шрифтов переменных путем проецирования именованных экземпляров, определенных в переменном шрифте в более ограниченные модели семейства шрифтов. В предыдущем примере "Selawik VF Semilight Banner Sans" можно проецировать в модель WSS как семейство Selawik VF Banner Sans с "Semilight" в качестве варианта веса. 

Например, рассмотрим семейство шрифтов типографических шрифтов, например Sitka, с вариантами веса и оптического размера. Именованные варианты в семье включают Sitka Text Regular и Sitka Баннер Полужирный (плюс многие другие). Типографическое семейство — "Sitka", в то время как имена лиц для этих вариантов в модели типографической семьи будут иметь значение "Text Regular" и "Баннер полужирный". Модели с четырьмя членами и семейства WSS не позволяют использовать варианты оптического размера в семье, поэтому различия оптического размера должны рассматриваться как различия на уровне семьи. В следующей таблице показано, как выбор шрифтов из семейства типов Sitka будет обрабатываться в модели семейства WSS:

Типографическая модель семейства

Модель семейства WSS

Семья

Лицо

Семья

Лицо

Ситка

Обычный текст

Ситка текст

Регулярный

Ситка

Баннер полужирным шрифтом

Ситка Баннер

Смелый

Ситка

Заголовок курсив

Ситка Подпись

Курсив

 

Проекция имен из типографической модели семейства в модель семейства WSS может применяться к шрифтам, не изменяям, и к именованным экземплярам шрифтов переменных. Это невозможно сделать, однако, для других неинтернационных экземпляров из пространства непрерывных вариантов конструктора переменной шрифта. По этой причине для поддержки полной функциональности шрифтов переменных потребуется API- интерфейсы, предназначенные для ссылки на лица в семействе типографических типов с точки зрения ограниченного набора значений вариантов осей и осей. 

Поддержка шрифта переменной OpenType в DirectWrite

По состоянию на выпуск Windows 10 Creators Update формат шрифта переменной OpenType по-прежнему очень новый, и поставщики шрифтов, платформы и приложения по-прежнему находятся в процессе реализации нового формата. Это обновление предоставляет начальную реализацию этого формата в DirectWrite. 

Внутренние элементы DirectWrite были обновлены для поддержки шрифтов переменных OpenType. Используя текущие API, это обеспечивает поддержку всех именованных экземпляров шрифта переменной. Эту поддержку можно использовать для полных рабочих процессов— от перечисления именованных экземпляров, выбора именованного экземпляра, использования в макете и формировании, для отрисовки и печати. Для преимуществ приложений, которые также используют текстовый взаимодействие GDI для определенных операций, аналогичная поддержка также добавлена в существующие API GDI. 

В Windows 10 Creators Update DirectWrite не поддерживает произвольные экземпляры, использующие возможность непрерывного изменения шрифтов переменных.

Во многих операциях поведение в DirectWrite именованных экземпляров шрифта переменной не может отличаться от поведения шрифтов, не являющихся переменными. И так как поддержка предоставляется с помощью существующих API DirectWrite, именованные экземпляры шрифтов переменных могут работать даже во многих существующих приложениях DirectWrite без каких-либо изменений. Однако исключения могут применяться в некоторых ситуациях:

  • Если приложение обрабатывает данные шрифта непосредственно для определенных операций. Например, если приложение считывает данные структуры глифа непосредственно из файла шрифта, чтобы создать определенные визуальные эффекты.
  • Если приложение использует стороннюю библиотеку для определенных операций. Например, если приложение использует DirectWrite для макета, чтобы получить окончательные индексы и позиции глифов, но затем использует стороннюю библиотеку для отрисовки.
  • Если приложение внедряет данные шрифта в документ или каким-то другим способом передает данные шрифта в подчиненный процесс.

Если операции выполняются с помощью реализаций, которые не поддерживают шрифты переменных, эти операции могут не выдавать ожидаемые результаты. Например, позиции глифов можно вычислить для одного именованного экземпляра шрифта переменной, но глифы могут отображаться при условии, что другой именованный экземпляр. В зависимости от реализации приложения результаты могут работать в некоторых контекстах, но не в других контекстах, в которых могут использоваться другие библиотеки. Например, текст может отображаться правильно на экране, но не при печати. Если комплексные рабочие процессы реализуются только с помощью DirectWrite, можно ожидать правильное поведение именованных экземпляров шрифта переменной. 

Так как существующие API DirectWrite поддерживают выбор лиц с помощью модели веса или растяжения или стиля, именованные экземпляры шрифтов, которые используют другие оси вариантов, будут проецироваться из общей типографической семейной модели в модель WSS, как описано выше. Это зависит от шрифта переменной, включая таблицу "атрибуты стиля" ('STAT') с вложенными таблицами со значением оси, которые DWrite использует для различения маркеров имен лица, которые определяют вес, растяжения или атрибуты стиля от маркеров, относящихся к другим осям вариантов.  

Если шрифт переменной не содержит таблицу "STAT", так как требуется для шрифтов переменных в спецификации OpenType, DirectWrite будет рассматривать шрифт как не переменный шрифт, содержащий только экземпляр по умолчанию.  

Если шрифт содержит таблицу STAT, но она не включает соответствующие вложенные таблицы для осей, это может привести к непредвиденным результатам, таким как наличие нескольких лиц с одинаковыми именами лиц. Такие шрифты в настоящее время не поддерживаются. 

Спецификация OpenType позволяет представлять данные структуры глифа в одном из двух форматов: используя таблицу glyf, которая использует формат структуры и указания TrueType или использует таблицу CFF, в которой используется представление "Формат шрифта" (CFF). В переменном шрифте с контурами TrueType таблица glyf продолжает использоваться и дополняется таблицей gvar, которая предоставляет данные вариантов для контуров. Это означает, что экземпляр по умолчанию шрифта переменной с контурами TrueType использует только традиционные таблицы OpenType, которые будут поддерживаться в старом программном обеспечении без поддержки шрифтов переменной. Однако в переменном шрифте с контурами CFF таблица CFF заменяется таблицей CFF2, которая инкапсулирует данные структуры по умолчанию и связанные данные вариантов в одной таблице. Данные CFF обрабатываются отдельным растеризатором, используемым для данных TrueType, а для таблицы CFF2 требуется обновленный растризатор CFF, имеющий поддержку CFF2. Таблица CFF2 не может обрабатываться старыми растризаторами CFF. Для переменной шрифта с данными структуры CFF это означает, что даже экземпляр по умолчанию не будет работать в более старом программном обеспечении. 

В Windows 10 Creators Update DirectWrite не поддерживает шрифты переменных с данными структуры CFF с помощью таблицы CFF2. 

Использование шрифтов переменных OpenType

Шрифты переменных OpenType можно легко использовать, учитывая текущие ограничения, указанные выше:

  • В настоящее время поддерживаются только именованные экземпляры шрифта переменной.
  • В настоящее время поддерживаются только переменные шрифты, использующие данные структуры glyph TrueType (а не структуры CFF). 
  • Для шрифтов, использующих оси конструктора, отличных от веса, растяжения или стиля, именованные экземпляры будут проецироваться в модель семейства WSS, что может привести к тому, что некоторые именованные экземпляры появляются в виде отдельных семейств (как и в прошлом для не переменных шрифтов). Для поддержки этого переменные шрифты должны иметь таблицу "STAT", которая включает соответствующие вложенные таблицы с значением оси.
  • Именованные экземпляры шрифтов переменных поддерживаются в API DirectWrite, но если некоторые операции выполняются в старых реализациях, которые не поддерживают шрифты переменных, они могут привести к неправильным результатам. 
  • Некоторые API DirectWrite используют перечисления DWRITE_FONT_WEIGHT, DWRITE_FONT_STRETCH и DWRITE_FONT_STYLE для указания весовых атрибутов, атрибутов растяжения и стиля при выборе лиц. Если шрифт переменной использует соответствующие оси вариантов, но имеет множество именованных экземпляров, требующих более детальной детализации, в этих API не все именованные экземпляры будут выбираться.

Шрифты переменных OpenType, соответствующие этим требованиям, можно установить из оболочки Windows так же, как и другие шрифты OpenType, а также использовать в пользовательских наборах шрифтов, созданных приложением.  

При установке в системе все именованные экземпляры шрифта переменной будут включены в набор шрифтов, возвращаемый путем вызова метода IDWriteFontFamily3::GetSystemFontSet. Обратите внимание, что набор шрифтов — это плоский список без иерархии группирования семейств, но каждый элемент в наборе имеет свойство имени семейства на основе модели семейства WSS. Набор шрифтов можно отфильтровать для определенного именованного экземпляра с помощью методов IDWriteFontSet::GetMatchingFonts. Если используется перегрузка GetMatchingFonts, которая принимает имя семейства, однако указанное имя семейства должно использовать имя, соответствующее модели семейства шрифтов WSS. Полный список имен семейств, совместимых с WSS, происходящих в наборе шрифтов, можно получить с помощью методов IDWriteFontSet::GetPropertyValues с помощью DWRITE_FONT_PROPERTY_ID_FAMILY_NAME.  

Аналогичным образом все именованные экземпляры шрифта переменной будут представлены в коллекции шрифтов, возвращаемой идентификатором IDWriteFactory::методом GetSystemFontCollection. Поскольку элементы коллекции шрифтов являются семействами шрифтов на основе модели WSS, именованные экземпляры шрифта переменной могут быть представлены в коллекции как члены двух или нескольких семейств шрифтов. Если используется метод IDWriteFontCollection::FindFamilyName, параметр familyName должен быть именем семейства, совместимым с WSS. Чтобы найти все имена семейств, совместимых с WSS, из коллекции шрифтов, приложение может выполнять циклы по каждой семье и вызывать IDWriteFontFamily::GetFamilyNames, однако, возможно, проще получить соответствующий набор шрифтов и использовать метод GetPropertyValues, как описано выше. 

При работе с пользовательскими шрифтами для создания набора шрифтов можно использовать различные подходы, описанные в разделе настраиваемых наборов шрифтов. Чтобы добавить шрифт переменной в настраиваемый набор шрифтов, рекомендуется использовать метод IDWriteFontSetBuilder1::AddFontFile, так как он поддерживает переменные шрифты и добавит все именованные экземпляры шрифта переменной в одном вызове. В настоящее время нельзя добавлять отдельные именованные экземпляры настраиваемого шрифта переменной в набор шрифтов с помощью метода IDWriteFontSetBuilder::AddFontFaceReference, так как нет способа создать ссылку на шрифт, указывающую, какой из именованных экземпляров из файла шрифта переменной не предназначен. Это означает, что в настоящее время нет способа добавлять именованные экземпляры пользовательского шрифта в настраиваемый набор шрифтов с назначенными настраиваемыми свойствами. Это в свою очередь означает, что пользовательские шрифты переменных в настоящее время нельзя легко использовать в сочетании с API DirectWrite для удаленных шрифтов. Если именованные экземпляры шрифта переменной включены в системный набор шрифтов, однако ссылки на шрифты для каждого именованного экземпляра уже будут существовать, и их можно добавить в настраиваемые наборы шрифтов, включая использование пользовательских значений свойств. Дополнительные сведения см. в разделе "Настраиваемые наборы шрифтов". 

При работе с переменными шрифтами перечисления DirectWrite DWRITE_FONT_WEIGHT и DWRITE_FONT_STRETCH тесно связаны с осями веса и ширины, определенными в спецификации OpenType, но не совпадают. Во-первых, числовой масштаб для любой оси вариантов всегда поддерживает дробные значения, а fontWeight и fontStretch используют целые числа. Масштабирование оси веса OpenType использует значения от 1 до 1000, которое также поддерживается шрифтомWeight. Таким образом, изменение значения оси веса вариантов на fontWeight является относительно незначительным: шрифт Вес, сообщаемый для именованного экземпляра, может быть округлен из точного значения, используемого для определения именованного экземпляра в шрифте. Различие между шрифтом DirectWrite и масштабом оси ширины OpenType больше: DirectWrite использует значения от 1 до 9, следуя usWidthClass значения таблицы OpenType OS/2, а шкала ширины OpenType использует положительные значения, представляющие процент нормальной ширины. В документации usWidthClass в спецификации OpenType можно сопоставить значения от 1 до 9 и процента нормальных значений. Значение fontStretch, указанное для именованного экземпляра, может включать округление при преобразовании из значений оси ширины. 

При создании IDWriteTextFormatнеобходимо указать коллекцию шрифтов и свойства шрифтов, совместимые с WSS (имя семейства, вес, растяжение и стиль). Это также относится к настройке свойств форматирования шрифта в idWriteTextLayout текстовом диапазоне. Свойства можно получить из объекта IDWriteFontFace3 или из IDWriteFont и объектов IDWriteFontFamily, представляющих конкретный именованный экземпляр. Как отмечалось выше, значения, возвращаемые методами GetWeight и GetStretch, могут округлить приближения для фактических значений осей, используемых для определения именованного экземпляра, но DirectWrite сопоставляет сочетание свойств обратно с нужным именованным экземпляром. 

Аналогичным образом, если приложение использует IDWriteFontFallbackBuilder для создания пользовательских резервных данных шрифта, семейства задаются для сопоставления диапазонов символов с помощью имен семейств, совместимых с WSS. Резервный вариант шрифта в DirectWrite основан на семействах с DirectWrite, выбрав вариант в резервном семействе, который является ближайшим совпадением для варианта начальной семьи. Для вариантов, включающих измерения, отличные от веса, растяжения и стиля, DirectWrite в настоящее время не сможет выбрать такие варианты в резервном семействе, если только пользовательские резервные данные не были созданы специально для предоставления резервных сопоставлений для семейств с определенными атрибутами, не имеющими атрибутов WSS, например "Caption" оптического размера.