Fontes variáveis OpenType

Este tópico descreve fontes de variáveis OpenType, seu suporte em DirectWrite e Direct2D e como usá-las em seu aplicativo. 

O que são fontes de variáveis OpenType?

A versão 1.8 da especificação de formato de fonte OpenType introduziu uma nova extensão para o formato conhecido como Variações de Fonte OpenType. Fontes que usam essas extensões são conhecidas como fontes de variável OpenType. Uma fonte de variável OpenType é uma única fonte que pode se comportar como várias fontes usando interpolação contínua entre designs diferentes, tudo definido dentro da fonte única.

Uma fonte de variável OpenType pode definir a variação contínua de seu design ao longo de um ou mais eixos independentes, como peso ou largura:

 

Mostra uma fonte de variável OpenType usando a letra 'G' e mostrando variações diferentes ao longo de um eixo de largura horizontal e um eixo de peso vertical.

Um desenvolvedor de fontes determina um conjunto de eixos de variação a serem usados em uma determinada fonte. Esses eixos podem incluir um conjunto de eixos conhecidos (ou "registrados") de variação, como peso e largura, mas também podem incluir eixos arbitrários e personalizados de variação definidos pelo desenvolvedor de fontes.  

Ao selecionar um conjunto de eixos de variação para uma fonte, o desenvolvedor de fontes define um espaço abstrato e ndimensional de variação de design para a fonte. Os mecanismos de texto podem especificar potencialmente qualquer posição ou "instância" dentro desse espaço contínuo para definir e renderizar texto. 

O desenvolvedor de fontes também pode selecionar e atribuir nomes a instâncias específicas no espaço de variação de design; elas são chamadas de "instâncias nomeadas". Por exemplo, uma fonte com variação de peso pode dar suporte à variação contínua entre traços muito leves e muito pesados, enquanto o desenvolvedor de fontes selecionou pesos específicos ao longo desse continuum e atribuiu nomes a eles, como "Light", "Regular" e "Semibold". 

O formato de fonte de variável OpenType usa tabelas de dados encontradas em fontes OpenType tradicionais, além de determinadas tabelas adicionais que descrevem como os valores de vários itens de dados mudam para instâncias diferentes. O formato designa uma instância de variação como uma "instância padrão", que usa tabelas tradicionais para obter valores padrão. Todas as outras instâncias dependem dos dados padrão mais outros dados delta. Por exemplo, uma tabela 'glyf' pode ter uma descrição de curva de Bezier de uma forma de glifo nominal, que é a forma usada para a instância padrão, enquanto uma tabela 'gvar' descreverá como os pontos de controle Bezier para o glifo são ajustados para outras instâncias. Da mesma forma, outros valores de fonte podem ter um valor nominal mais dados delta que descrevem como esses valores mudam para instâncias diferentes; por exemplo, altura x e outras métricas de toda a fonte ou posições de ancoragem de marca específicas de glifo e ajustes de kerning. 

Como fontes variáveis podem dar suporte a um conjunto arbitrário de eixos de variação, elas exigem um modelo extensível de famílias de fontes que reflete mais diretamente como os designers de fontes criam famílias de fontes: uma família de fontes é definida por um nome de família e determinadas características de design constantes, com um número arbitrário (determinado pelo desenvolvedor de fontes) de maneiras pelas quais o design pode variar. Uma família de fontes pode ser criada com variantes de peso, mas uma família de fontes diferente pode ser criada com variantes para altura x, tamanho de serif, "funkiness" ou o que o desenvolvedor de fonte desejar. Nesse modelo, uma seleção de rosto de fonte é melhor descrita usando o nome de família geral ou "preferencial" ou "tipográfico", mais um conjunto de pares chave-valor, cada um representando um tipo de variação e valor específico, com os tipos de variação em geral sendo um conjunto extensível. Essa noção geral de uma família de fontes pode se aplicar a fontes tradicionais e não variáveis, bem como a fontes variáveis. Por exemplo, nesse modelo geral de família tipográfica, uma família "Selawik VF" pode ter variações de peso, tamanho óptico e design de serif, com instâncias como "Semilight Banner Sans". 

