Conjuntos de fontes personalizados

Este tópico descreve várias maneiras pelas quais você pode usar fontes personalizadas em seu aplicativo.

Introdução

Na maioria das vezes, os aplicativos usam as fontes instaladas localmente no sistema. DirectWrite fornece acesso a essas fontes usando os métodos IDWriteFactory3::GetSystemFontSet ou IDWriteFactory::GetSystemFontCollection. Em alguns casos, os aplicativos também podem querer usar fontes incluídas como parte do Windows 10, mas que não estão instaladas atualmente no sistema atual. Essas fontes podem ser acessadas do serviço de fonte do Windows usando o método GetSystemFontSet ou chamando IDWriteFactory3::GetSystemFontCollection com includeDownloadableFonts definido como TRUE. 

Em alguns cenários de aplicativo, no entanto, os aplicativos precisam usar fontes que não estão instaladas no sistema e não são fornecidas pelo Serviço de Fonte do Windows. Veja a seguir exemplos desses cenários:

  • As fontes são inseridas como recursos em um binário de aplicativo.
  • Os arquivos de fonte são agrupados em um pacote de aplicativos e armazenados em disco na pasta de instalação do aplicativo.
  • O aplicativo é uma ferramenta de desenvolvimento de fontes que precisa carregar arquivos de fonte especificados pelo usuário. 
  • As fontes são inseridas em arquivos de documento que podem ser exibidos ou editados no aplicativo. 
  • O aplicativo usa fontes obtidas de um serviço público de fonte da Web. 
  • O aplicativo usa dados de fonte transmitidos por meio de um protocolo de rede privada. 

DirectWrite fornece APIs para trabalhar com fontes personalizadas nesses e em outros cenários semelhantes. Os dados de fonte personalizados podem vir de arquivos no sistema de arquivos local; de fontes remotas baseadas em nuvem acessadas usando HTTP; ou de fontes arbitrárias depois de terem sido carregadas em um buffer de memória. 

Observação

Embora DirectWrite tenha fornecido APIs para trabalhar com fontes personalizadas desde o Windows 7, APIs mais recentes foram adicionadas no Windows 10 e novamente na Atualização do Windows 10 para Criadores (versão prévia 15021 ou posterior) que facilitam a implementação de vários dos cenários mencionados. Este tópico se concentra nas APIs disponíveis no Windows 10. Para aplicativos que precisam funcionar em versões anteriores do Windows, consulte Coleções de fontes personalizadas (Windows 7/8)

 

Resumo das APIs

Este tópico se concentra na funcionalidade fornecida pelas seguintes APIs:

 

Principais conceitos

Para entender as APIs de DirectWrite para trabalhar com fontes personalizadas, pode ser útil entender o modelo conceitual subjacente a essas APIs. Os principais conceitos serão descritos aqui. 

Quando DirectWrite faz layout ou renderização de texto real, ele precisa acessar dados de fonte reais. Um objeto de rosto de fonte contém dados de fonte reais, que devem existir no sistema local. Mas para outras operações, como verificar a disponibilidade de uma fonte específica ou apresentar opções de fonte a um usuário, tudo o que é necessário é uma referência a uma fonte específica, não aos dados reais da fonte em si. Em DirectWrite, um objeto de referência facial de fonte contém apenas as informações necessárias para localizar e instanciar uma fonte. Como a referência facial da fonte não contém dados reais, DirectWrite pode lidar com referências faciais de fonte para as quais os dados reais estão em um local de rede remota, bem como quando os dados reais são locais.

Um conjunto de fontes é um conjunto de referências de rosto de fonte, juntamente com determinadas propriedades básicas e informativas que podem ser usadas na referência à fonte ou na comparação com outras fontes, como o nome da família ou um valor de peso da fonte. Os dados reais das várias fontes podem ser locais ou podem ser todos remotos ou alguma mistura.

Um conjunto de fontes pode ser usado para obter um objeto de coleção de fontes correspondente. Consulte Conjuntos de fontes e coleções de fontes abaixo para obter mais detalhes. 

A interface IDWriteFontSet fornece métodos que permitem a consulta de valores de propriedade, como nome da família ou peso da fonte, ou para referências faciais de fonte que correspondem a valores de propriedade específicos. Depois de filtrar para uma seleção específica, uma instância da interface IDWriteFontFaceReference pode ser obtida, com métodos para download (se os dados de fonte reais forem atualmente remotos), para obter o objeto IDWriteFontFace3 correspondente que pode ser usado para layout e renderização. 

A interface IDWriteFontFile está por trás de cada face de fonte ou referência facial de fonte. Isso representa o local de um arquivo de fonte e tem dois componentes: um carregador de arquivo de fonte e uma chave de arquivo de fonte. O carregador de arquivos de fonte (IDWriteFontFileLoader) é usado para abrir um arquivo, se necessário, e retorna um fluxo com os dados (IDWriteFontFileStream). Dependendo do carregador, os dados podem estar localizados em um caminho de arquivo local, um URL remota ou em um buffer de memória. A chave é um valor definido pelo carregador que identifica exclusivamente o arquivo dentro do contexto do carregador, permitindo que o carregador localize os dados e crie um fluxo para ele. 

