Partager via


Jeux de polices personnalisés

Cette rubrique décrit différentes façons d’utiliser des polices personnalisées dans votre application.

Introduction

La plupart du temps, les applications utilisent les polices installées localement sur le système. DirectWrite fournit l’accès à ces polices à l’aide des méthodes IDWriteFactory3 ::GetSystemFontSet ou IDWriteFactory ::GetSystemFontCollection. Dans certains cas, les applications peuvent également vouloir utiliser des polices incluses dans windows 10, mais qui ne sont pas actuellement installées sur le système actuel. Ces polices sont accessibles à partir du service de police Windows à l’aide de la méthode GetSystemFontSet, ou en appelant IDWriteFactory3 ::GetSystemFontCollection avec includeDownloadableFonts défini sur TRUE. 

Dans certains scénarios d’application, toutefois, les applications doivent utiliser des polices qui ne sont pas installées dans le système et qui ne sont pas fournies par le service de police Windows. Voici des exemples de tels scénarios :

  • Les polices sont incorporées en tant que ressources dans un fichier binaire d’application.
  • Les fichiers de police sont regroupés dans un package d’application et stockés sur le disque sous le dossier d’installation de l’application.
  • L’application est un outil de développement de polices qui doit charger des fichiers de police spécifiés par l’utilisateur. 
  • Les polices sont incorporées dans des fichiers de document qui peuvent être consultés ou modifiés dans l’application. 
  • L’application utilise des polices obtenues à partir d’un service de police web public. 
  • L’application utilise des données de police diffusées par le biais d’un protocole de réseau privé. 

DirectWrite fournit des API permettant d’utiliser des polices personnalisées dans ces scénarios et d’autres scénarios similaires. Les données de police personnalisées peuvent provenir de fichiers dans le système de fichiers local ; à partir de sources distantes et basées sur le cloud accessibles à l’aide de HTTP ; ou à partir de sources arbitraires après avoir été chargés dans une mémoire tampon. 

Note

Bien que DirectWrite ait fourni des API pour travailler avec des polices personnalisées depuis Windows 7, les API plus récentes ont été ajoutées dans Windows 10 et à nouveau dans Windows 10 Creators Update (préversion build 15021 ou version ultérieure) qui facilitent l’implémentation de plusieurs scénarios mentionnés. Cette rubrique se concentre sur les API disponibles dans la fenêtre 10. Pour les applications qui doivent fonctionner sur des versions antérieures de Windows, consultez collections de polices personnalisées (Windows 7/8)

 

Résumé des API

Cette rubrique se concentre sur les fonctionnalités fournies par les API suivantes :

 

Concepts clés

Pour comprendre les API DirectWrite pour utiliser des polices personnalisées, il peut être utile de comprendre le modèle conceptuel qui sous-tend ces API. Les concepts clés seront décrits ici. 

Lorsque DirectWrite effectue une disposition ou un rendu de texte réel, il doit accéder aux données de police réelles. Un objet visage de police contient des données de police réelles, qui doivent exister dans le système local. Toutefois, pour d’autres opérations, telles que la vérification de la disponibilité d’une police particulière ou la présentation de choix de polices à un utilisateur, tout ce qui est nécessaire est une référence à une police particulière, et non aux données de police proprement dites. Dans DirectWrite, un objet de référence de visage de police contient uniquement les informations nécessaires pour localiser et instancier une police. Étant donné que la référence de visage de police ne contient pas de données réelles, DirectWrite peut gérer les références de visage de police pour lesquelles les données réelles se trouvent dans un emplacement réseau distant, ainsi que lorsque les données réelles sont locales.

Un jeu de polices est un ensemble de références de visage de police, ainsi que certaines propriétés d’information de base qui peuvent être utilisées pour faire référence à la police ou pour la comparer à d’autres polices, telles que le nom de la famille ou une valeur de pondération de police. Les données réelles des différentes polices peuvent être locales, ou elles peuvent toutes être distantes, ou un mélange.

Un jeu de polices peut être utilisé pour obtenir un objet de collection de polices correspondant. Pour plus d’informations, consultez les ensembles de polices et les collections de polices ci-dessous. 

L’interface IDWriteFontSet fournit des méthodes qui permettent d’interroger des valeurs de propriété telles que le nom de famille ou le poids de police, ou pour les références de visage de police qui correspondent à des valeurs de propriété particulières. Après avoir filtré jusqu’à une sélection particulière, une instance de l’interface IDWriteFontFaceReference peut être obtenue, avec des méthodes de téléchargement (si les données de police réelles sont actuellement distantes), pour obtenir le IDWriteFontFace3 correspondant objet qui peut être utilisé pour la disposition et le rendu. 

L’interface IDWriteFontFile sous-jacente chaque référence de visage de police ou de visage de police. Cela représente l’emplacement d’un fichier de police et comporte deux composants : un chargeur de fichiers de police et une clé de fichier de police. Le chargeur de fichiers de police (IDWriteFontFileLoader) est utilisé pour ouvrir un fichier si nécessaire et retourne un flux avec les données (IDWriteFontFileStream). Selon le chargeur, les données peuvent se trouver dans un chemin de fichier local, une URL distante ou dans une mémoire tampon. La clé est une valeur définie par un chargeur qui identifie de manière unique le fichier dans le contexte du chargeur, ce qui permet au chargeur de localiser les données et de créer un flux pour celui-ci. 