Algumas implementações de software existentes, no entanto, incluindo APIs DirectWrite existentes, podem ser projetadas assumindo um modelo mais limitado de famílias de fontes. Por exemplo, alguns aplicativos podem assumir que uma família de fontes pode ter, no máximo, variantes Regular, Negrito, Itálico e Negrito Itálico. As interfaces IDWriteFontCollection e IDWriteFontFamily existentes pressupõem um modelo de família de peso/alongamento/estilo ("WSS"), permitindo que variantes dentro de uma família sejam especificadas usando as enumerações DWRITE_FONT_WEIGHT, DWRITE_FONT_STRETCH ou DWRITE_FONT_STYLE como parâmetros. Seguindo o exemplo anterior, os eixos óptico e serif não seriam tratados como eixos familiares internos de variação no modelo WSS. 

O suporte completo para fontes variáveis exigiria APIs que permitem que um membro da família seja especificado com potencialmente vários parâmetros, conforme determinado pela fonte. Mas os designs de API existentes podem ser capazes de fornecer suporte parcial para fontes variáveis projetando as instâncias nomeadas definidas em uma fonte variável nos modelos mais limitados da família de fontes. No exemplo anterior, "Selawik VF Semilight Banner Sans" poderia ser projetado no modelo WSS como uma família "Selawik VF Banner Sans" com "Semilight" como uma variante de peso. 

Por outro exemplo, considere uma família de fontes tipográficas, como Sitka, com variantes de tamanho óptico e de peso. As variantes nomeadas dentro da família incluem Sitka Text Regular e Sitka Banner Bold (além de muitas outras). O nome da família tipográfica é "Sitka", enquanto os nomes de rosto para essas variantes no modelo de família tipográfica seriam "Text Regular" e "Banner Bold". Os modelos de família WSS e de quatro membros não permitem variantes de tamanho óptico dentro de uma família e, portanto, as distinções de tamanho óptico devem ser tratadas como distinções de nível familiar. A tabela a seguir ilustra como uma seleção de fontes da família tipográfica Sitka seria tratada no modelo da família WSS:

Modelo de família tipográfica

Modelo da família WSS

Família

Face

Família

Face

Sitka

Texto Regular

Texto sitka

Regular

Sitka

Faixa em Negrito

Faixa sitka

Negrito

Sitka

Legenda Itálico

Legenda sitka

Itálico

 

A projeção de nomes de um modelo de família tipográfica para o modelo da família WSS pode ser aplicada a fontes não variáveis e às instâncias nomeadas de fontes variáveis. No entanto, isso não pode ser feito para outras instâncias não nomeadas do espaço de variação de design contínuo de uma fonte variável. Por esse motivo, o suporte para a funcionalidade completa de fontes variáveis exigirá APIs projetadas para referenciar rostos dentro de uma família tipográfica em termos de um conjunto irrestrito de eixos de variação e valores de eixo. 

Suporte à fonte de variável OpenType no DirectWrite

A partir do lançamento da Atualização de Criadores do Windows 10, o formato de fonte de variável OpenType ainda é muito novo e fornecedores de fontes, plataformas e aplicativos ainda estão em processo de implementação do novo formato. Essa atualização fornece implementação inicial para esse formato em DirectWrite. 

DirectWrite internos foram atualizados para dar suporte a fontes de variáveis OpenType. Usando APIs atuais, isso fornece suporte para todas as instâncias nomeadas de uma fonte variável. Esse suporte pode ser usado para fluxos de trabalho completos, desde a enumeração das instâncias nomeadas, a seleção de uma instância nomeada, o uso no layout e na formatação até a renderização e impressão. Para o benefício de aplicativos que também usam a interoperabilidade de texto GDI para determinadas operações, suporte semelhante também foi adicionado em APIs GDI existentes. 

No Windows 10 Creators Update, DirectWrite não dá suporte a instâncias arbitrárias que utilizam a funcionalidade de variação contínua de fontes variáveis.