Fontes personalizadas podem ser facilmente adicionadas a um conjunto de fontes personalizado, que, por sua vez, pode ser usado para filtrar ou organizar informações de fonte para fins como criar uma interface do usuário do seletor de fontes. O conjunto de fontes também pode ser usado para criar uma coleção de fontes para uso em APIs de nível superior, como IDWriteTextFormat e IDWriteTextLayout. A interface IDWriteFontSetBuilder pode ser usada para criar um conjunto de fontes personalizado que inclui várias fontes personalizadas. Ele também pode ser usado para criar um conjunto de fontes personalizado que combina fontes personalizadas e fontes fornecidas pelo sistema; ou que combina fontes com fontes diferentes para os dados reais : armazenamento local, URLs remotas e memória. 

Conforme mencionado, uma referência de face de fonte pode se referir a dados de fonte em uma fonte remota, mas os dados devem ser locais para obter um objeto de face de fonte que pode ser usado para layout e renderização. O download de dados remotos é tratado por uma fila de download de fontes. Os aplicativos podem usar a interface IDWriteFontDownloadQueue para enfileirar solicitações para baixar fontes remotas para iniciar o processo de download e registrar um objeto IDWriteFontDownloadListener para executar uma ação quando o processo de download for concluído. 

Para a maioria das interfaces descritas aqui, DirectWrite fornece implementações do sistema. A única exceção é a interface IDWriteFontDownloadListener , que um aplicativo implementa para executar ações específicas do aplicativo quando fontes remotas são baixadas localmente. Os aplicativos podem ter motivos para fornecer suas próprias implementações personalizadas para determinadas outras interfaces, embora isso só seja necessário em cenários específicos e mais avançados. Por exemplo, um aplicativo precisaria fornecer uma implementação personalizada da interface IDWriteFontFileLoader para manipular arquivos de fonte no armazenamento local que usam o formato de contêiner WOFF2. Detalhes adicionais serão fornecidos abaixo. 

Fontes e formatos de arquivo de fonte

Outro conceito importante que é útil para entender é a relação entre rostos de fonte individuais e arquivos de fonte que os contêm. A ideia de um arquivo de fonte OpenType (.ttf ou .otf) que contém uma única fonte é familiar. Mas o formato de fonte OpenType também permite uma Coleção de Fontes OpenType (.ttc ou .otc), que é um único arquivo que contém várias fontes. Os arquivos de coleção OpenType geralmente são usados para fontes grandes que estão intimamente relacionadas e têm valores idênticos para determinados dados de fonte: combinando as fontes em um único arquivo, os dados comuns podem ser duplicados. Por esse motivo, uma referência de face de fonte ou de rosto de fonte precisa se referir não apenas a um arquivo de fonte (ou fonte de dados equivalente), mas também deve especificar um índice de fonte dentro desse arquivo, para o caso geral em que o arquivo pode ser um arquivo de coleção. 

Para fontes usadas na Web, os dados de fonte geralmente são empacotados em determinados formatos de contêiner, WOFF ou WOFF2, que fornecem alguma compactação dos dados de fonte e algum nível de proteção contra pirataria e violação de licenças de fonte. Funcionalmente, um arquivo WOFF ou WOFF2 é equivalente a uma fonte OpenType ou arquivo de Coleção de Fontes, mas os dados são codificados em um formato diferente que requer desempacotar antes que possam ser usados. 

Determinadas APIs de DirectWrite podem lidar com rostos de fonte individuais, enquanto outras APIs podem manipular arquivos que podem incluir arquivos da Coleção OpenType que contêm vários rostos. Da mesma forma, determinadas APIs lidam apenas com dados brutos em formato OpenType, enquanto outras APIs podem lidar com os formatos de contêiner empacotados, WOFF e WOFF2. Esses detalhes são fornecidos na discussão abaixo. 

Conjuntos de fontes e coleções de fontes

Alguns aplicativos podem ser implementados para trabalhar com fontes usando a interface IDWriteFontCollection . Há uma correspondência direta entre uma coleção de fontes e um conjunto de fontes. Cada uma pode conter as mesmas fontes, mas elas as apresentam com uma organização diferente. De qualquer coleção de fontes, um conjunto de fontes correspondente pode ser obtido e vice-versa.

Ao trabalhar com várias fontes personalizadas, é mais fácil usar uma interface do construtor de conjunto de fontes para criar um conjunto de fontes personalizado e, em seguida, obter uma coleção de fontes após a criação do conjunto de fontes. O processo para criar um conjunto de fontes personalizado será descrito em detalhes abaixo. Para obter uma interface IDWriteFontCollection1 de um conjunto de fontes, o método IDWriteFactory3::CreateFontCollectionFromFontSet é usado.

Se o aplicativo tiver um objeto de coleção e precisar obter um conjunto de fontes correspondente, isso poderá ser feito usando o método IDWriteFontCollection1::GetFontSet

Cenários comuns

Esta seção descreve alguns dos cenários mais comuns envolvendo conjuntos de fontes personalizados:

  • Criar um conjunto de fontes personalizado usando fontes arbitrárias em caminhos no sistema de arquivos local.
  • Criar um conjunto de fontes personalizado usando fontes conhecidas (talvez agrupadas com o aplicativo) armazenadas no sistema de arquivos local.
  • Criar um conjunto de fontes personalizado usando fontes conhecidas e remotas na Web.
  • Criar um conjunto de fontes personalizado usando dados de fonte carregados na memória.

Implementações completas para esses cenários são fornecidas no exemplo DirectWrite conjuntos de fontes personalizados. Esse exemplo também ilustra mais um cenário avançado para lidar com dados de fonte empacotados em formatos de contêiner WOFF ou WOFF2, que serão discutidos abaixo. 

Criando um conjunto de fontes usando fontes arbitrárias no sistema de arquivos local