Les polices personnalisées peuvent facilement être ajoutées à un jeu de polices personnalisé, qui à son tour peut être utilisé pour filtrer ou organiser des informations de police à des fins telles que la création d’une interface utilisateur du sélecteur de polices. Le jeu de polices peut également être utilisé pour créer une collection de polices à utiliser dans des API de niveau supérieur telles que IDWriteTextFormat et IDWriteTextLayout. L’interface IDWriteFontSetBuilder peut être utilisée pour créer un jeu de polices personnalisé qui inclut plusieurs polices personnalisées. Il peut également être utilisé pour créer un jeu de polices personnalisé qui combine des polices personnalisées et des polices fournies par le système ; ou qui combine des polices avec différentes sources pour les données réelles : stockage local, URL distantes et mémoire. 

Comme mentionné, une référence de visage de police peut faire référence aux données de police à une source distante, mais les données doivent être locales pour obtenir un objet de visage de police qui peut être utilisé pour la disposition et le rendu. Le téléchargement de données distantes est géré par une file d’attente de téléchargement de police. Les applications peuvent utiliser l’interface IDWriteFontDownloadQueue pour mettre en file d’attente les demandes de téléchargement pour lancer le processus de téléchargement et inscrire un objet IDWriteFontDownloadListener pour prendre des mesures lorsque le processus de téléchargement est terminé. 

Pour la plupart des interfaces décrites ici, DirectWrite fournit des implémentations système. L’une des exceptions est l’interface IDWriteFontDownloadListener, qu’une application implémente pour effectuer des actions spécifiques à l’application lorsque des polices distantes ont été téléchargées localement. Les applications peuvent avoir une raison de fournir leurs propres implémentations personnalisées pour certaines autres interfaces, bien que cela ne soit nécessaire que dans des scénarios spécifiques et plus avancés. Par exemple, une application doit fournir une implémentation personnalisée du IDWriteFontFileLoader pour gérer les fichiers de police dans le stockage local qui utilisent le format de conteneur WOFF2. Des détails supplémentaires seront fournis ci-dessous. 

Polices et formats de fichier de police

Un autre concept clé qui est utile à comprendre est la relation entre les visages de police individuels et les fichiers de police qui les contiennent. L’idée d’un fichier de police OpenType (.ttf ou .otf) contenant une police unique est familière. Toutefois, le format de police OpenType autorise également une collection de polices OpenType (.ttc ou .otc), qui est un fichier unique qui contient plusieurs polices. Les fichiers de collection OpenType sont souvent utilisés pour les polices volumineuses étroitement liées et qui ont des valeurs identiques pour certaines données de police : en combinant les polices dans un seul fichier, les données communes peuvent être dédupliquées. Pour cette raison, une référence de visage de police ou de visage de police doit faire référence non seulement à un fichier de police (ou à une source de données équivalente), mais elle doit également spécifier un index de police dans ce fichier, pour le cas général dans lequel le fichier peut être un fichier collection. 

Pour les polices utilisées sur le Web, les données de police sont souvent empaquetées dans certains formats de conteneur, WOFF ou WOFF2, qui fournissent une certaine compression des données de police et un niveau de protection contre le piratage et la violation des licences de police. Fonctionnellement, un fichier WOFF ou WOFF2 équivaut à une police OpenType ou un fichier de collection de polices, mais les données sont encodées dans un autre format qui nécessite un déballage avant de pouvoir être utilisées. 

Certaines API DirectWrite peuvent traiter des visages de police individuels, tandis que d’autres API peuvent gérer des fichiers qui peuvent inclure des fichiers de collection OpenType qui contiennent plusieurs visages. De même, certaines API traitent uniquement des données brutes au format OpenType, tandis que d’autres API peuvent gérer les formats de conteneur packed, WOFF et WOFF2. Ces détails sont fournis dans la discussion ci-dessous. 

Jeux de polices et collections de polices

Certaines applications peuvent être implémentées pour utiliser des polices à l’aide de l’interface IDWriteFontCollection. Il existe une correspondance directe entre une collection de polices et un jeu de polices. Chacun peut contenir les mêmes polices, mais ils les présentent avec une organisation différente. À partir de n’importe quelle collection de polices, un jeu de polices correspondant peut être obtenu, et inversement.

Lorsque vous utilisez un certain nombre de polices personnalisées, il est plus simple d’utiliser une interface de générateur de jeux de polices pour créer un jeu de polices personnalisé, puis d’obtenir une collection de polices une fois le jeu de polices créé. Le processus de création d’un jeu de polices personnalisé sera décrit en détail ci-dessous. Pour obtenir une interface IDWriteFontCollection1 à partir d’un jeu de polices, la méthode IDWriteFactory3 ::CreateFontCollectionFromFontSet est utilisée.

Si l’application a un objet de collection et doit obtenir un jeu de polices correspondant, cela peut être effectué à l’aide de la méthode IDWriteFontCollection1 ::GetFontSet

Scénarios courants

Cette section décrit certains des scénarios les plus courants impliquant des jeux de polices personnalisés :

  • Création d’un jeu de polices personnalisé à l’aide de polices arbitraires sur des chemins d’accès dans le système de fichiers local.
  • Création d’un jeu de polices personnalisé à l’aide de polices connues (peut-être regroupées avec l’application) stockées dans le système de fichiers local.
  • Création d’un jeu de polices personnalisé à l’aide de polices connues et distantes sur le Web.
  • Création d’un jeu de polices personnalisé à l’aide de données de police chargées en mémoire.