Em muitas operações, o comportamento em DirectWrite de instâncias nomeadas de uma fonte variável não pode ser distinguido do comportamento de fontes não variáveis. E como o suporte é fornecido usando APIs de DirectWrite existentes, as instâncias nomeadas de fontes variáveis podem até mesmo funcionar em muitos aplicativos DirectWrite existentes sem nenhuma alteração. No entanto, as exceções podem ser aplicadas em determinadas situações:

  • Se um aplicativo processar dados de fonte diretamente para determinadas operações. Por exemplo, se um aplicativo ler dados de estrutura de tópicos de glifo diretamente do arquivo de fonte para criar determinados efeitos visuais.
  • Se um aplicativo usar uma biblioteca de terceiros para determinadas operações. Por exemplo, se um aplicativo usa DirectWrite para layout, para obter índices e posições finais de glifo, mas usa uma biblioteca de terceiros para renderização.
  • Se um aplicativo inserir dados de fonte em um documento ou de alguma outra forma passar dados de fonte para um processo downstream.

Se as operações forem executadas usando implementações que não dão suporte a fontes variáveis, essas operações poderão não produzir os resultados esperados. Por exemplo, as posições de glifo podem ser calculadas para uma instância nomeada da fonte variável, mas os glifos podem ser renderizados assumindo uma instância nomeada diferente. Dependendo da implementação do aplicativo, os resultados podem funcionar em alguns contextos, mas não em outros contextos em que outras bibliotecas podem ser usadas. Por exemplo, o texto pode ser exibido corretamente na tela, mas não quando impresso. Se fluxos de trabalho de ponta a ponta forem implementados usando apenas DirectWrite, o comportamento correto para instâncias nomeadas de uma fonte variável poderá ser esperado. 

Como as APIs de DirectWrite existentes dão suporte à seleção facial usando o modelo de peso/alongamento/estilo, as instâncias nomeadas de fontes que usam outros eixos de variação serão projetadas do modelo de família geral e tipográfico para o modelo WSS, conforme descrito acima. Isso se baseia em uma fonte variável, incluindo uma tabela de "atributos de estilo" ('STAT') com subtables de valor de eixo, que dWrite usa para distinguir tokens de nome facial que designam atributos de peso, alongamento ou estilo de tokens que pertencem a outros eixos de variação.  

Se uma fonte de variável não incluir uma tabela 'STAT', conforme necessário para fontes variáveis pela especificação OpenType, DirectWrite tratará a fonte como uma fonte não variável que contém apenas a instância padrão.  

Se uma fonte contiver uma tabela 'STAT', mas não incluir subtables de valor de eixo apropriadas, isso poderá levar a resultados inesperados, como ter várias faces com nomes de rosto idênticos. Não há suporte para essas fontes no momento. 

A especificação OpenType permite que os dados de estrutura de tópicos de glifo sejam representados em um dos dois formatos: usando uma tabela 'glyf', que usa a estrutura de tópicos TrueType e o formato de dica, ou usando uma tabela 'CFF', que usa a representação formato de fonte compacta ("CFF"). Em uma fonte variável com estruturas de tópicos TrueType, a tabela 'glyf' continua a ser usada e é complementada com uma tabela 'gvar' que fornece os dados de variação para as estruturas de tópicos. Isso significa que a instância padrão de uma fonte variável com estruturas de tópicos TrueType usa apenas tabelas OpenType tradicionais que terão suporte em softwares mais antigos que não têm suporte de fonte variável. Em uma fonte variável com estruturas de tópicos CFF, no entanto, a tabela 'CFF' é substituída pela tabela 'CFF2', que encapsula os dados de estrutura de tópicos padrão e os dados de variação associados em uma tabela. Os dados CFF são processados por um rasterizador separado do usado para dados TrueType e uma tabela 'CFF2' requer um rasterizador CFF atualizado que tenha suporte a 'CFF2'. Uma tabela 'CFF2' não pode ser processada por rasterizadores CFF mais antigos. Para uma fonte variável com dados de estrutura de tópicos CFF, isso significa que mesmo a instância padrão não funcionará em softwares mais antigos. 