Ao lidar com um conjunto arbitrário de arquivos de fonte no armazenamento local, o método IDWriteFontSetBuilder1::AddFontFile é conveniente, pois, em uma única chamada, ele pode manipular todos os rostos de fonte em um arquivo de coleção de fontes OpenType, bem como todas as instâncias de uma fonte de variável OpenType. Isso está disponível na Atualização do Windows 10 para Criadores (versão prévia 15021 ou posterior) e é recomendado sempre que disponível. 

Para usar esse método, use o processo a seguir.

1. Comece criando a interface IDWriteFactory5 :
IDWriteFactory5* pDWriteFactory; 
HRESULT hr = DWriteCreateFactory( 
  DWRITE_FACTORY_TYPE_SHARED, 
  __uuidof(IDWriteFactory5), 
  reinterpret_cast<IUnknown**>(&pDWriteFactory) 
); 

 
2. Use a fábrica para obter a interface IDWriteFontSetBuilder1:

IDWriteFontSetBuilder1* pFontSetBuilder; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder); 
}  
                
  1. Para cada arquivo de fonte no sistema de arquivos local, crie um IDWriteFontFile que se refere a ele:
IDWriteFontFile* pFontFile; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile); 
} 

 
4. Adicione o objeto IDWriteFontFile ao construtor do conjunto de fontes usando o método AddFontFile :

hr = pFontSetBuilder->AddFontFile(pFontFile); 

Se o caminho do arquivo especificado na chamada para CreateFontFileReference se referir a algo diferente de um arquivo OpenType com suporte, a chamada para AddFontFile retornará um erro DWRITE_E_FILEFORMAT.

  1. Depois que todos os arquivos tiverem sido adicionados ao construtor de conjunto de fontes, o conjunto de fontes personalizado poderá ser criado:
IDWriteFontSet* pFontSet; 
hr = pFontSetBuilder->CreateFontSet(&pFontSet); 

 

Se o aplicativo precisar ser executado em versões do Windows 10 anteriores à Atualização do Windows 10 para Criadores, o método AddFontFile não estará disponível. A disponibilidade pode ser detectada criando uma interface IDWriteFactory3 e, em seguida, usando QueryInterface para tentar obter uma interface IDWriteFactory5 : se isso for bem-sucedido, a interface IDWriteFontSetBuilder1 e o método AddFontFile também estarão disponíveis.

Se o método AddFontFile não estiver disponível, o método IDWriteFontSetBuilder::AddFontFaceReference deverá ser usado para adicionar faces de fonte individuais. Para permitir arquivos opentype font collection que contêm várias faces, o método IDWriteFontFile::Analyze pode ser usado para determinar o número de rostos contidos no arquivo. O processo é o seguinte.

1. Comece criando a interface IDWriteFactory3 :
IDWriteFactory3* pDWriteFactory; 
HRESULT hr = DWriteCreateFactory( 
DWRITE_FACTORY_TYPE_SHARED, 
  __uuidof(IDWriteFactory5), 
  reinterpret_cast<IUnknown**>(&pDWriteFactory) 
); 
  1. Use a fábrica para obter a interface IDWriteFontSetBuilder :
IDWriteFontSetBuilder* pFontSetBuilder; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder); 
} 
  1. Para cada arquivo de fonte, crie um IDWriteFontFile, conforme acima:
IDWriteFontFile* pFontFile; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile); 
} 

Em vez de adicionar o arquivo diretamente ao construtor de conjuntos de fontes, precisamos determinar o número de faces e criar objetos IDWriteFontFaceReference individuais. 
4. Use o método Analyze para obter o número de rostos no arquivo. 

BOOL isSupported; 
DWRITE_FONT_FILE_TYPE fileType; 
UINT32 numberOfFonts; 
hr = pFontFile->Analyze(&isSupported, &fileType, /* face type */ nullptr, &numberOfFonts); 

O método Analyze também definirá valores para os parâmetros isSupported e fileType. Se o arquivo não for um formato com suporte, isSupported será FALSE e a ação apropriada, como ignorar o arquivo, poderá ser tomada. 
5. Execute um loop sobre o número de fontes definidas no parâmetro numberOfFonts. Dentro do loop, crie um IDWriteFontFaceReference para cada par de arquivo/índice e adicione-o ao construtor do conjunto de fontes. 

for (uint32_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++) 
{ 
  IDWriteFontFaceReference* pFontFaceReference;
  hr = pDWriteFactory->CreateFontFaceReference(pFontFile, fontIndex, DWRITE_FONT_SIMULATIONS_NONE, &pFontFaceReference);

  if (SUCCEEDED(hr))
  {
    hr = pFontSetBuilder->AddFontFaceReference(pFontFaceReference);
  }
} 
  1. Depois que todos os rostos tiverem sido adicionados ao construtor de conjunto de fontes, crie o conjunto de fontes personalizado, conforme mostrado acima.

Um aplicativo pode ser projetado para que ele use o método AddFontFile preferencial ao ser executado na Atualização do Windows 10 para Criadores, mas faça fallback para usar o método AddFontFaceReference durante a execução em versões anteriores do Windows 10. Teste a disponibilidade da interface IDWriteFactory5 , conforme descrito acima, e, em seguida, branch adequadamente. Essa abordagem é ilustrada no exemplo DirectWrite Conjuntos de Fontes Personalizados

Criando um conjunto de fontes usando fontes conhecidas no sistema de arquivos local