Des implémentations complètes pour ces scénarios sont fournies dans l’exemple Jeux de polices personnalisés DirectWrite. Cet exemple illustre également un scénario plus avancé pour la gestion des données de police packées dans les formats de conteneur WOFF ou WOFF2, qui seront abordés ci-dessous. 

Création d’un jeu de polices à l’aide de polices arbitraires dans le système de fichiers local

Lorsque vous traitez d’un ensemble arbitraire de fichiers de police dans le stockage local, la méthode IDWriteFontSetBuilder1 ::AddFontFile est pratique, car, dans un seul appel, elle peut gérer toutes les faces de police dans un fichier de collection de polices OpenType, ainsi que toutes les instances d’une police de variable OpenType. Cette fonctionnalité est disponible dans Windows 10 Creators Update (préversion 15021 ou version ultérieure) et est recommandée chaque fois qu’elle est disponible. 

Pour utiliser cette méthode, utilisez le processus suivant.

1. Commencez par créer l’interface IDWriteFactory5 :
IDWriteFactory5* pDWriteFactory; 
HRESULT hr = DWriteCreateFactory( 
  DWRITE_FACTORY_TYPE_SHARED, 
  __uuidof(IDWriteFactory5), 
  reinterpret_cast<IUnknown**>(&pDWriteFactory) 
); 

 
2. Utilisez la fabrique pour obtenir l’interface IDWriteFontSetBuilder1 :

IDWriteFontSetBuilder1* pFontSetBuilder; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder); 
}  
                
  1. Pour chaque fichier de police dans le système de fichiers local, créez un IDWriteFontFile qui lui fait référence :
IDWriteFontFile* pFontFile; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile); 
} 

 
4. Ajoutez l’objet IDWriteFontFile au générateur de jeux de polices à l’aide de la méthode AddFontFile :

hr = pFontSetBuilder->AddFontFile(pFontFile); 

Si le chemin d’accès au fichier spécifié dans l’appel à CreateFontFileReference fait référence à quelque chose d’autre qu’un fichier OpenType pris en charge, l’appel à AddFontFile retourne une erreur, DWRITE_E_FILEFORMAT.

  1. Une fois que tous les fichiers ont été ajoutés au générateur de jeu de polices, le jeu de polices personnalisé peut être créé :
IDWriteFontSet* pFontSet; 
hr = pFontSetBuilder->CreateFontSet(&pFontSet); 

 

Si l’application doit s’exécuter sur des versions de Windows 10 antérieures à Windows 10 Creators Update, la méthode AddFontFile n’est pas disponible. La disponibilité peut être détectée en créant une interface IDWriteFactory3, puis en utilisant QueryInterface pour essayer d’obtenir une interface IDWriteFactory5 : si cela réussit, l’interface IDWriteFontSetBuilder1 et méthode AddFontFile sera également disponible.

Si la méthode AddFontFile n’est pas disponible, la méthode IDWriteFontSetBuilder ::AddFontFaceReference méthode doit être utilisée pour ajouter des visages de police individuels. Pour autoriser les fichiers de collection de polices OpenType qui contiennent plusieurs visages, la méthode IDWriteFontFile ::Analyze peut être utilisée pour déterminer le nombre de visages contenus dans le fichier. Le processus est le suivant.

1. Commencez par créer l’interface IDWriteFactory3 :
IDWriteFactory3* pDWriteFactory; 
HRESULT hr = DWriteCreateFactory( 
DWRITE_FACTORY_TYPE_SHARED, 
  __uuidof(IDWriteFactory5), 
  reinterpret_cast<IUnknown**>(&pDWriteFactory) 
); 
  1. Utilisez la fabrique pour obtenir l’interface IDWriteFontSetBuilder :
IDWriteFontSetBuilder* pFontSetBuilder; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder); 
} 
  1. Pour chaque fichier de police, créez un IDWriteFontFile, comme ci-dessus :
IDWriteFontFile* pFontFile; 
if (SUCCEEDED(hr)) 
{ 
  hr = pDWriteFactory->CreateFontFileReference(pFilePath, /* lastWriteTime*/ nullptr, &pFontFile); 
} 

Au lieu d’ajouter le fichier directement au générateur de jeux de polices, nous devons déterminer le nombre de visages et créer des objets IDWriteFontFaceReference individuels
4. Utilisez la méthode Analyser pour obtenir le nombre de visages dans le fichier. 

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

La méthode Analyser définit également des valeurs pour les paramètres isSupported et fileType. Si le fichier n’est pas un format pris en charge, isSupported a la valeur FALSE et l’action appropriée, comme ignorer le fichier, peut être effectuée. 
5. Effectuez une boucle sur le nombre de polices définies dans le paramètre numberOfFonts. Dans la boucle, créez un IDWriteFontFaceReference pour chaque paire de fichiers/index, puis ajoutez-le au générateur de jeux de polices. 

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. Une fois que tous les visages ont été ajoutés au générateur de jeu de polices, créez le jeu de polices personnalisé, comme indiqué ci-dessus.

Une application peut être conçue pour qu’elle utilise la méthode AddFontFile préférée lors de l’exécution sur Windows 10 Creators Update, mais revient à utiliser la méthode AddFontFaceReference lors de l’exécution sur les versions antérieures de Windows 10. Testez la disponibilité de l’interfaceIDWriteFactory5, comme décrit ci-dessus, puis branchez en conséquence. Cette approche est illustrée dans l’exemple DirectWrite Custom Font Sets

