Fontes variáveis OpenType
Este tópico descreve as fontes variáveis OpenType, seu suporte em DirectWrite e Direct2D e como usá-las em seu aplicativo.
- O que são fontes variáveis OpenType?
- suporte a fontes variáveis OpenType no DirectWrite
- Usando fontes variáveis OpenType
O que são fontes 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 OpenType Font Variations. As fontes que usam essas extensões são conhecidas como fontes variáveis OpenType. Uma fonte variável OpenType é uma única fonte que pode se comportar como várias fontes usando interpolação contínua entre diferentes designs, todos definidos dentro da fonte única.
Uma fonte 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:
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 de variação bem conhecidos (ou "registrados"), como peso e largura, mas também podem incluir eixos arbitrários e personalizados de variação definidos pelo desenvolvedor da fonte.
Ao selecionar um conjunto de eixos de variação para uma fonte, o desenvolvedor da fonte define um espaço abstrato e n-dimensional 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 disposição e renderização de texto.
O desenvolvedor da fonte também pode selecionar e atribuir nomes a instâncias específicas dentro do espaço de variação de design; estes são referidos como "instâncias nomeadas". Por exemplo, uma fonte com variação de peso pode suportar variação contínua entre traços muito leves e muito pesados, enquanto o desenvolvedor da fonte selecionou pesos específicos ao longo desse contínuo e atribuiu nomes a eles, como "Light", "Regular" e "Semibold".
O formato de fonte variável OpenType usa tabelas de dados encontradas em fontes OpenType tradicionais, além de certas tabelas adicionais que descrevem como os valores de vários itens de dados mudam para diferentes instâncias. 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 da curva de Bezier de uma forma nominal de glifo, que é a forma usada para a instância padrão, enquanto uma tabela 'gvar' descreverá como os pontos de controle de 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 descrevendo como esses valores mudam para diferentes instâncias; por exemplo, altura x e outras métricas de largura de fonte, ou posições de ancoragem de marcação específicas do glifo e ajustes de kerning.
Como as fontes variáveis podem suportar um conjunto arbitrário de eixos de variação, elas exigem um modelo extensível de famílias de fontes que reflita 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 certas características de design que são constantes, com um número arbitrário (determinado pelo desenvolvedor da fonte) de maneiras pelas quais o design pode variar. Uma família de fontes pode ser criada com variantes para peso, mas uma família de fontes diferente pode ser criada com variantes para x-height, serif-size, "funkiness", ou o que o desenvolvedor de fontes desejar. Neste modelo, uma seleção de face de fonte é melhor descrita usando o nome de família geral, ou "preferido" 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. Esta noção geral de uma família de fontes pode aplicar-se a fontes tradicionais, não variáveis, bem como a fontes variáveis. Por exemplo, sob este modelo geral de família tipográfica, uma família "Selawik VF" pode ter variações de peso, tamanho ótico e design de serifa, 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, algumas aplicações podem assumir que uma família de fontes pode ter, no máximo, variantes Regular, Negrito, Itálico e Negrito Itálico. As interfaces deIDWriteFontCollection eIDWriteFontFamily existentes assumem um modelo de família weight/stretch/style ("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. Tomando o exemplo anterior, o tamanho ótico e os eixos serifa não seriam tratados como eixos internos da família de variação no modelo WSS.
O suporte completo para fontes variáveis exigiria APIs que permitissem que um membro da família fosse 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 de família de fontes mais limitados. 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.
Para outro exemplo, considere uma família de fontes tipográficas como Sitka, com variantes de peso e tamanho ótico. Variantes nomeadas dentro da família incluem Sitka Text Regular e Sitka Banner Bold (além de muitos outros). O nome de família tipográfico é "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 quatro membros e da família WSS não permitem variantes de tamanho ótico dentro de uma família e, portanto, as distinções de tamanho ótico 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
Rosto
Família
Rosto
Sitka
Texto Regular
Texto Sitka
Regular
Sitka
Banner Negrito
Bandeira 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 de família WSS pode ser aplicada a fontes não variáveis e às instâncias nomeadas de fontes variáveis. Isso não pode ser feito, no entanto, para outras instâncias sem nome 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 fazer referência a faces dentro de uma família tipográfica em termos de um conjunto irrestrito de eixos de variação e valores de eixo.
Suporte a fontes variáveis OpenType no DirectWrite
A partir do lançamento do Windows 10 Creators Update, o formato de fonte variável OpenType ainda é muito novo, e os fornecedores de fontes, plataformas e aplicativos ainda estão no processo de implementação do novo formato. Esta atualização fornece implementação inicial para esse formato no DirectWrite.
Os internos do DirectWrite foram atualizados para suportar fontes variáveis OpenType. Usando APIs atuais, isso fornece suporte para quaisquer 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, seleção de uma instância nomeada, uso em layout e modelagem até renderização e impressão. Para o benefício de aplicativos que também usam interoperabilidade de texto GDI para determinadas operações, suporte semelhante também foi adicionado em APIs GDI existentes.
Na Atualização de Criadores do Windows 10, o DirectWrite não oferece suporte a instâncias arbitrárias que utilizam o recurso de variação contínua de fontes variáveis.
Em muitas operações, o comportamento no 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 DirectWrite existentes, as instâncias nomeadas de fontes variáveis podem até funcionar em muitos aplicativos DirectWrite existentes sem alterações. No entanto, podem aplicar-se exceções em determinadas situações:
- Se um aplicativo processa dados de fonte diretamente para determinadas operações. Por exemplo, se um aplicativo lê dados de contorno de glifo diretamente do arquivo de fonte para criar determinados efeitos visuais.
- Se um aplicativo usa uma biblioteca de terceiros para determinadas operações. Por exemplo, se um aplicativo usa DirectWrite para layout, para obter índices e posições finais do glifo, mas usa uma biblioteca de terceiros para renderização.
- Se um aplicativo incorporar 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 suportam fontes variáveis, essas operações podem não produzir os resultados esperados. Por exemplo, as posições dos glifos 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 nos quais 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 pode ser esperado.
Como as APIs DirectWrite existentes oferecem suporte à seleção de faces usando o modelo peso/estiramento/estilo, as instâncias nomeadas de fontes que usam outros eixos de variação serão projetadas do modelo geral da família tipográfica para o modelo WSS, conforme descrito acima. Isso depende de uma fonte variável, incluindo uma tabela de "atributos de estilo" ('STAT') com subtabelas de valor de eixo, que o DWrite usa para distinguir tokens de nome de rosto que designam atributos de peso, estiramento ou estilo de tokens que pertencem a outros eixos de variação.
Se uma fonte variável não incluir uma tabela 'STAT', como exigido para fontes variáveis pela especificação OpenType, o DirectWrite tratará a fonte como uma fonte não variável contendo apenas a instância padrão.
Se uma fonte contiver uma tabela 'STAT', mas não incluir subtabelas de valor de eixo apropriadas, isso pode levar a resultados inesperados, como ter várias faces com nomes de faces idênticos. Essas fontes não são suportadas no momento.
A especificação OpenType permite que os dados da estrutura de tópicos do glifo sejam representados em um de dois formatos: usando uma tabela 'glyf', que usa o formato de contorno e dica TrueType, ou usando uma tabela 'CFF', que usa representação Compact Font Format ("CFF"). Em uma fonte variável com contornos TrueType, a tabela 'glyf' continua a ser usada e é complementada com uma tabela 'gvar' que fornece os dados de variação para os contornos. Isso significa que a instância padrão de uma fonte variável com contornos TrueType usa apenas tabelas OpenType tradicionais que serão suportadas em softwares mais antigos que não têm suporte a fontes variáveis. Em uma fonte variável com contornos 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 daquele 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.
No Windows 10 Creators Update, o DirectWrite não suporta fontes variáveis com dados de estrutura de tópicos CFF usando a tabela 'CFF2'.
Usando fontes variáveis OpenType
As fontes variáveis OpenType podem ser fáceis de usar, tendo em mente as limitações atuais mencionadas acima:
- Somente instâncias nomeadas de uma fonte variável são suportadas no momento.
- Somente fontes variáveis que usam dados de estrutura de tópicos do glifo TrueType (não contornos CFF) são suportadas no 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 suportar isso, as fontes variáveis devem ter uma tabela 'STAT' que inclua subtabelas de valor de eixo apropriadas.
- Instâncias nomeadas de fontes variáveis são suportadas em APIs do DirectWrite, mas se determinadas operações forem executadas em implementações mais antigas que não oferecem suporte a fontes variáveis, elas poderão produzir resultados incorretos.
- Algumas APIs do 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.
As fontes variáveis OpenType que estão em conformidade com esses requisitos podem ser instaladas a partir 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 IDWriteFontFamily3::GetSystemFontSet método. 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 baseada no modelo de família WSS. O conjunto de fontes pode ser filtrado para uma determinada ocorrência de fonte variável chamada usando os IDWriteFontSet::GetMatchingFonts métodos. No entanto, se estiver usando o GetMatchingFonts sobrecarga que usa um familyName, o familyName especificado deverá usar o nome em conformidade com o modelo de família de fontes WSS. A lista completa de nomes de família compatíveis com WSS que ocorrem em um conjunto de fontes pode ser obtida usando o IDWriteFontSet::GetPropertyValues métodos 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 IDWriteFactory::GetSystemFontCollection método. Como os elementos de uma coleção de fontes são famílias de fontes baseadas 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 IDWriteFontCollection::FindFamilyName método for usado, o parâmetro familyName deverá ser um nome de família compatível com WSS. Para encontrar 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étodoGetPropertyValuesconforme 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 IDWriteFontSetBuilder1::AddFontFile método é recomendado, pois ele suporta 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 variável personalizada a um conjunto de fontes usando os métodos IDWriteFontSetBuilder::AddFontFaceReference, pois não há como criar uma referência de face de fonte especificando qual das instâncias nomeadas de um arquivo de fonte variável é destinada. 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 variáveis personalizadas atualmente não podem ser facilmente usadas em conjunto com APIs DirectWrite para fontes remotas. Se instâncias nomeadas de uma fonte variável forem incluídas em um conjunto de fontes do sistema, no entanto, as 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 personalizada. Consulte o tópico Conjuntos de fontes personalizados para obter mais detalhes.
Ao trabalhar com fontes variáveis, as enumerações DirectWrite DWRITE_FONT_WEIGHT e DWRITE_FONT_STRETCH estão intimamente conectadas aos eixos de variação de peso e largura definidos na especificação OpenType, mas não são as mesmas. Primeiro, a escala numérica para qualquer eixo de variação sempre suporta 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 é suportado por fontWeight. Assim, a mudança 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 o DirectWrite fontStretch e a escala do eixo de largura OpenType é maior: o 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 da largura normal. A documentação usWidthClass na especificação OpenType fornece um mapeamento entre valores de 1 a 9 e valores percentuais do normal. O valor fontStretch relatado para uma instância nomeada pode envolver arredondamento ao converter 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 IDWriteTextLayout intervalo de texto. As propriedades podem ser obtidas de um objeto deIDWriteFontFace3ou de IDWriteFont e IDWriteFontFamily objetos que representam uma instância nomeada específica. Como observado acima, os valores retornados pelos métodos GetWeight e GetStretch podem ser aproximações arredondadas para os valores de eixo reais 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 no DirectWrite é baseado em famílias com o 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, estiramento e estilo, o DirectWrite atualmente não seria capaz de selecionar essas variantes dentro de uma família de fallback, a menos que dados de fallback personalizados fossem criados especificamente para fornecer mapeamentos de fallback para famílias que têm atributos específicos não WSS, como variantes de tamanho ótico "Caption".