Na Atualização de Criadores do Windows 10, DirectWrite não dá suporte a fontes variáveis com dados de estrutura de tópicos CFF usando a tabela 'CFF2'. 

Usando fontes de variável OpenType

Fontes de variáveis OpenType podem ser fáceis de usar, tendo em mente as limitações atuais indicadas acima:

  • Há suporte apenas para instâncias nomeadas de uma fonte variável no momento.
  • Somente fontes variáveis que usam dados de estrutura de tópicos de glifo TrueType (não estruturas de tópicos CFF) têm suporte neste momento. 
  • Para fontes que usam eixos de variação de design diferentes de peso, alongamento ou estilo, as instâncias nomeadas serão projetadas no modelo da família WSS, o que pode resultar em algumas instâncias nomeadas aparecendo como famílias separadas (como aconteceria no passado para fontes não variáveis). Para dar suporte a isso, as fontes variáveis devem ter uma tabela 'STAT' que inclua subtables de valor de eixo apropriadas.
  • Há suporte para instâncias nomeadas de fontes variáveis em APIs DirectWrite, mas se determinadas operações forem executadas em implementações mais antigas que não dão suporte a fontes variáveis, elas poderão produzir resultados incorretos. 
  • Determinadas APIs de DirectWrite usam as enumerações DWRITE_FONT_WEIGHT, DWRITE_FONT_STRETCH e DWRITE_FONT_STYLE para especificar atributos de peso, alongamento e estilo ao selecionar rostos. Se uma fonte variável usar eixos de variação correspondentes, mas tiver muitas instâncias nomeadas que exigem granularidade mais fina, nem todas as instâncias nomeadas serão selecionáveis nessas APIs.

Fontes variáveis OpenType que estão em conformidade com esses requisitos podem ser instaladas do shell do Windows, assim como outras fontes OpenType, e também podem ser usadas em conjuntos de fontes personalizados criados por um aplicativo.  

Quando instalado no sistema, todas as instâncias nomeadas de uma fonte variável serão incluídas no conjunto de fontes retornado chamando o método IDWriteFontFamily3::GetSystemFontSet . Observe que um conjunto de fontes é uma lista simples sem uma hierarquia de agrupamento familiar, mas cada item no conjunto tem uma propriedade de nome de família com base no modelo da família WSS. O conjunto de fontes pode ser filtrado para uma determinada instância de fonte variável chamada usando os métodos IDWriteFontSet::GetMatchingFonts . Se estiver usando a sobrecarga GetMatchingFonts que usa um familyName, no entanto, o familyName especificado deverá usar o nome em conformidade com o modelo da família de fontes do WSS. A lista completa de nomes de família compatíveis com WSS que ocorrem em um conjunto de fontes pode ser obtida usando os métodos IDWriteFontSet::GetPropertyValues usando DWRITE_FONT_PROPERTY_ID_FAMILY_NAME.  

Da mesma forma, todas as instâncias nomeadas de uma fonte variável serão representadas na coleção de fontes retornada pelo método IDWriteFactory::GetSystemFontCollection . Como os elementos de uma coleção de fontes são famílias de fontes com base no modelo WSS, as instâncias nomeadas de uma fonte variável podem ser representadas em uma coleção como membros de duas ou mais famílias de fontes. Se o método IDWriteFontCollection::FindFamilyName for usado, o parâmetro familyName deverá ser um nome de família compatível com WSS. Para localizar todos os nomes de família compatíveis com WSS de uma coleção de fontes, um aplicativo pode percorrer cada família e chamar IDWriteFontFamily::GetFamilyNames, embora possa ser mais fácil obter um conjunto de fontes correspondente e usar o método GetPropertyValues , conforme descrito acima. 

