Jeux de polices personnalisés
Cette rubrique décrit les différentes façons dont vous pouvez utiliser des polices personnalisées dans votre application.
- Introduction
- Résumé des API
- Concepts clés
- Polices et formats de fichier de police
- Jeux de polices et collections de polices
-
Scénarios courants
- Création d’un jeu de polices à l’aide de polices arbitraires dans le système de fichiers local
- Création d’un jeu de polices à l’aide de polices connues dans le système de fichiers local
- Création d’un jeu de polices personnalisé à l’aide de polices distantes connues sur le web
- Création d’un jeu de polices personnalisé à l’aide de données de police chargées en mémoire
- Scénarios avancés
Introduction
La plupart du temps, les applications utilisent les polices installées localement sur le système. DirectWrite permet d’accéder à 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 le cadre de Windows 10 mais qui ne sont pas installées actuellement sur le système actuel. Ces polices sont accessibles à partir du service de polices 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 polices Windows. Voici quelques exemples de scénarios de ce type :
- 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 les fichiers document qui peuvent être consultés ou modifiés dans l’application.
- L’application utilise des polices obtenues à partir d’un service de polices Web public.
- L’application utilise des données de police diffusées via un protocole réseau privé.
DirectWrite fournit des API permettant d’utiliser des polices personnalisées dans ces scénarios et dans 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 basées sur le cloud accessibles à l’aide du protocole HTTP ; ou à partir de sources arbitraires après avoir été chargé dans une mémoire tampon.
Notes
Bien que DirectWrite ait fourni des API permettant d’utiliser des polices personnalisées depuis Windows 7, des API plus récentes ont été ajoutées dans Windows 10 et à nouveau dans le Windows 10 Creators Update (préversion build 15021 ou ultérieure) qui facilitent l’implémentation de plusieurs des 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 :
- Interface IDWriteFontSet
- Interface IDWriteFontSetBuilder
- Interface IDWriteFontSetBuilder1
- Interface IDWriteFontFaceReference
- Interface IDWriteFontFile
- IDWriteFactory::CreateFontFileReference, méthode
- IDWriteFactory::CreateCustomFontFileReference, méthode
- MÉTHODES IDWriteFactory3::CreateFontFaceReference
- DWRITE_FONT_PROPERTY structure
- énumération DWRITE_FONT_PROPERTY_ID
- Interface IDWriteFontFileLoader
- MÉTHODE IDWriteFactory::RegisterFontFileLoader
- MÉTHODE IDWriteFactory::UnregisterFontFileLoader
- MÉTHODE IDWriteFactory5::CreateInMemoryFontFileLoader
- Interface IDWriteInMemoryFontFileLoader
- MÉTHODE IDWriteFactory5::CreateHttpFontFileLoader
- Interface IDWriteRemoteFontFileLoader
- Interface IDWriteFontDownloadQueue
- Interface IDWriteFontDownloadListener
- Interface IDWriteFontFileStream
- Interface IDWriteRemoteFontFileStream
- Interface IDWriteAsyncResult
- IDWriteFactory5::AnalyzeContainerType , méthode
- IDWriteFactory5::UnpackFontFile , méthode
Concepts clés
Pour comprendre les DIRECTWRITE API pour l’utilisation de polices personnalisées, il peut être utile de comprendre le modèle conceptuel qui sous-tend ces API. Les concepts clés sont décrits ici.
Lorsque DirectWrite effectue la mise en page ou le rendu du texte réel, il doit accéder aux données de police réelles. Un objet de face de police contient les 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 police à un utilisateur, il suffit d’une référence à une police particulière, et non aux données de police elles-mêmes. Dans DirectWrite, un objet de référence de face de police contient uniquement les informations nécessaires pour localiser et instancier une police. Étant donné que la référence de face de police ne contient pas de données réelles, DirectWrite pouvez 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 face 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 famille ou une valeur de poids de police. Les données réelles pour les 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 Jeux de polices et 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 face de police qui correspondent à des valeurs de propriété particulières. Après avoir filtré sur 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 l’objet IDWriteFontFace3 correspondant qui peut être utilisé pour la disposition et le rendu.
L’interface IDWriteFontFile sous-tend chaque visage de police ou référence de visage de police. Cela représente l’emplacement d’un fichier de police et comporte deux composants : un chargeur de fichiers de polices 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 d’accès de fichier local, un URL distante ou dans une mémoire tampon. La clé est une valeur définie par le 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 celle-ci.
Les polices personnalisées peuvent facilement être ajoutées à un jeu de polices personnalisé, qui à leur tour peuvent être utilisées pour filtrer ou organiser les informations de police à des fins telles que la création d’une interface utilisateur de 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 comme IDWriteTextFormat et IDWriteTextLayout. L’interface IDWriteFontSetBuilder peut être utilisée pour créer un jeu de polices personnalisé qui comprend plusieurs polices personnalisées. Il peut également être utilisé pour créer un jeu de polices personnalisé qui mélange 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 d’une source distante, mais les données doivent être locales pour obtenir un objet de face de police qui peut être utilisé pour la disposition et le rendu. Le téléchargement des données distantes est géré par une file d’attente de téléchargement de polices. Les applications peuvent utiliser l’interface IDWriteFontDownloadQueue pour mettre en file d’attente les demandes de téléchargement de polices distantes afin de lancer le processus de téléchargement et pour inscrire un objet IDWriteFontDownloadListener pour effectuer une action lorsque le processus de téléchargement est terminé.
Pour la plupart des interfaces décrites ici, DirectWrite fournit des implémentations système. La seule exception 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 des raisons 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 de l’interface IDWriteFontFileLoader pour gérer les fichiers de police dans le stockage local qui utilisent le format de conteneur WOFF2. Des détails supplémentaires sont fournis ci-dessous.
Polices et formats de fichier de police
Un autre concept clé qu’il est utile de 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 seule police 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 qui sont étroitement liées et ont des valeurs identiques pour certaines données de police : en combinant les polices dans un fichier unique, les données communes peuvent être dédupliquées. Pour cette raison, une référence de police ou de face de police doit faire référence non seulement à un fichier de polices (ou à une source de données équivalente), mais elle doit également spécifier un index de police dans ce fichier, dans le cas général où 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 certain niveau de protection contre le piratage et la violation des licences de police. Fonctionnellement, un fichier WOFF ou WOFF2 est équivalent à 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écompression 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 contenant 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. Chacune peut contenir les mêmes polices, mais elle leur présente une organization différente. À partir de n’importe quelle collection de polices, un jeu de polices correspondant peut être obtenu, et vice versa.
Lorsque vous travaillez avec un certain nombre de polices personnalisées, il est plus facile 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 après la création du jeu de polices. 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, vous pouvez le faire à 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 au niveau 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 distantes connues 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 DirectWrite jeux de polices personnalisés. Cet exemple illustre également un scénario plus avancé pour la gestion des données de police empaquetées dans des formats de conteneur WOFF ou WOFF2, qui sera abordé ci-dessous.
Création d’un jeu de polices à l’aide de polices arbitraires dans le système de fichiers local
Lors du traitement d’un ensemble arbitraire de fichiers de polices dans le stockage local, la méthode IDWriteFontSetBuilder1::AddFontFile est pratique, car, en 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 option est disponible dans le Windows 10 Creators Update (préversion 15021 ou ultérieure) et est recommandée chaque fois que cela est disponible.
Pour utiliser cette méthode, utilisez le processus suivant.
- 1. Commencez par créer l’interface IDWriteFactory5 :
- Pour chaque fichier de police dans le système de fichiers local, créez un IDWriteFontFile qui y fait référence :
- Une fois tous les fichiers ajoutés au générateur de jeux de polices, le jeu de polices personnalisé peut être créé :
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);
}
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 faisait référence à autre chose qu’un fichier OpenType pris en charge, l’appel à AddFontFile renvoie une erreur, DWRITE_E_FILEFORMAT.
IDWriteFontSet* pFontSet;
hr = pFontSetBuilder->CreateFontSet(&pFontSet);
Si l’application doit s’exécuter sur Windows 10 versions antérieures à la Windows 10 Creators Update, la méthode AddFontFile ne sera 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 la méthode AddFontFile seront également disponibles.
Si la méthode AddFontFile n’est pas disponible, la méthode IDWriteFontSetBuilder::AddFontFaceReference 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 :
- Utilisez la fabrique pour obtenir l’interface IDWriteFontSetBuilder :
- Pour chaque fichier de police, créez un IDWriteFontFile, comme ci-dessus :
- Une fois que tous les visages ont été ajoutés au générateur de jeux de polices, créez le jeu de polices personnalisé, comme indiqué ci-dessus.
IDWriteFactory3* pDWriteFactory;
HRESULT hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory5),
reinterpret_cast<IUnknown**>(&pDWriteFactory)
);
IDWriteFontSetBuilder* pFontSetBuilder;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateFontSetBuilder(&pFontSetBuilder);
}
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 Analyze 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 Analyze 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 une action appropriée, telle que l’ignorance du fichier, peut être effectuée.
5. Boucle sur le nombre de polices définies dans le paramètre numberOfFonts. Dans la boucle, créez un IDWriteFontFaceReference pour chaque paire fichier/index et 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);
}
}
Une application peut être conçue de telle sorte qu’elle utilise la méthode AddFontFile préférée lors de l’exécution sur le Windows 10 Creators Update, mais revient à utiliser la méthode AddFontFaceReference lors de l’exécution sur des versions antérieures Windows 10. Testez la disponibilité de l’interface IDWriteFactory5 , comme décrit ci-dessus, puis branchez en conséquence. Cette approche est illustrée dans l’exemple DirectWrite jeux de polices personnalisés.
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 face de police dans un jeu de polices est associée à certaines propriétés d’information, telles que le nom de famille et le poids de police. Lorsque des polices personnalisées sont ajoutées à un générateur de jeux 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 au fur et à mesure de l’ajout de la police. Dans certaines situations, toutefois, si une application a une autre source d’informations sur une police, elle 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, par exemple avec une nouvelle version d’application, les polices spécifiques que l’application utilise pour ces éléments doivent parfois être modifiées. Si l’application a des références encodées aux polices spécifiques, le remplacement d’une police par une autre nécessite de modifier 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. Le remplacement d’une police par une autre ne nécessite que la modification de l’emplacement où l’alias est mappé à une police spécifique.
Des valeurs personnalisées pour les propriétés d’information peuvent être affectées lorsque la méthode IDWriteFontSetBuilder::AddFontFaceReference est appelée. Pour ce faire, la méthode est la suivante : il peut être utilisé sur n’importe quelle version Windows 10.
Comme indiqué ci-dessus, commencez par obtenir les interfaces IDWriteFactory3 et IDWriteFontSet . Pour chaque face de police personnalisée à ajouter, créez un IDWriteFontFaceReference, comme indiqué ci-dessus. Toutefois, avant d’ajouter ce paramètre au générateur de jeux de polices (dans la boucle de l’étape 5, illustrée ci-dessus), 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 . Chacun de ces éléments 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 affectées sous forme de chaînes. Si elles 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 pas de valeurs 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 souhaité de valeurs de propriété pour une police, effectuez un appel à AddFontFaceRefence, en passant le tableau de propriétés ainsi que la référence de face de police.
hr = pFontSetBuilder->AddFontFaceReference(pFontFaceReference, props, ARRAYSIZE(props));
Une fois que toutes les faces de police personnalisées ont été ajoutées au générateur de jeux 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 distantes connues sur le web
Les propriétés personnalisées sont importantes pour l’utilisation des polices distantes. Chaque référence de face de police doit avoir des propriétés d’information pour caractériser la police et la distinguer des autres polices. Étant donné que les données de police des polices distantes ne sont pas locales, DirectWrite ne peuvent pas dériver des propriétés directement à partir 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 jeux 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. Toutefois, étant donné que les données de police sont distantes, les opérations impliquées pour la lecture des données de police réelles seront différentes de celles liées à l’utilisation de fichiers dans le stockage local. Dans ce cas, une nouvelle interface de niveau inférieur, IDWriteRemoteFontFileLoader, a été ajoutée dans le Windows 10 Creators Update.
Pour utiliser le chargeur de fichiers de polices distant, il doit d’abord être inscrit auprès d’une fabrique de DirectWrite. Le chargeur doit être conservé par l’application tant que les polices qui lui sont associées 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 qui possède l’objet chargeur. Ces étapes sont indiquées 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 le 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.
- Définissez des propriétés personnalisées pour le visage de police, comme indiqué ci-dessus.
- Ajoutez la référence du visage de police ainsi que des propriétés personnalisées au générateur de jeux de polices, comme indiqué ci-dessus.
- Une fois que toutes les polices ont été ajoutées au générateur de jeux de polices, créez le jeu de polices, comme indiqué ci-dessus.
- À un moment donné, lorsque les polices distantes ne sont plus utilisées, annulez l’inscription du chargeur de fichiers de polices distantes.
IDWriteRemoteFontFileLoader* pRemoteFontFileLoader;
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->CreateHttpFontFileLoader(
/* referrerURL */ nullptr,
/* extraHeaders */ nullptr,
&pRemoteFontFileLoader
);
}
Cette opération retourne une implémentation fournie par le système de l’interface de chargeur de fichiers de polices distante qui est en mesure de gérer les interactions HTTP pour le téléchargement des données de police pour le compte de l’application. Une URL de référence ou des en-têtes supplémentaires peuvent être spécifiés si le service de polices 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, un attaquant risque d’usurper le serveur prévu qui sera appelé. Dans ce cas, les URL de la cible et du référent, ainsi que les détails de l’en-tête, sont divulgués à l’attaquant. Les développeurs d’applications sont chargés d’atténuer ce risque. L’utilisation du protocole HTTPS, plutôt que HTTP, est recommandée.
Un seul chargeur de fichiers de polices distant peut être utilisé pour plusieurs polices, mais différents chargeurs peuvent être utilisés si des polices sont obtenues à partir de plusieurs services qui ont des exigences différentes pour l’URL du référent ou des en-têtes supplémentaires.
4. Inscrivez le chargeur de fichiers de polices distant auprès de la fabrique.
if (SUCCEEDED(hr))
{
hr = pDWriteFactory->RegisterFontFileLoader(pRemoteFontFileLoader);
}
À partir de ce point, 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 de chargeur de fichiers de polices distante plutôt qu’à l’aide de la fabrique. Deuxièmement, 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 polices distant est un fichier de collection de polices OpenType et, si c’est le cas, elle doit savoir quelles polices au sein de la collection elle utilisera, et l’index pour chacune d’elles. Par conséquent, les étapes restantes sont les suivantes.
5. Pour chaque fichier de police distant, utilisez l’interface du chargeur de fichiers de polices distantes pour créer un IDWriteFontFile, en spécifiant l’URL requise pour accéder au fichier de polices.
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 fournira pas de délimiteur supplémentaire.
Important
Remarque sur la sécurité et les performances : lorsqu’une tentative est effectuée pour extraire une police distante, il n’y a aucune garantie que Windows recevra une réponse du serveur. Dans certains cas, un serveur peut répondre avec une erreur de fichier introuvable 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 finit par expirer, bien que cela puisse prendre plusieurs minutes si plusieurs extractions sont lancées. Vous devez faire ce que vous pouvez 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 qu’elle 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 face 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);
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. DirectWrite prise en charge des polices distantes permet de conserver une référence de face de police dans le jeu de polices et de sélectionner une police pour une utilisation dans la mise en page et le rendu, mais que les données réelles ne sont pas téléchargées tant qu’il n’est pas nécessaire de l’utiliser, par exemple quand la mise en page du texte sera effectuée.
Une application peut adopter une approche à l’avance en demandant que DirectWrite télécharger les données de police, puis en attendant la confirmation d’un téléchargement réussi avant de commencer tout traitement avec la police. Toutefois, 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, en autorisant la disposition et le rendu à effectuer initialement à l’aide de polices alternatives ou de secours qui sont déjà locales, tout en demandant le téléchargement de la police distante souhaitée en parallèle, puis en mettant à 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, vous pouvez utiliser la méthode IDWriteFontFaceReference::EnqueueFontDownloadRequest . Si la police est très grande, seule 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 pour 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 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 utilisera automatiquement la méthode MapCharacters pour obtenir les polices de secours locales et mettre en file d’attente une demande de téléchargement des données de police distantes.
DirectWrite conserve une file d’attente de téléchargement de polices 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 une absence d’opération : Rien n’est ajouté à la file d’attente de téléchargement. Une application peut case activée si la file d’attente est vide ou s’il existe des demandes de téléchargement en attente en appelant la méthode IDWriteFontDownloadQueue::IsEmpty.
Une fois les demandes de police distantes ajoutées à la file d’attente, le processus de téléchargement doit être lancé. Lorsque des polices distantes sont utilisées dans IDWriteTextLayout, le téléchargement est lancé automatiquement lorsque l’application appelle des méthodes IDWriteTextLayout 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é, il incombe à l’application de prendre les mesures appropriées, en procédant aux opérations en attente ou en répétant les opérations 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é pour effacer les résultats temporaires calculés à l’aide des polices de secours.) Pour que l’application soit avertie lorsque le processus de téléchargement est terminé et qu’elle prenne les mesures appropriées, l’application doit fournir une implémentation de l’interface IDWriteFontDownloadListener et la transmettre à l’appel BeginDownload.
Important
Remarque sur la sécurité et les performances : lorsqu’une tentative est effectuée pour extraire une police distante, il n’y a aucune garantie que Windows recevra une réponse du serveur. Si le serveur ne répond pas, Windows finit par expirer, bien que cela puisse prendre plusieurs minutes si plusieurs polices distantes sont récupérées mais échouent. L’appel BeginDownload est retourné immédiatement. Les applications ne doivent pas bloquer l’interface utilisateur en attendant l’appel de IDWriteFontDownloadListener::D ownloadCompleted .
Vous trouverez des exemples d’implémentations de ces interactions avec la file d’attente de téléchargement de polices de DirectWrite et l’interface IDWriteFontDownloadListener dans l’exemple DirectWrite Jeux de polices personnalisés, ainsi que dans l’exemple DirectWrite Polices téléchargeables.
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 de lecture des données d’un fichier de police sont différentes pour les fichiers sur un disque local et les fichiers distants sur le Web, il en va de même 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 le Windows 10 Creators Update, IDWriteInMemoryFontFileLoader.
Comme avec un chargeur de fichiers de polices distant, un chargeur de fichiers de polices en mémoire doit d’abord être inscrit auprès d’une fabrique de DirectWrite. Le chargeur doit être conservé par l’application tant que les polices qui lui sont associées 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 qui possède l’objet chargeur. Ces étapes sont indiquées 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 police individuelles à un générateur de jeux de polices avec des propriétés personnalisées spécifiées. Toutefois, étant donné que les données de police sont en mémoire locale, cela n’est pas nécessaire ; DirectWrite pourrez 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 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.
Une considération importante 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 pour DirectWrite sans indication claire qu’il existe un propriétaire, DirectWrite effectuera une copie des données dans une nouvelle mémoire tampon dont elle sera propriétaire. Pour éviter la copie de données et l’allocation de mémoire supplémentaire, l’application peut passer 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 pouvez ajouter au nombre de références de l’objet, garantissant ainsi 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 le Windows 10 Creators Update. Cela suppose un objet 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);
}
Cette opération retourne une implémentation fournie par le système de l’interface de chargeur de fichiers de polices en mémoire.
4. Inscrivez le chargeur de fichiers de polices 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 polices en mémoire pour créer un FICHIER 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. Si nécessaire, l’application peut créer des objets IDWriteFontFaceReference individuels basés sur IDWriteFontFile, définir éventuellement des propriétés personnalisées pour chaque référence de face de police, puis ajouter la référence de face de police avec des propriétés personnalisées au jeu de polices à l’aide de la méthode AddFontFaceReference , comme indiqué ci-dessus.
7. Une fois que toutes les polices ont été ajoutées au générateur de jeux 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 polices 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 celui 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 vouloir 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 les polices installées correspondant à certains critères avec d’autres polices. DirectWrite dispose d’API pour prendre en charge la manipulation et la combinaison de jeux de polices.
Pour combiner au moins deux jeux de polices, 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 qui a été 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 ou plusieurs jeux de polices existants
Utilisation des données de police WOFF ou WOFF2 locales
Si une application a 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 de chargeur de fichiers de polices. Pour ce faire, vous pouvez créer une implémentation IDWriteFontFileLoader personnalisée qui encapsule le flux. Comme pour les autres chargeurs de fichiers de police, celui-ci doit être inscrit avant l’utilisation et désinscrit avant que la fabrique ne sorte de l’étendue.
Si le chargeur personnalisé est également utilisé avec des fichiers de police bruts (non compressés), l’application doit également fournir une implémentation personnalisée de l’interface IDWriteFontFileStream pour gérer 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 brutes. 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.
Après la création d’un objet chargeur de fichiers de polices personnalisé, les données du fichier de police packées sont ajoutées au chargeur par des moyens spécifiques à 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 polices compressé a été ajouté au chargeur, la méthode IDWriteFactory::CreateCustomFontFileReference est utilisée pour obtenir un IDWriteFontFile basé sur ce chargeur pour les données de police identifiées par une clé donnée.
Le déballage réel des données de police peut être effectué à mesure que les polices sont ajoutées au chargeur, mais peut également être gérée dans la méthode IDWriteFontFileLoader::CreateStreamFromKey, que DirectWrite appelleront quand il aura besoin de lire les données de police pour la première fois.
Une fois qu’un objet IDWriteFontFile a été créé, les étapes restantes pour ajouter les polices à un jeu de polices personnalisé sont décrites ci-dessus.
Une implémentation utilisant cette approche est illustrée dans l’exemple DirectWrite jeux de polices personnalisés.
Utilisation DirectWrite mécanismes de police distants avec une implémentation réseau de bas niveau personnalisée
Les mécanismes DirectWrite pour gérer les polices distantes peuvent être divisés en mécanismes de niveau supérieur (avoir des jeux de polices qui incluent des références de police pour les polices distantes, vérifier la localité des données de police et gérer la file d’attente pour les demandes de téléchargement de polices) et 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 elles 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 : IDWriteRemoteFontFileStream et IDWriteAsyncResult. Ces trois interfaces ont des méthodes de rappel que DirectWrite appelleront 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, elle appelle la méthode BeginDownload du flux. L’implémentation du flux ne doit pas bloquer cet appel, mais doit immédiatement retourner un objet IDWriteAsyncResult qui fournit le handle d’attente DirectWrite utiliserez pour attendre l’opération de téléchargement asynchrone. L’implémentation de flux personnalisé est responsable de la gestion de la communication à distance. Lorsque l’événement d’achèvement s’est produit, DirectWrite appellera 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 sur la sécurité et les performances : lorsqu’une tentative est effectuée pour extraire une police distante, un attaquant risque en général d’usurper le serveur en cours d’appel ou de ne pas répondre au serveur. Si vous implémentez des interactions réseau personnalisées, vous pouvez avoir un contrôle plus important sur les atténuations que lorsque vous traitez avec des serveurs tiers. Toutefois, il vous incombe d’envisager des mesures d’atténuation appropriées pour éviter la divulgation d’informations ou le déni de service. Des protocoles sécurisés tels que HTTPS sont recommandés. En outre, vous devez générer dans un certain délai d’expiration afin que le handle d’événement retourné à DirectWrite finisse par être 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 des versions antérieures de Windows, mais nécessitent une implémentation beaucoup plus personnalisée de la part de l’application à l’aide des API plus limitées qui étaient disponibles avant Windows 10. Pour plus d’informations, consultez Collections de polices personnalisées (Windows 7/8).