Création d’un jeu de polices à l’aide de polices connues dans le système de fichiers local

Comme mentionné ci-dessus, chaque référence de visage de police dans un jeu de polices est associée à certaines propriétés d’information, telles que le nom de famille et l’épaisseur de police. Lorsque des polices personnalisées sont ajoutées à un générateur de polices à l’aide des appels d’API répertoriés ci-dessus, ces propriétés d’information sont obtenues directement à partir des données de police réelles, qui sont lues à mesure que la police est ajoutée. Dans certaines situations, toutefois, si une application a une autre source d’informations sur une police, il peut souhaiter fournir ses propres valeurs personnalisées pour ces propriétés. 

Par exemple, supposons qu’une application regroupe certaines polices utilisées pour présenter des éléments d’interface utilisateur particuliers au sein de l’application. Parfois, comme avec une nouvelle version d’application, les polices spécifiques que l’application utilise pour ces éléments peuvent avoir besoin de changer. Si l’application a encodé des références aux polices spécifiques, le remplacement d’une police par une autre nécessite la modification de chacune de ces références. Au lieu de cela, si l’application utilise des propriétés personnalisées pour affecter des alias fonctionnels en fonction du type d’élément ou de texte affiché, mappe chaque alias à une police spécifique à un emplacement, puis utilise les alias dans tous les contextes où les polices sont créées et manipulées, puis en remplaçant une police par une autre ne nécessite que la modification de l’emplacement où l’alias est mappé à une police spécifique. 

Les valeurs personnalisées pour les propriétés informationnelles peuvent être affectées lorsque la méthode IDWriteFontSetBuilder ::AddFontFaceReference est appelée. La méthode pour ce faire est la suivante : cela peut être utilisé sur n’importe quelle version de Windows 10. 

Comme indiqué ci-dessus, commencez par obtenir les interfaces IDWriteFactory 3 et IDWriteFontSet. Pour que chaque visage de police personnalisé soit ajouté, créez un IDWriteFontFaceReference, comme indiqué ci-dessus. Avant d’être ajoutée au générateur de jeu de polices (dans la boucle de l’étape 5, illustrée ci-dessus), toutefois, l’application définit les valeurs de propriété personnalisées à utiliser. 

Un ensemble de valeurs de propriété personnalisées est défini à l’aide d’un tableau de structures DWRITE_FONT_PROPERTY. Chacune d’elles identifie une propriété particulière de l’énumération DWRITE_FONT_PROPERTY_ID et la valeur de propriété correspondante à utiliser.  

Notez que toutes les valeurs de propriété sont attribuées en tant que chaînes. Si ces valeurs peuvent être affichées ultérieurement aux utilisateurs, d’autres valeurs pour une propriété donnée pour différentes langues peuvent être définies, mais cela n’est pas obligatoire. Notez également que si des valeurs de propriété personnalisées sont définies par l’application, seules les valeurs spécifiées seront utilisées dans le jeu de polices ; DirectWrite ne dérive aucune valeur directement de la police pour les propriétés d’information utilisées dans un jeu de polices. 

L’exemple suivant définit des valeurs personnalisées pour trois propriétés d’information : nom de famille, nom complet et poids de police. 

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 } 
}; 
               
            

Après avoir défini le tableau de valeurs de propriété souhaité pour une police, appelez AddFontFaceRefence, en passant le tableau de propriétés ainsi que la référence de visage de police. 

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

 

Une fois que tous les visages de police personnalisés ont été ajoutés au générateur de polices, ainsi que leurs propriétés personnalisées, créez le jeu de polices personnalisé, comme indiqué ci-dessus. 

Création d’un jeu de polices personnalisé à l’aide de polices connues et distantes sur le Web

Les propriétés personnalisées sont importantes pour l’utilisation des polices distantes. Chaque référence de visage de police doit avoir des propriétés d’information pour caractériser la police et la distinguer d’autres polices. Étant donné que les données de police pour les polices distantes ne sont pas locales, DirectWrite ne peut pas dériver les propriétés directement des données de police. Par conséquent, les propriétés doivent être fournies explicitement lors de l’ajout d’une police distante au générateur de jeu de polices.

La séquence d’appels d’API pour l’ajout de polices distantes à un jeu de polices est similaire à la séquence décrite pour le scénario précédent. Étant donné que les données de police sont distantes, toutefois, les opérations impliquées pour la lecture des données de police réelles sont différentes de celles effectuées lors de l’utilisation de fichiers dans le stockage local. Dans ce cas, une nouvelle interface de niveau inférieur, IDWriteRemoteFontFileLoader, a été ajoutée dans Windows 10 Creators Update. 

Pour utiliser le chargeur de fichiers de police distant, il doit d’abord être inscrit auprès d’une fabrique DirectWrite. Le chargeur doit être conservé par l’application tant que les polices associées à celle-ci sont utilisées. Une fois que les polices ne sont plus utilisées et à un moment donné avant la destruction de la fabrique, le chargeur doit être désinscrit. Cette opération peut être effectuée dans le destructeur de la classe propriétaire de l’objet chargeur. Ces étapes s’affichent ci-dessous. 

La méthode de création d’un jeu de polices personnalisé à l’aide de polices distantes est la suivante : Cela nécessite Windows 10 Creators Update.  