Conforme mencionado acima, cada referência facial de fonte em um conjunto de fontes está associada a determinadas propriedades informativas, como nome da família e peso da fonte. Quando fontes personalizadas são adicionadas a um construtor de conjunto de fontes usando as chamadas à API listadas acima, essas propriedades informativas são obtidas diretamente dos dados reais da fonte, que são lidos à medida que a fonte é adicionada. Em algumas situações, no entanto, se um aplicativo tiver outra fonte de informações sobre uma fonte, talvez ele queira fornecer seus próprios valores personalizados para essas propriedades. 

Como exemplo de como isso pode ser útil, suponha que um aplicativo agrupe algumas fontes que são usadas para apresentar elementos específicos da interface do usuário dentro do aplicativo. Às vezes, como com uma nova versão do aplicativo, as fontes específicas que o aplicativo usa para esses elementos podem precisar ser alteradas. Se o aplicativo tiver referências codificadas às fontes específicas, a substituição de uma fonte por outra exigirá a alteração de cada uma dessas referências. Em vez disso, se o aplicativo usa propriedades personalizadas para atribuir aliases funcionais com base no tipo de elemento ou texto que está sendo renderizado, mapeia cada alias para uma fonte específica em um só lugar e, em seguida, usa os aliases em todos os contextos em que as fontes são criadas e manipuladas e, em seguida, substituir uma fonte por outra requer apenas a alteração de um local em que o alias é mapeado para uma fonte específica. 

Valores personalizados para propriedades informativas podem ser atribuídos quando o método IDWriteFontSetBuilder::AddFontFaceReference é chamado. O método para fazer isso é o seguinte; isso pode ser usado em qualquer versão do Windows 10. 

Conforme mostrado acima, comece obtendo as interfaces IDWriteFactory3 e IDWriteFontSet . Para cada rosto de fonte personalizado a ser adicionado, crie um IDWriteFontFaceReference, conforme mostrado acima. Antes que isso seja adicionado ao construtor de conjunto de fontes (dentro do loop na etapa 5, mostrado acima), no entanto, o aplicativo define os valores de propriedade personalizados a serem usados. 

Um conjunto de valores de propriedade personalizados é definido usando uma matriz de estruturas DWRITE_FONT_PROPERTY . Cada uma delas identifica uma propriedade específica da enumeração DWRITE_FONT_PROPERTY_ID e o valor da propriedade correspondente que deve ser usado.  

Observe que todos os valores de propriedade são atribuídos como cadeias de caracteres. Se eles podem ser exibidos posteriormente para os usuários, valores alternativos para uma determinada propriedade para idiomas diferentes podem ser definidos, mas isso não é necessário. Observe também que, se quaisquer valores de propriedade personalizados forem definidos pelo aplicativo, somente os valores especificados serão usados dentro do conjunto de fontes; DirectWrite não derivará nenhum valor diretamente da fonte para propriedades informativas usadas em um conjunto de fontes. 

O exemplo a seguir define valores personalizados para três propriedades informativas: nome da família, nome completo e peso da fonte. 

DWRITE_FONT_PROPERTY props[] = 
{ 
  { DWRITE_FONT_PROPERTY_ID_FAMILY_NAME, L"My Icon Font", L"en-US" }, 
  { DWRITE_FONT_PROPERTY_ID_FULL_NAME, L"My Icon Font", L"en-US" }, 
  { DWRITE_FONT_PROPERTY_ID_WEIGHT, L"400", nullptr } 
}; 
               
            

Depois de definir a matriz desejada de valores de propriedade para uma fonte, faça uma chamada para AddFontFaceRefence, passando a matriz de propriedades, bem como a referência facial da fonte. 

hr = pFontSetBuilder->AddFontFaceReference(pFontFaceReference, props, ARRAYSIZE(props)); 

 

Depois que todos os rostos de fonte personalizados tiverem sido adicionados ao construtor de conjuntos de fontes, juntamente com suas propriedades personalizadas, crie o conjunto de fontes personalizado, conforme mostrado acima. 

Criando um conjunto de fontes personalizado usando fontes conhecidas e remotas na Web

As propriedades personalizadas são importantes para trabalhar com fontes remotas. Cada referência facial de fonte deve ter algumas propriedades informativas para caracterizar a fonte e distingui-la de outras fontes. Como os dados de fonte para fontes remotas não são locais, DirectWrite não pode derivar propriedades diretamente dos dados da fonte. Portanto, as propriedades devem ser fornecidas explicitamente ao adicionar uma fonte remota ao construtor de conjunto de fontes.

A sequência de chamadas à API para adicionar fontes remotas a um conjunto de fontes é semelhante à sequência descrita para o cenário anterior. Como os dados de fonte são remotos, no entanto, as operações envolvidas para ler os dados reais da fonte serão diferentes do que ao trabalhar com arquivos no armazenamento local. Para essa situação, uma nova interface de nível inferior, IDWriteRemoteFontFileLoader, foi adicionada à Atualização do Windows 10 para Criadores. 

Para usar o carregador de arquivos de fonte remoto, ele deve primeiro ser registrado com uma fábrica de DirectWrite. O carregador precisará ser mantido pelo aplicativo enquanto as fontes associadas a ele estiverem sendo usadas. Depois que as fontes não estiverem mais em uso e, em algum momento, antes que a fábrica seja destruída, o carregador deverá ser cancelado. Isso pode ser feito no destruidor da classe que possui o objeto carregador. Estas etapas serão mostradas abaixo. 

O método para criar um conjunto de fontes personalizado usando fontes remotas é o seguinte; isso requer a Atualização do Windows 10 para Criadores.  