Ao trabalhar com fontes personalizadas, várias abordagens descritas no tópico Conjuntos de Fontes Personalizados podem ser usadas para criar um conjunto de fontes. Para adicionar uma fonte variável a um conjunto de fontes personalizado, o método IDWriteFontSetBuilder1::AddFontFile é recomendado, pois dá suporte a fontes variáveis e adicionará todas as instâncias nomeadas de uma fonte variável em uma única chamada. No momento, não há como adicionar instâncias nomeadas individuais de uma fonte de variável personalizada a um conjunto de fontes usando os métodos IDWriteFontSetBuilder::AddFontFaceReference , pois não há como criar uma referência facial de fonte especificando qual das instâncias nomeadas de um arquivo de fonte variável se destina. Isso significa que atualmente não há como adicionar instâncias nomeadas de uma fonte personalizada a um conjunto de fontes personalizado com propriedades personalizadas atribuídas. Isso, por sua vez, significa que as fontes de variáveis personalizadas atualmente não podem ser usadas facilmente em conjunto com apIs DirectWrite para fontes remotas. Se instâncias nomeadas de uma fonte variável estiverem incluídas em um conjunto de fontes do sistema, no entanto, referências de face de fonte para cada instância nomeada já existirão e elas poderão ser adicionadas a conjuntos de fontes personalizados, inclusive com o uso de valores de propriedade personalizados. Consulte o tópico Conjuntos de Fontes Personalizados para obter mais detalhes. 

Ao trabalhar com fontes variáveis, as DirectWrite DWRITE_FONT_WEIGHT e DWRITE_FONT_STRETCH enumerações são intimamente conectadas aos eixos de variação de largura e peso definidos na especificação OpenType, mas não são os mesmos. Primeiro, a escala numérica para qualquer eixo de variação sempre dá suporte a valores fracionários, enquanto fontWeight e fontStretch usam inteiros. A escala do eixo de peso OpenType usa valores que variam de 1 a 1000, que também é compatível com fontWeight. Portanto, a alteração de um valor de eixo de peso de variação para fontWeight é relativamente menor: o fontWeight relatado para uma instância nomeada pode ser arredondado do valor preciso usado para definir a instância nomeada dentro da fonte. A distinção entre DirectWrite fontStretch e a escala do eixo de largura OpenType é maior: DirectWrite usa valores de 1 a 9, seguindo os valores usWidthClass da tabela OpenType OS/2, enquanto a escala do eixo de largura OpenType usa valores positivos que representam uma porcentagem de largura normal. A documentação usWidthClass na especificação OpenType fornece um mapeamento entre valores de 1 a 9 e por cento dos valores normais. O valor fontStretch relatado para uma instância nomeada pode envolver arredondamento ao converter de valores de eixo de largura. 

Ao criar um IDWriteTextFormat, uma coleção de fontes e propriedades de fonte compatíveis com WSS (nome da família, peso, alongamento e estilo) devem ser especificadas. Isso também se aplica ao definir propriedades de formatação de fonte em um intervalo de texto IDWriteTextLayout . As propriedades podem ser obtidas de um objeto IDWriteFontFace3 ou de objetos IDWriteFont e IDWriteFontFamily que representam uma instância nomeada específica. Conforme observado acima, os valores retornados pelos métodos GetWeight e GetStretch podem ser aproximações arredondadas para os valores reais do eixo usados para definir a instância nomeada, mas DirectWrite mapeará a combinação de propriedades de volta para a instância nomeada desejada. 

Da mesma forma, se um aplicativo usar IDWriteFontFallbackBuilder para criar dados de fallback de fonte personalizados, as famílias serão especificadas para mapeamentos de intervalo de caracteres usando nomes de família compatíveis com WSS. O fallback de fonte em DirectWrite baseia-se em famílias com DirectWrite selecionando uma variante dentro de uma família de fallback que é uma correspondência mais próxima para a variante da família inicial. Para variantes que envolvem dimensões diferentes de peso, alongamento e estilo, DirectWrite atualmente não seria capaz de selecionar essas variantes em uma família de fallback, a menos que dados de fallback personalizados tenham sido criados especificamente para fornecer mapeamentos de fallback para famílias que têm atributos não WSS específicos, como variantes de tamanho óptico "Caption".