1. Créez une interface IDWriteFactory5, comme indiqué ci-dessus.  2. Créez une interface IDWriteFontSetBuilder, comme indiqué ci-dessus.  3. Utilisez la fabrique pour obtenir un IDWriteRemoteFontFileLoader
IDWriteRemoteFontFileLoader* pRemoteFontFileLoader; 
if (SUCCEEDED(hr)) 
{ 
    hr = pDWriteFactory->CreateHttpFontFileLoader( 
        /* referrerURL */ nullptr, 
        /* extraHeaders */ nullptr, 
        &pRemoteFontFileLoader 
    ); 
} 

Cela retourne une implémentation fournie par le système de l’interface de chargeur de fichiers de police distante capable de gérer les interactions HTTP pour télécharger des données de police pour le compte de l’application. Une URL de référence ou des en-têtes supplémentaires peut être spécifiée si nécessaire par le service de police ou les services qui sont la source des polices.  

Important

Remarque de sécurité : lorsqu’une tentative d’extraction d’une police distante est effectuée, le risque existe pour un attaquant d’usurper le serveur prévu qui sera appelé. Dans ce cas, les URL cible et référence et les détails de l’en-tête sont divulgués à l’attaquant. Les développeurs d’applications sont responsables de l’atténuation de ce risque. L’utilisation du protocole HTTPS, plutôt que HTTP, est recommandée. 

 

Un chargeur de fichiers de police distant unique peut être utilisé pour plusieurs polices, bien que différents chargeurs puissent être utilisés si des polices sont obtenues à partir de plusieurs services qui ont des exigences différentes pour l’URL de référence ou les en-têtes supplémentaires. 
4. Inscrivez le chargeur de fichiers de police distant avec la fabrique. 

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

À partir de ce stade, les étapes de création du jeu de polices personnalisé sont similaires à celles décrites pour les fichiers de police locaux connus, avec deux exceptions importantes. Tout d’abord, l’objet IDWriteFontFile est créé à l’aide de l’interface du chargeur de fichiers de police distant plutôt que d’utiliser la fabrique. Ensuite, la méthode Analyze ne peut pas être utilisée, car les données de police ne sont pas locales. Au lieu de cela, l’application doit savoir si le fichier de police distant est un fichier de collection de polices OpenType et, le cas échéant, il doit savoir quelles polices au sein de la collection elle utilisera et l’index pour chacun d’eux. Par conséquent, les étapes restantes sont les suivantes. 
5. Pour chaque fichier de police distant, utilisez l’interface du chargeur de fichiers de police distant pour créer un IDWriteFontFile, en spécifiant l’URL requise pour accéder au fichier de police. 

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

Notez que l’URL complète peut être spécifiée dans le paramètre fontFileUrl, ou qu’elle peut être divisée en parties de base et relatives. Si une URL de base est spécifiée, la concaténation des valeurs baseUrl et fontFileUrl doit fournir l’URL complète . DirectWrite ne fournit aucun délimiteur supplémentaire.

Important

Note de sécurité/performances : lorsqu’une tentative d’extraction d’une police distante n’est pas garantie que Windows recevra une réponse du serveur. Dans certains cas, un serveur peut répondre avec une erreur introuvable dans un fichier pour une URL relative non valide, mais cesser de répondre s’il reçoit plusieurs demandes non valides. Si le serveur ne répond pas, Windows expirera finalement, bien que cela peut prendre plusieurs minutes si plusieurs extractions sont lancées. Vous devez faire ce que vous pouvez faire pour vous assurer que les URL seront valides lorsque des appels sont effectués. 

 

Notez également que l’URL peut pointer vers un fichier de police OpenType brut (.ttf, .otf, .ttc, .otc), mais il peut également pointer vers des polices dans un fichier conteneur WOFF ou WOFF2. Si un fichier WOFF ou WOFF2 est référencé, l’implémentation DirectWrite du chargeur de fichiers de police distant décompresse automatiquement les données de police du fichier conteneur. 
6. Pour chaque index de visage de police dans le fichier de police distant à utiliser, créez un IDWriteFontFaceReference

 IDWriteFontFaceReference* pFontFaceReference; 
 hr = pDWriteFactory->CreateFontFaceReference(pFontFile, /* faceIndex */ 0, DWRITE_FONT_SIMULATIONS_NONE, &pFontFaceReference);
  1. Définissez des propriétés personnalisées pour le visage de police, comme indiqué ci-dessus. 
  2. Ajoutez la référence de visage de police avec les propriétés personnalisées au générateur de jeu de polices, comme indiqué ci-dessus. 
  3. Une fois que toutes les polices ont été ajoutées au générateur de jeu de polices, créez le jeu de polices, comme indiqué ci-dessus. 
  4. À un moment donné, lorsque les polices distantes ne seront plus utilisées, annulez l’inscription du chargeur de fichiers de police distant. 
hr = pDWriteFactory->UnregisterFontFileLoader(pRemoteFontFileLoader); 

Une fois qu’un jeu de polices personnalisé avec des polices distantes personnalisées est créé, le jeu de polices contient des références et des propriétés d’information pour les polices distantes, mais les données réelles sont toujours distantes. La prise en charge de DirectWrite pour les polices distantes permet à une référence de visage de police d’être conservée dans le jeu de polices, et pour qu’une police soit sélectionnée pour être utilisée dans la disposition et le rendu, mais que les données réelles ne sont pas téléchargées tant qu’il n’y a pas besoin de l’utiliser, par exemple lorsque la disposition du texte sera effectuée.  