1. Crie uma interface IDWriteFactory5, conforme mostrado acima.  2. Crie uma interface IDWriteFontSetBuilder , conforme mostrado acima.  3. Use a fábrica para obter um IDWriteRemoteFontFileLoader
IDWriteRemoteFontFileLoader* pRemoteFontFileLoader; 
if (SUCCEEDED(hr)) 
{ 
    hr = pDWriteFactory->CreateHttpFontFileLoader( 
        /* referrerURL */ nullptr, 
        /* extraHeaders */ nullptr, 
        &pRemoteFontFileLoader 
    ); 
} 

Isso retorna uma implementação fornecida pelo sistema da interface do carregador de arquivos de fonte remota que é capaz de lidar com interações HTTP para baixar dados de fonte em nome do aplicativo. Uma URL de referenciador ou cabeçalhos extras podem ser especificados se exigido pelo serviço de fonte ou pelos serviços que são a origem das fontes.  

Importante

Observação de segurança: quando é feita uma tentativa de buscar uma fonte remota, existe o potencial de um invasor falsificar o servidor pretendido que será chamado. Nesse caso, as URLs de destino e referenciador e os detalhes do cabeçalho seriam divulgados ao invasor. Os desenvolvedores de aplicativos são responsáveis por atenuar esse risco. O uso do protocolo HTTPS, em vez de HTTP, é recomendado. 

 

Um único carregador de arquivo de fonte remota pode ser usado para várias fontes, embora carregadores diferentes possam ser usados se fontes forem obtidas de vários serviços que têm requisitos diferentes para URL de referenciador ou cabeçalhos extras. 
4. Registre o carregador de arquivos de fonte remoto com a fábrica. 

 if (SUCCEEDED(hr)) 
 { 
     hr = pDWriteFactory->RegisterFontFileLoader(pRemoteFontFileLoader); 
 } 

A partir desse ponto, as etapas para criar o conjunto de fontes personalizado são semelhantes às descritas para arquivos de fonte locais conhecidos, com duas exceções importantes. Primeiro, o objeto IDWriteFontFile é criado usando a interface do carregador de arquivos de fonte remota em vez de usar a fábrica. Segundo, o método Analyze não pode ser usado, pois os dados da fonte não são locais. Em vez disso, o aplicativo deve saber se o arquivo de fonte remoto é um arquivo de coleção de fontes OpenType e, em caso afirmativo, ele deve saber qual das fontes dentro da coleção ele usará e o índice para cada um. Portanto, as etapas restantes são as seguintes. 
5. Para cada arquivo de fonte remota, use a interface do carregador de arquivos de fonte remota para criar um IDWriteFontFile, especificando a URL necessária para acessar o arquivo de fonte. 

 IDWriteFontFile* pFontFile; 
 hr = pRemoteFontFileLoader->CreateFontFileReferenceFromUrl( 
     pDWriteFactory, 
     /* baseUrl */ L"https://github.com/", 
     /* fontFileUrl */ L"winjs/winjs/blob/master/src/fonts/Symbols.ttf?raw=true", 
     &pFontFile 
 ); 

Observe que a URL completa pode ser especificada no parâmetro fontFileUrl ou pode ser dividida em partes base e relativas. Se uma URL base for especificada, a concatenação dos valores baseUrl e fontFileUrl deverá fornecer a URL completa — DirectWrite não fornecerá nenhum delimitador adicional.

Importante

Observação de segurança/desempenho: quando é feita uma tentativa de buscar uma fonte remota, não há nenhuma garantia de que o Windows receberá uma resposta do servidor. Em alguns casos, um servidor pode responder com um erro de arquivo não encontrado para uma URL relativa inválida, mas parar de responder se receber várias solicitações inválidas. Se o servidor não responder, o Windows acabará atingindo o tempo limite, embora isso possa levar vários minutos se várias buscas forem iniciadas. Você deve fazer o que puder para garantir que as URLs serão válidas quando as chamadas forem feitas. 

 

Observe também que a URL pode apontar para um arquivo de fonte OpenType bruto (.ttf, .otf, .ttc, .otc), mas também pode apontar para fontes em um arquivo de contêiner WOFF ou WOFF2. Se um arquivo WOFF ou WOFF2 for referenciado, a implementação DirectWrite do carregador de arquivos de fonte remota desempacotará automaticamente os dados da fonte do arquivo de contêiner. 
6. Para cada índice facial de fonte dentro do arquivo de fonte remoto que deve ser usado, crie um IDWriteFontFaceReference

 IDWriteFontFaceReference* pFontFaceReference; 
 hr = pDWriteFactory->CreateFontFaceReference(pFontFile, /* faceIndex */ 0, DWRITE_FONT_SIMULATIONS_NONE, &pFontFaceReference);
  1. Defina propriedades personalizadas para a face da fonte, conforme mostrado acima. 
  2. Adicione a referência de face da fonte junto com propriedades personalizadas ao construtor de conjunto de fontes, conforme mostrado acima. 
  3. Depois que todas as fontes tiverem sido adicionadas ao construtor de conjunto de fontes, crie o conjunto de fontes, conforme mostrado acima. 
  4. Em algum momento em que as fontes remotas não serão mais usadas, cancele o registro do carregador de arquivos de fonte remoto. 
hr = pDWriteFactory->UnregisterFontFileLoader(pRemoteFontFileLoader); 