Une application peut adopter une approche frontale en demandant à DirectWrite de télécharger les données de police, puis en attendant la confirmation d’un téléchargement réussi avant tout traitement avec la police. Mais un téléchargement réseau implique une certaine latence de durée imprévisible, et la réussite est également incertaine. Pour cette raison, il est généralement préférable d’adopter une approche différente, ce qui permet d’effectuer la disposition et le rendu initialement à l’aide de polices alternatives ou de secours déjà locales, tout en demandant le téléchargement de la police souhaitée, distante en parallèle, puis de mettre à jour les résultats une fois la police souhaitée téléchargée. 

Pour demander que la police entière soit téléchargée avant d’être utilisée, la méthode IDWriteFontFaceReference ::EnqueueFontDownloadRequest peut être utilisée. Si la police est très volumineuse, seules une partie des données peut être nécessaire pour traiter des chaînes particulières. DirectWrite fournit des méthodes supplémentaires qui peuvent être utilisées pour demander des parties des données de police nécessaires à un contenu particulier, EnqueueCharacterDownloadRequest et EnqueueGlyphDownloadRequest.  

Supposons que l’approche à adopter dans l’application consiste à autoriser le traitement à effectuer initialement à l’aide de polices locales, alternatives ou de secours. La méthode IDWriteFontFallback ::MapCharacters peut être utilisée pour identifier les polices de secours locales, et elle met également automatiquement en file d’attente une demande de téléchargement de la police préférée. En outre, si IDWriteTextLayout est utilisé et que tout ou partie du texte de la disposition est mis en forme à l’aide d’une référence de police distante, DirectWrite utilise automatiquement la méthode MapCharacters pour obtenir des polices de secours locales et mettre en file d’attente une demande de téléchargement des données de police distantes. 

DirectWrite gère une file d’attente de téléchargement de police pour chaque fabrique et les demandes effectuées à l’aide des méthodes mentionnées ci-dessus sont ajoutées à cette file d’attente. La file d’attente de téléchargement de polices peut être obtenue à l’aide de la méthode IDWriteFactory3 ::GetFontDownloadQueue

Si une demande de téléchargement est effectuée mais que les données de police sont déjà locales, cela entraîne un no-op: rien n’est ajouté à la file d’attente de téléchargement. Une application peut vérifier si la file d’attente est vide ou si des demandes de téléchargement en attente sont en attente en appelant la méthode IDWriteFontDownloadQueue ::IsEmpty

Une fois que les demandes de police distantes ont été ajoutées à la file d’attente, le processus de téléchargement doit être lancé. Lorsque les polices distantes sont utilisées dans IDWriteTextLayout, le téléchargement est lancé automatiquement lorsque l’application appelle IDWriteTextLayout méthodes qui forcent les opérations de disposition ou de rendu, telles que les méthodes GetLineMetrics ou Draw. Dans d’autres scénarios, l’application doit lancer le téléchargement directement en appelant IDWriteFontDownloadQueue ::BeginDownload.  

Lorsqu’un téléchargement est terminé, l’application doit prendre les mesures appropriées , en procédant avec des opérations en attente ou des opérations répétées qui ont été effectuées initialement avec des polices de secours. (Si la disposition de texte de DirectWrite est utilisée, IDWriteTextLayout3 ::InvalidateLayout peut être utilisée pour effacer les résultats temporaires calculés à l’aide de polices de secours.) Pour que l’application soit avertie lorsque le processus de téléchargement s’est terminé et qu’elle prenne les mesures appropriées, l’application doit fournir une implémentation de l'IDWriteFontDownloadListener interface, puis passer cette opération à l’appel BeginDownload. 

Important

Note de sécurité/performances : lorsqu’une tentative d’extraction d’une police distante n’est pas garantie que Windows recevra une réponse du serveur. Si le serveur ne répond pas, Windows expirera, bien que cela peut prendre plusieurs minutes si plusieurs polices distantes sont récupérées mais échouent. L’appel BeginDownload retourne immédiatement. Les applications ne doivent pas bloquer l’interface utilisateur en attendant IDWriteFontDownloadListener ::D ownloadCompleted à appeler. 

 

Des exemples d’implémentations de ces interactions avec la file d’attente de téléchargement de polices de DirectWrite et de l’interface IDWriteFontDownloadListener sont visibles dans l’exemple Ensembles de polices personnalisés DirectWrite, ainsi que dans l’exemple Polices téléchargeables DirectWrite

Création d’un jeu de polices personnalisé à l’aide de données de police chargées en mémoire

Tout comme les opérations de bas niveau pour la lecture des données à partir d’un fichier de police sont différentes pour les fichiers sur un disque local et les fichiers distants sur le Web, la même chose est également vraie pour les données de police chargées dans une mémoire tampon. Une nouvelle interface de bas niveau pour la gestion des données de police en mémoire a été ajoutée dans Windows 10 Creators Update, IDWriteInMemoryFontFileLoader

Comme avec un chargeur de fichiers de police distant, un chargeur de fichiers de police en mémoire doit d’abord être inscrit auprès d’une fabrique DirectWrite. Le chargeur doit être conservé par l’application tant que les polices associées à celle-ci sont utilisées. Une fois que les polices ne sont plus utilisées et à un moment donné avant la destruction de la fabrique, le chargeur doit être désinscrit. Cette opération peut être effectuée dans le destructeur de la classe propriétaire de l’objet chargeur. Ces étapes s’affichent ci-dessous. 