Depois que um conjunto de fontes personalizado com fontes remotas personalizadas é criado, o conjunto de fontes contém referências e propriedades informativas para as fontes remotas, mas os dados reais ainda são remotos. DirectWrite suporte para fontes remotas permite que uma referência facial de fonte seja mantida no conjunto de fontes e que uma fonte seja selecionada para uso no layout e na renderização, mas que os dados reais não sejam baixados até que haja uma necessidade real de usá-lo, como quando o layout de texto será executado.  

Um aplicativo pode adotar uma abordagem antecipada solicitando que DirectWrite baixe os dados da fonte e, em seguida, aguardando a confirmação de um download bem-sucedido antes que qualquer processamento com a fonte seja iniciado. Mas um download de rede implica alguma latência de duração imprevisível, e o sucesso também é incerto. Por esse motivo, geralmente será melhor adotar uma abordagem diferente, permitindo que o layout e a renderização sejam feitos inicialmente usando fontes alternativas ou de fallback que já são locais, enquanto solicita o download da fonte remota desejada em paralelo e, em seguida, atualiza os resultados depois que a fonte desejada é baixada. 

Para solicitar que toda a fonte seja baixada antes de ser usada, o método IDWriteFontFaceReference::EnqueueFontDownloadRequest pode ser usado. Se a fonte for muito grande, apenas uma parte dos dados poderá ser necessária para processar cadeias de caracteres específicas. DirectWrite fornece métodos adicionais que podem ser usados para solicitar partes dos dados de fonte necessários para conteúdo específico, EnqueueCharacterDownloadRequest e EnqueueGlyphDownloadRequest.  

Suponha que a abordagem a ser adotada no aplicativo seja permitir que o processamento seja feito inicialmente usando fontes locais, alternativas ou de fallback. O método IDWriteFontFallback::MapCharacters pode ser usado para identificar fontes de fallback locais e também enfileirará automaticamente uma solicitação para baixar a fonte preferencial. Além disso, se IDWriteTextLayout for usado e parte ou todo o texto no layout for formatado usando uma referência de fonte remota, DirectWrite usará automaticamente o método MapCharacters para obter fontes de fallback locais e enfileirar uma solicitação para baixar os dados da fonte remota. 

DirectWrite mantém uma fila de download de fontes para cada fábrica e as solicitações feitas usando os métodos mencionados acima são adicionadas a essa fila. A fila de download de fontes pode ser obtida usando o método IDWriteFactory3::GetFontDownloadQueue

Se uma solicitação de download for feita, mas os dados da fonte já forem locais, isso resultará em uma no-op: Nada será adicionado à fila de download. Um aplicativo pode marcar se a fila está vazia ou se há solicitações de download pendentes chamando o método IDWriteFontDownloadQueue::IsEmpty

Depois que as solicitações de fonte remota tiverem sido adicionadas à fila, o processo de download deverá ser iniciado. Quando fontes remotas são usadas em IDWriteTextLayout, o download será iniciado automaticamente quando o aplicativo chamar métodos IDWriteTextLayout que forçam operações de layout ou renderização, como os métodos GetLineMetrics ou Draw. Em outros cenários, o aplicativo deve iniciar o download diretamente chamando IDWriteFontDownloadQueue::BeginDownload.  

Quando um download for concluído, caberá ao aplicativo executar as ações apropriadas , continuar com operações pendentes ou repetir operações que foram feitas inicialmente com fontes de fallback. (Se o layout de texto de DirectWrite estiver sendo usado, IDWriteTextLayout3::InvalidateLayout poderá ser usado para limpar os resultados temporários calculados usando fontes de fallback.) Para que o aplicativo seja notificado quando o processo de download for concluído e tomar as ações apropriadas, o aplicativo deve fornecer uma implementação da interface IDWriteFontDownloadListener e passá-la para a chamada BeginDownload. 

Importante

Observação de segurança/desempenho: quando é feita uma tentativa de buscar uma fonte remota, não há nenhuma garantia de que o Windows receberá uma resposta do servidor. Se o servidor não responder, o Windows acabará atingindo o tempo limite, embora isso possa levar vários minutos se várias fontes remotas estiverem sendo buscadas, mas falhando. A chamada BeginDownload retornará imediatamente. Os aplicativos não devem bloquear a interface do usuário enquanto esperam que IDWriteFontDownloadListener::D ownloadCompleted seja chamado. 

 

Exemplos de implementações dessas interações com a fila de download de fontes do DirectWrite e a interface IDWriteFontDownloadListener podem ser vistas no exemplo DirectWrite Conjuntos de Fontes Personalizados e também no exemplo DirectWrite Fontes Baixáveis

Criando um conjunto de fontes personalizado usando dados de fonte carregados na memória

Assim como as operações de baixo nível para ler dados de um arquivo de fonte são diferentes para arquivos em um disco local versus arquivos remotos na Web, o mesmo também é verdadeiro para dados de fonte carregados em um buffer de memória. Uma nova interface de baixo nível para lidar com dados de fonte na memória foi adicionada à Atualização do Windows 10 para Criadores, IDWriteInMemoryFontFileLoader

Assim como acontece com um carregador de arquivos de fonte remoto, um carregador de arquivos de fonte na memória deve primeiro ser registrado com uma fábrica de DirectWrite. O carregador precisará ser mantido pelo aplicativo enquanto as fontes associadas a ele estiverem sendo usadas. Depois que as fontes não estiverem mais em uso e, em algum momento, antes que a fábrica seja destruída, o carregador deverá ser cancelado. Isso pode ser feito no destruidor da classe que possui o objeto carregador. Estas etapas serão mostradas abaixo. 

Se o aplicativo tiver informações separadas sobre os rostos de fonte representados pelos dados, ele poderá adicionar referências de face de fonte individuais a um construtor de conjunto de fontes com propriedades personalizadas especificadas. Como os dados da fonte estão na memória local, no entanto, isso não é necessário; DirectWrite poderá ler os dados diretamente para derivar os valores da propriedade. 

DirectWrite pressupõe que os dados da fonte estejam no formato OpenType bruto, equivalente a um arquivo OpenType (.ttf, .otf, .ttc, .otc), mas na memória e não no disco. Os dados não podem estar em um formato de contêiner WOFF ou WOFF2. Os dados podem representar uma Coleção de Fontes OpenType. Se as propriedades personalizadas não estiverem sendo usadas, o método IDWriteFontSetBuilder1::AddFontFile poderá ser usado para adicionar todos os rostos de fonte nos dados em uma única chamada. 

Uma consideração importante para o cenário na memória é o tempo de vida dos dados. Se um ponteiro para o buffer for fornecido para DirectWrite sem uma indicação clara de que há um proprietário, DirectWrite fará uma cópia dos dados em um novo buffer de memória que ele possuirá. Para evitar a cópia de dados e alocação de memória adicional, o aplicativo pode passar um objeto proprietário de dados que implementa IUnknown e que possui o buffer de memória que contém os dados da fonte. Ao implementar essa interface, DirectWrite pode adicionar à contagem de ref do objeto, garantindo assim o tempo de vida dos dados de propriedade. 

O método para criar um conjunto de fontes personalizado usando dados de fonte na memória é o seguinte; isso requer a Atualização do Windows 10 para Criadores. Isso assumirá um objeto de proprietário de dados implementado pelo aplicativo, que implementa IUnknown e também tem métodos que retornam um ponteiro para o buffer de memória e o tamanho do buffer. 

1. Crie uma interface IDWriteFactory5, conforme mostrado acima. 2. Crie uma interface [**IDWriteFontSetBuilder1**](/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontsetbuilder1), conforme mostrado acima. 3. Use a fábrica para obter um IDWriteInMemoryFontFileLoader. 
 IDWriteInMemoryFontFileLoader* pInMemoryFontFileLoader; 
if (SUCCEEDED(hr)) 
{ 
    hr = pDWriteFactory->CreateInMemoryFontFileLoader(&pInMemoryFontFileLoader); 
}

Isso retorna uma implementação fornecida pelo sistema da interface do carregador de arquivos de fonte na memória. 
4. Registre o carregador de arquivos de fonte na memória com a fábrica. 

if (SUCCEEDED(hr)) 
{ 
    hr = pDWriteFactory->RegisterFontFileLoader(pInMemoryFontFileLoader); 
}

 
5. Para cada arquivo de fonte na memória, use o carregador de arquivos de fonte na memória para criar um IDWriteFontFile

IDWriteFontFile* pFontFile; 
hr = pInMemoryFontFileLoader->CreateInMemoryFontFileReference( 
    pDWriteFactory, 
    pFontDataOwner->fontData /* returns void* */, 
    pFontDataOwner->fontDataSize /* returns UINT32 */, 
    pFontDataOwner /* ownerObject, owns the memory with font data and implements IUnknown */, 
    &pFontFile 
); 

 
6. Adicione o objeto IDWriteFontFile ao construtor de conjunto de fontes usando o método AddFontFile , conforme mostrado acima.  Se houver necessidade, o aplicativo poderá, em vez disso, criar objetos IDWriteFontFaceReference individuais com base no IDWriteFontFile, opcionalmente definir propriedades personalizadas para cada referência facial de fonte e, em seguida, adicionar a referência de face de fonte com propriedades personalizadas ao conjunto de fontes usando o método AddFontFaceReference , conforme mostrado acima. 
7. Depois que todas as fontes tiverem sido adicionadas ao construtor de conjunto de fontes, crie o conjunto de fontes personalizado, conforme mostrado acima. 
8. Em algum momento em que as fontes na memória não serão mais usadas, cancele o registro do carregador de arquivos de fonte na memória. 

hr = pDWriteFactory->UnregisterFontFileLoader(pInMemoryFontFileLoader);

 

Cenários avançados

Alguns aplicativos podem ter requisitos especiais que exigem processamento mais avançado do que o descrito acima. 

Combinando conjuntos de fontes

Alguns aplicativos podem precisar criar um conjunto de fontes que inclua alguma combinação de itens de outros conjuntos de fontes. Por exemplo, um aplicativo pode querer criar um conjunto de fontes que combine todas as fontes instaladas no sistema com uma seleção de fontes personalizadas ou que combine fontes instaladas que correspondem a determinados critérios com outras fontes. DirectWrite tem APIs para dar suporte à manipulação e à combinação de conjuntos de fontes. 

Para combinar dois ou mais conjuntos de fontes, o método IDWriteFontSetBuilder::AddFontSet adiciona todas as fontes em determinado conjunto de fontes a serem adicionadas a um construtor de conjunto de fontes em uma única chamada. Se apenas determinadas fontes de um conjunto de fontes existentes forem desejadas no novo conjunto de fontes, o método IDWriteFontSet::GetMatchingFonts poderá ser usado para derivar um novo objeto de conjunto de fontes que foi filtrado para incluir apenas fontes correspondentes às propriedades especificadas. Esses métodos fornecem uma maneira fácil de criar um conjunto de fontes personalizado combinando fontes de dois ou mais conjuntos de fontes existentes