Si l’application dispose d’informations distinctes sur les visages de police représentés par les données, elle peut ajouter des références de visage de police individuelles à un générateur de polices avec des propriétés personnalisées spécifiées. Étant donné que les données de police sont en mémoire locale, cela n’est pas obligatoire ; DirectWrite pourra lire les données directement pour dériver les valeurs de propriété. 

DirectWrite suppose que les données de police sont au format brut, OpenType, équivalent à un fichier OpenType (.ttf, .otf, .ttc, .otc), mais en mémoire plutôt que sur le disque. Les données ne peuvent pas être au format de conteneur WOFF ou WOFF2. Les données peuvent représenter une collection de polices OpenType. Si les propriétés personnalisées ne sont pas utilisées, la méthode IDWriteFontSetBuilder1 ::AddFontFile peut être utilisée pour ajouter tous les visages de police dans les données dans un seul appel. 

Un facteur important pour le scénario en mémoire est la durée de vie des données. Si un pointeur vers la mémoire tampon est fourni à DirectWrite sans indication claire qu’il existe un propriétaire, DirectWrite effectue une copie des données dans une nouvelle mémoire tampon qu’il possède. Pour éviter la copie de données et l’allocation de mémoire supplémentaire, l’application peut transmettre un objet propriétaire de données qui implémente IUnknown et qui possède la mémoire tampon contenant les données de police. En implémentant cette interface, DirectWrite peut ajouter au nombre de références de l’objet, ce qui garantit la durée de vie des données détenues. 

La méthode de création d’un jeu de polices personnalisé à l’aide de données de police en mémoire est la suivante : Cela nécessite Windows 10 Creators Update. Cela suppose un objet de propriétaire de données implémenté par l’application, qui implémente IUnknown et possède également des méthodes qui retournent un pointeur vers la mémoire tampon et la taille de la mémoire tampon. 

1. Créez une interface IDWriteFactory5, comme indiqué ci-dessus. 2. Créez une interface [**IDWriteFontSetBuilder1***](/windows/win32/api/dwrite_3/nn-dwrite_3-idwritefontsetbuilder1), comme indiqué ci-dessus. 3. Utilisez la fabrique pour obtenir un IDWriteInMemoryFontFileLoader. 
 IDWriteInMemoryFontFileLoader* pInMemoryFontFileLoader; 
if (SUCCEEDED(hr)) 
{ 
    hr = pDWriteFactory->CreateInMemoryFontFileLoader(&pInMemoryFontFileLoader); 
}

Cela retourne une implémentation fournie par le système de l’interface de chargeur de fichiers de police en mémoire. 
4. Inscrivez le chargeur de fichiers de police en mémoire auprès de la fabrique. 

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

 
5. Pour chaque fichier de police en mémoire, utilisez le chargeur de fichiers de police en mémoire pour créer un 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. Ajoutez l’objet IDWriteFontFile au générateur de jeux de polices à l’aide de la méthode AddFontFile, comme indiqué ci-dessus.  En cas de besoin, l’application peut créer des idWriteFontFaceReference individuelles objets basés sur l'IDWriteFontFile, définir éventuellement des propriétés personnalisées pour chaque référence de visage de police, puis ajouter la référence de visage de police avec des propriétés personnalisées à la police définie à l’aide de la méthode AddFontFaceReference, comme indiqué ci-dessus. 
7. Une fois toutes les polices ajoutées au générateur de jeu de polices, créez le jeu de polices personnalisé, comme indiqué ci-dessus. 
8. À un moment donné, lorsque les polices en mémoire ne seront plus utilisées, annulez l’inscription du chargeur de fichiers de police en mémoire. 

hr = pDWriteFactory->UnregisterFontFileLoader(pInMemoryFontFileLoader);

 

Scénarios avancés

Certaines applications peuvent avoir des exigences particulières qui nécessitent un traitement plus avancé que décrit ci-dessus. 

Combinaison de jeux de polices

Certaines applications peuvent avoir besoin de créer un jeu de polices qui comprend une combinaison d’éléments d’autres jeux de polices. Par exemple, une application peut souhaiter créer un jeu de polices qui combine toutes les polices installées sur le système avec une sélection de polices personnalisées ou qui combine des polices installées correspondant à certains critères avec d’autres polices. DirectWrite a des API pour prendre en charge la manipulation et la combinaison de jeux de polices. 

Pour combiner deux ensembles de polices ou plus, la méthode IDWriteFontSetBuilder ::AddFontSet ajoute toutes les polices dans un jeu de polices donné à ajouter à un générateur de jeux de polices dans un seul appel. Si seules certaines polices d’un jeu de polices existant sont souhaitées dans le nouveau jeu de polices, la méthode IDWriteFontSet ::GetMatchingFonts peut être utilisée pour dériver un nouvel objet de jeu de polices filtré pour inclure uniquement les polices correspondant aux propriétés spécifiées. Ces méthodes offrent un moyen simple de créer un jeu de polices personnalisé combinant des polices à partir de deux jeux de polices existants ou plus

Utilisation des données de police WOFF ou WOFF2 locales