Usando dados de fonte WOFF ou WOFF2 locais

Se um aplicativo tiver arquivos de fonte no sistema de arquivos local ou em um buffer de memória, mas usar os formatos de contêiner WOFF ou WOFF2, DirectWrite (Windows 10 Creator Update ou posterior) fornecerá um método para desempacotar o formato de contêiner, IDWriteFactory5::UnpackFontFile, que retorna um IDWriteFontFileStream

No entanto, o aplicativo precisará de uma maneira de colocar o IDWriteFontFileStream em um objeto carregador de arquivo de fonte. Uma maneira de fazer isso é criar uma implementação IDWriteFontFileLoader personalizada que encapsula o fluxo. Assim como acontece com outros carregadores de arquivos de fonte, isso deve ser registrado antes do uso e cancelado antes que a fábrica saia do escopo.  

Se o carregador personalizado também for usado com arquivos de fonte brutos (não empacotados), o aplicativo também precisará fornecer uma implementação personalizada da interface IDWriteFontFileStream para lidar com esses arquivos. No entanto, há maneiras mais fáceis de usar APIs discutidas acima para lidar com arquivos de fonte brutos. A necessidade de uma implementação de fluxo personalizado pode ser evitada usando caminhos de código separados para arquivos de fonte empacotados versus arquivos de fonte brutos. 

Depois que um objeto carregador de arquivo de fonte personalizado é criado, os dados do arquivo de fonte empacotado são adicionados ao carregador por meios específicos do aplicativo. O carregador pode manipular vários arquivos de fonte, cada um deles identificado usando uma chave definida pelo aplicativo opaca para DirectWrite. Depois que um arquivo de fonte empacotado é adicionado ao carregador, o método IDWriteFactory::CreateCustomFontFileReference é usado para obter um IDWriteFontFile com base nesse carregador para os dados de fonte identificados por uma determinada chave.  

O desempacotamento real dos dados da fonte pode ser feito à medida que fontes são adicionadas ao carregador, mas também pode ser tratado no método IDWriteFontFileLoader::CreateStreamFromKey, que DirectWrite chamará quando precisar ler os dados da fonte pela primeira vez. 

Depois que um objeto IDWriteFontFile tiver sido criado, as etapas restantes para adicionar as fontes a um conjunto de fontes personalizado serão conforme descrito acima. 

Uma implementação que usa essa abordagem é ilustrada no exemplo DirectWrite Conjuntos de Fontes Personalizados

Usando DirectWrite mecanismos de fonte remota com implementação de rede personalizada de baixo nível

Os mecanismos de DirectWrite para lidar com fontes remotas podem ser divididos em mecanismos de nível superior , tendo conjuntos de fontes que incluem referências de rosto de fonte para fontes remotas, verificando a localidade dos dados da fonte e gerenciando a fila para solicitações de download de fontes e os mecanismos de nível inferior que lidam com o download real. Alguns aplicativos podem querer utilizar os mecanismos de fonte remota de nível superior, mas também exigem interações de rede personalizadas, como se comunicar com servidores usando protocolos diferentes de HTTP. 

Para essa situação, um aplicativo precisará criar uma implementação personalizada da interface IDWriteRemoteFontFileLoader que interage com outras interfaces de nível inferior das maneiras necessárias. O aplicativo também precisará fornecer implementações personalizadas dessas interfaces de nível inferior: IDWriteRemoteFontFileStream e IDWriteAsyncResult. Essas três interfaces têm métodos de retorno de chamada que DirectWrite chamarão durante as operações de download. 

Quando IDWriteFontDownloadQueue::BeginDownload for chamado, DirectWrite fará consultas ao carregador de arquivo de fonte remota sobre a localidade dos dados e solicitará o fluxo remoto. Se os dados não forem locais, ele chamará o método BeginDownload do fluxo. A implementação do fluxo não deve ser bloqueada nessa chamada, mas deve retornar imediatamente, retornando um objeto IDWriteAsyncResult que fornece o identificador de espera DirectWrite usará para aguardar a operação de download assíncrona. A implementação do fluxo personalizado é responsável por lidar com a comunicação remota. Quando o evento de conclusão tiver ocorrido, DirectWrite chamará IDWriteAsyncResult::GetResult para determinar o resultado da operação. Se o resultado for bem-sucedido, espera-se que as chamadas readfragment subsequentes para o fluxo dos intervalos baixados sejam bem-sucedidas. 

Importante

Observação de segurança/desempenho: quando é feita uma tentativa de buscar uma fonte remota, o potencial existe em geral para um invasor falsificar o servidor pretendido que está sendo chamado ou que o servidor pode não responder. Se você estiver implementando interações de rede personalizadas, poderá ter maior controle sobre mitigações do que ao lidar com servidores de terceiros. No entanto, cabe a você considerar mitigações apropriadas para evitar a divulgação de informações ou negação de serviço. Protocolos seguros, como HTTPS, são recomendados. Além disso, você deve criar em algum tempo limite para que o identificador de evento retornado ao DirectWrite eventualmente seja definido. 

 

Cenários de suporte em versões anteriores do Windows

Os cenários descritos podem ter suporte em DirectWrite em versões anteriores do Windows, mas exigiriam uma implementação muito mais personalizada por parte do aplicativo usando as APIs mais limitadas que estavam disponíveis antes do Windows 10. Para obter mais informações, consulte Coleções de fontes personalizadas (Windows 7/8).