Si une application possède des fichiers de police dans le système de fichiers local ou dans une mémoire tampon, mais qu’elle utilise les formats de conteneur WOFF ou WOFF2, DirectWrite (Windows 10 Creator Update ou version ultérieure) fournit une méthode pour décompresser le format de conteneur, IDWriteFactory5 ::UnpackFontFile, qui retourne un IDWriteFontFileStream

Toutefois, l’application a besoin d’un moyen d’obtenir l'IDWriteFontFileStream dans un objet chargeur de fichiers de police. Pour ce faire, vous devez créer une implémentation personnalisée IDWriteFontFileLoader qui encapsule le flux. Comme pour les autres chargeurs de fichiers de police, cela doit être enregistré avant l’utilisation et non enregistré avant que la fabrique ne soit hors de portée.  

Si le chargeur personnalisé sera également utilisé avec des fichiers de police bruts (non emballés), l’application doit également fournir une implémentation personnalisée de l'IDWriteFontFileStream interface pour la gestion de ces fichiers. Toutefois, il existe des façons plus simples d’utiliser les API décrites ci-dessus pour gérer les fichiers de police bruts. La nécessité d’une implémentation de flux personnalisé peut être évitée en utilisant des chemins de code distincts pour les fichiers de police compressés et les fichiers de police bruts. 

Une fois qu’un objet de chargeur de fichiers de police personnalisé est créé, les données de fichier de police empaquetées sont ajoutées au chargeur par moyen spécifique à l’application. Le chargeur peut gérer plusieurs fichiers de police, chacun d’eux étant identifié à l’aide d’une clé définie par l’application opaque pour DirectWrite. Une fois qu’un fichier de police packé a été ajouté au chargeur, la méthode IDWriteFactory ::CreateCustomFontFileReference est utilisée pour obtenir un IDWriteFontFile en fonction de ce chargeur pour les données de police identifiées par une clé donnée.  

La décompression réelle des données de police peut être effectuée à mesure que les polices sont ajoutées au chargeur, mais peuvent également être gérées dans la méthode IDWriteFontFileLoader ::CreateStreamFromKey, que DirectWrite appelle quand il doit d’abord lire les données de police. 

Une fois qu’un objet IDWriteFontFile a été créé, les étapes restantes pour ajouter les polices à un jeu de polices personnalisé seront décrites ci-dessus. 

Une implémentation utilisant cette approche est illustrée dans l’exemple DirectWrite Custom Font Sets

Utilisation de mécanismes de police distants DirectWrite avec une implémentation réseau de bas niveau personnalisée

Les mécanismes DirectWrite pour la gestion des polices distantes peuvent être divisés en mécanismes de niveau supérieur , avec des jeux de polices qui incluent des références de police pour les polices distantes, la vérification de la localité des données de police et la gestion de la file d’attente pour les demandes de téléchargement de polices , ainsi que les mécanismes de niveau inférieur qui gèrent le téléchargement réel. Certaines applications peuvent vouloir utiliser les mécanismes de police distants de niveau supérieur, mais nécessitent également des interactions réseau personnalisées, telles que la communication avec des serveurs à l’aide de protocoles autres que HTTP. 

Dans ce cas, une application doit créer une implémentation personnalisée de l’interface IDWriteRemoteFontFileLoader qui interagit avec d’autres interfaces de niveau inférieur de la manière requise. L’application doit également fournir des implémentations personnalisées de ces interfaces de niveau inférieur : IDWriteRemoteFontFileStreamet IDWriteAsyncResult. Ces trois interfaces ont des méthodes de rappel que DirectWrite appelle pendant les opérations de téléchargement. 

Lorsque IDWriteFontDownloadQueue ::BeginDownload est appelé, DirectWrite effectue des requêtes au chargeur de fichiers de police distant sur la localité des données et demande le flux distant. Si les données ne sont pas locales, elles appellent la méthode BeginDownload du flux. L’implémentation de flux ne doit pas bloquer cet appel, mais doit immédiatement retourner un IDWriteAsyncResult objet qui fournit le handle d’attente DirectWrite utilisera pour attendre l’opération de téléchargement asynchrone. L’implémentation de flux personnalisé est chargée de gérer la communication à distance. Lorsque l’événement d’achèvement s’est produit, DirectWrite appelle IDWriteAsyncResult ::GetResult pour déterminer le résultat de l’opération. Si le résultat réussit, il est attendu que les appels ReadFragment suivants au flux pour les plages téléchargées réussissent. 

Important

Remarque de sécurité/performances : lorsqu’une tentative est effectuée pour extraire une police distante, le potentiel existe en général pour qu’un attaquant usurpe l’identité du serveur prévu appelé ou que le serveur ne réponde pas. Si vous implémentez des interactions réseau personnalisées, vous avez peut-être plus de contrôle sur les atténuations que lors du traitement des serveurs tiers. Toutefois, il vous incombe de prendre en compte les mesures d’atténuation appropriées pour éviter la divulgation d’informations ou le déni de service. Les protocoles sécurisés tels que HTTPS sont recommandés. En outre, vous devez générer dans un délai d’attente afin que le handle d’événement retourné à DirectWrite ait finalement été défini. 

 

Scénarios de prise en charge sur les versions antérieures de Windows

Les scénarios décrits peuvent être pris en charge dans DirectWrite sur les versions antérieures de Windows, mais nécessitent une implémentation beaucoup plus personnalisée sur la partie de l’application à l’aide des API plus limitées disponibles avant Windows 10. Pour plus d’informations, consultez collections de polices personnalisées (Windows 7/8).