Cet article a fait l'objet d'une traduction automatique.

Facteur DirectX

Qui a peur du glyphe fonctionne ?

Charles Petzold

Télécharger l'exemple de code

Charles PetzoldJ'ai d'abord rencontré le concept de glyphes de caractères dans Windows Presentation Foundation (WPF) quelques années en arrière. En typographie, « glyphe » désigne la représentation graphique d'un caractère plutôt que de sa fonction dans une langue particulière écrite, ce qui est indiquée par la valeur Unicode du caractère. Je savais que l'élément WPF glyphes et classe GlyphRun représente un autre moyen pour afficher du texte, mais ils semblaient ajouter une couche de complexité inutile. La plus grande bizarrerie impliqué référençant une police désirée, pas par un nom de famille de polices, mais par le chemin d'accès du fichier police réelle. J'avais été codant pour Windows depuis la version bêta de 1.0, et je n'avais jamais nécessaire pour référencer une police par le nom de fichier. Ce n'était tout simplement pas comment c'est fait.

Rapidement, j'ai conclu que les Glyphs et GlyphRun étaient beaucoup trop ésotérique pour les programmeurs comme moi. Seuls ans plus tard, quand j'ai commencé à travailler avec le système d'exploitation Microsoft XML Paper Specification (XPS) a fait la raison d'être de glyphes deviennent apparents.

La Distinction fondamentale

Normalement lorsqu'un programme demande une police sur Windows, il le fait à l'aide d'un nom de famille de polices comme Century Schoolbook et attributs, tels qu'italique ou gras. Lors de l'exécution, Windows détecte un fichier de polices sur le système de l'utilisateur avec une police qui correspond au nom de famille. Italique et gras peut être intrinsèque à cette police ou synthétisée par le système. Pour mettre en page texte, soit Windows, soit l'application accède aux informations métriques de police qui décrit les tailles de polices de caractères.

Que se passe-t-il si deux utilisateurs différents ont deux fichiers de polices différentes sur leurs systèmes que les deux contiennent une police avec le nom de famille Century Schoolbook, mais avec les paramètres de police un peu différente ? Ce n'est pas un vrai problème. Parce que le texte est formaté et aménagé lors de l'exécution, le rendu réel de ces deux polices pourrait être légèrement différent, mais il ne serait pas vraiment d'importance. Programmes d'application sont conçus pour être flexibles, de cette façon.

Documents XPS sont différentes, cependant. Comme PDF, XPS décrit bien un document de page fixe. Tout le texte sur chaque page est déjà aménagé et positionner avec précision. Si un tel document est rendu avec une police qui est légèrement différente de la police utilisée pour la conception de la page, il ne sera pas regarder à droite. Il s'agit de documents XPS contiennent souvent des fichiers de police incorporée, et pourquoi les pages XPS utilisent l'élément Glyphs pour référencer ces fichiers de police et de restituer le texte. Toute ambiguïté est complètement éliminée.

Normalement, nous nous référons à des caractères par les codes de caractères. Nous avons habituellement n'avez pas besoin de tout savoir sur le glyphe précis qui arrive à afficher par suite de l'utilisation de ce code de caractère avec une police particulière. Mais parfois, il est important d'avoir davantage de contrôle sur les glyphes eux-mêmes.

Vous pourriez supposer il y a une correspondance biunivoque entre les codes de caractères et des glyphes dans une police particulière, et c'est habituellement le cas. Mais il y a des exceptions très importantes : Certains fichiers de polices contiennent des ligatures, qui sont des glyphes unique correspondant aux paires de caractères telles que fi ou fl. Certains jeux de caractères non latins nécessite plusieurs glyphes pour restituer un caractère unique. En outre, certains fichiers de polices contiennent des glyphes pour certains caractères, par exemple, un zéro avec une barre oblique à travers elle, petites majuscules utilisées pour minuscules ou lettres à paraphes stylistiques. Ces variantes stylistiques sont caractéristiques d'un fichier de police particulière plutôt qu'une police. C'est pourquoi obtenir le fichier de police droite est crucial.

Si vous écrivez une application Windows Store pour Windows 8, vous pouvez faire usage de ces alternatives stylistiques grâce à l'API d'exécution de Windows. Chapitre 16 de « Programmation Windows, 6e édition » (o ' Reilly Media, 2012) a un programme appelé TypographyDemo qui montre comment faire exactement cela. Mais le support sous-jacent pour les glyphes dans Windows 8 est implémenté dans DirectX et le pouvoir des glyphes eux-mêmes se révèle le plus dans cet environnement.

Le Support de DirectX glyphe

Explorer l'affichage des glyphes dans DirectX consiste à tracer un chemin à travers plusieurs interfaces, méthodes et structures.

Commençons par l'interface ID2D1RenderTarget qui contient les méthodes de base pour afficher le texte et les graphismes en 2D. Cette interface définit une méthode DrawGlyphRun. Cette méthode nécessite une structure de type DWRITE_GLYPH_RUN qui décrit les glyphes à afficher, et aussi fait référence à un objet de type IDWriteFontFace.

Une façon pour obtenir un objet IDWriteFontFace est par le biais de la méthode de CreateFontFace de IDWriteFactory. Cette méthode nécessite un objet IDWriteFontFile, qui est obtenu par le biais de la méthode de CreateFontFileReference de IDWriteFactory.

La méthode CreateFontFileReference fait référence à un fichier de polices à l'aide d'un chemin d'accès et le nom de fichier. Toutefois, si vous utilisez DirectX dans une application Windows Store, votre application n'aurez probablement pas pleinement et librement accès au disque dur de l'utilisateur, et vous ne pouvez accéder généralement les polices de cette manière. N'importe quel fichier de polices que vous référencer avec CreateFontFileReference sera probablement défini comme une ressource d'application et d'être lié dans le paquet de l'application.

Toutefois, vous ne pouvez pas inclure n'importe quel fichier de police dans le package de l'application. Si une police est partie de votre application, vous devez posséder une licence de distribuer cette police. Heureusement, Microsoft a autorisé plusieurs fichiers de polices d'Ascender Corp. dans le but exprès de vous permettre de les distribuer avec votre application. Ces fichiers de polices ont été utilisés principalement pour des applications de XNA, mais ils sont aussi intéressants d'un point de vue de glyphes.

Le code pour cette colonne est un programme appelé GlyphDump que j'ai créé basé sur le modèle de DirectX App (XAML) dans le Visual Studio Express 2013 Preview. Ce modèle crée une application qui restitue des graphismes DirectX sur une SwapChainPanel.

J'ai créé un nouveau filtre (et le dossier correspondant) dans le projet de GlyphDump nommé Fonts et ajouté les fichiers de 10 polices sous licenciés par Ascender Corp. Un ListBox dans DirectXPage.xaml énumère explicitement les noms de famille de ces polices, avec des propriétés de la balise référençant les noms de fichiers. Lorsque l'une est sélectionnée, le programme construit le chemin et le nom du fichier de polices comme suit :

Package::Current->InstalledLocation->Path +
  "\\Fonts\\" + filename;

La classe GlyphDumpRenderer utilise ensuite ce chemin pour créer un objet IDWriteFontFile et un objet IDWriteFontFace.

Le reste du travail se produit dans la méthode Render, comme le montre Figure 1.

Figure 1 la méthode Render dans GlyphDump

bool GlyphDumpRenderer::Render()
{
  if (!m_needsRedraw)
      return false;
  ID2D1DeviceContext* context = m_deviceResources->GetD2DDeviceContext();
  context->SaveDrawingState(m_stateBlock.Get());
  context->BeginDraw();
  context->Clear(ColorF(ColorF::White));
  context->SetTransform(m_deviceResources->GetOrientationTransform2D());
  if (m_fontFace != nullptr)
  {
    Windows::Foundation::Size outputBounds = m_deviceResources->GetOutputBounds();
    uint16 glyphCount = m_fontFace->GetGlyphCount();
    int rows = (glyphCount + 16) / 16;
    float boxHeight = outputBounds.Height / (rows + 1);
    float boxWidth = outputBounds.Width / 17;
    // Define entire structure except glyphIndices
    DWRITE_GLYPH_RUN glyphRun;
    glyphRun.fontFace = m_fontFace.Get();
    glyphRun.fontEmSize = 0.75f * min(boxHeight, boxWidth);
    glyphRun.glyphCount = 1;
    glyphRun.glyphAdvances = nullptr;
    glyphRun.glyphOffsets = nullptr;
    glyphRun.isSideways = false;
    glyphRun.bidiLevel = 0;
    for (uint16 index = 0; index < glyphCount; index++)
    {
      glyphRun.glyphIndices = &index;
      context->DrawGlyphRun(Point2F(((index) % 16 + 0.5f) * boxWidth,
                                    ((index) / 16 + 1) * boxHeight),
                                    &glyphRun,
                                    m_blackBrush.Get());
    }
  }
  // We ignore D2DERR_RECREATE_TARGET here.
This error indicates
  // that the device is lost.
It will be handled during
  // the next call to Present.
HRESULT hr = context->EndDraw();
  if (hr != D2DERR_RECREATE_TARGET)
  {
    DX::ThrowIfFailed(hr);
  }
  context->RestoreDrawingState(m_stateBlock.Get());
  m_needsRedraw = false;
  return true;
}

Cette méthode de rendu affiche tous les glyphes dans le fichier de police sélectionnée en rangées de 16 glyphes chaque, donc il essaie de calculer une valeur de fontEmSize suffisamment petite pour que l'affichage. (Pour certaines polices avec plusieurs glyphes, cela ne fonctionnera pas bien.) Normalement, le champ glyphIndices de la structure DWRITE_GLYPH_RUN est un tableau d'indices de glyphe. Ici, je suis seulement afficher un glyphe à la fois.

La méthode DrawGlyphRun nécessite un point de coordonnée, la structure DWRITE_GLYPH_RUN et une brosse. La coordonnée indique où le bord gauche de la ligne de base de la glyphe doit être placé. Notez que j'ai dit « de base ». Ceci est différent de la plupart des méthodes d'affichage texte, nécessitant spécifiant le coin haut-gauche du premier caractère.

La figure 2 montre peut-être la police plus intéressante de ce lot, qui a un nom de famille de Pescadero et un nom de fichier de police de Pesca.ttf.

The GlyphDump Program Showing the Pescadero Font
Figure 2 le programme de GlyphDump montrant la police Pescadero

Avant d'écrire ce programme, je n'avais jamais vu un écran comme celui-ci. Il commence à la recherche de quelque chose comme un tableau ASCII traditionnel, mais ensuite, il y a un tas de glyphes pour numérique mise en indice et en exposant et toute une collection de ligatures de diverses sortes, plus les majuscules avec ornements décoratifs.

Évidemment, le domaine de la glyphIndices de DWRITE_GLYPH_RUN n'est pas identique à un code de caractère. Ce sont des indices qui référencent les glyphes réelles dans le fichier de police, et ces glyphes ne doivent même être dans n'importe quel ordre rationnel.

Texte de glyphes

Vous pouvez déjà voir certaine utilité à pouvoir afficher du texte en utilisant un fichier de police spécifique avec des indices de glyphe plutôt que des codes de caractères. Vous pouvez spécifier exactement quels glyphes que vous voulez.

Le projet FancyTitle montre cela. L'idée ici est que vous avez un programme qui est surtout basée sur XAML, mais vous voulez un titre fantaisie à l'aide de quelques ligatures et des lettres italiques ornées de la police Pescadero. Le projet comprend le fichier Pesca.ttf et le fichier XAML définit la SwapChainPanel pour avoir une largeur de 778 et une hauteur de 54, valeurs, j'ai choisi empiriquement basés sur la taille du texte affiché.

Parce que les exigences de l'affichage de ce projet sont simples, j'ai enlevé la classe FancyTitleMain et les classes de rendu, laissant la classe DirectXPage pour restituer à le SwapChainPanel. (Cependant, j'ai dû modifier DeviceResources légèrement pour faire IDeviceNotify une interface de classe Réf afin que DirectXPage pourrait implémenter IDevice­Notify et être averti lorsque le périphérique de sortie est perdu et recréé.)

La sortie de texte affichée dans Figure 3 a 24 caractères, mais seulement 22 glyphes. Vous reconnaîtrez les ligatures et les lettres italiques ornées de Figure 2.

The FancyTitle Output
Figure 3 la sortie de FancyTitle

J'ai fait le fond de DirectX bleu Alice donc vous pouvez voir que le SwapChainPanel est à peine plus grand que le texte. Bien sûr, il est possible de prévoir la taille de la sortie exactement parce que le fichier de police fait partie de la demande et les glyphes sont accédées directement.

Vous pouvez obtenir des ligatures et des glyphes alternatifs sans utiliser de DrawGlyphRun. Vous pouvez aussi les obtenir avec moins de précision à l'aide de l'élément TextBlock dans l'exécution de Windows, comme la typographie­programme de démonstration de mon livre Windows 8 illustre. Dans DirectWrite, vous pouvez utiliser la méthode SetTypography de IDWriteTextLayout avec un objet IDWriteTypography, qui en fin de compte fait référence à un membre de l'énumération DWRITE_FONT_FEATURE_TAG vaste. Mais ces techniques ne sont pas tout à fait certains que les glyphes à spécifier précisément.

Comment obtenez-vous les italiques et gras avec DrawGlyphRun ? Dans de nombreux cas, les fichiers de polices différentes contiendra des variations d'une police italiques et gras. Parmi les polices fournies par le programme de GlyphDump sont un couple de polices "BOLD" et une police de lumière. Cependant, vous avez également la possibilité de simuler des caractères obliques et "BOLD" à l'aide de drapeaux DWRITE_FONT_SIMULATIONS dans CreateFontFace.

Avances et compense

Les GlyphDump et FancyTitle deux des champs situé dans DWRITE_GLYPH_RUN pour le nullptr. Ces deux champs sont nommés glyphAdvances et glyphOffsets.

Lorsque vous affichez un tableau de glyphes, vous spécifiez l'origine du niveau de référence de gauche du premier caractère. Pour chaque caractère successifs, la position horizontale de l'origine est automatiquement augmentée basée sur la largeur du caractère. (Un processus semblable se produit lors de l'affichage de texte sur le côté). Cette augmentation est connue comme une « avance ».

Vous pouvez obtenir les avances que DirectX utilise des caractères d'espacement en appelant la méthode GetDesignGlyphMetrics de la IDWriteFontFace. Le résultat est un tableau de structures DWRITE_GLYPH_METRICS, un pour chaque index de glyphes dans lequel vous êtes intéressé. Le champ advanceWidth de cette structure indique à l'avance par rapport au champ designUnitsPerEm de la structure de la DWRITE_FONT_METRICS obtenue par la méthode de GetMetrics de IDWriteFontFace, et qui comprend également des métriques verticaux applicables à tous les glyphes dans une police particulière.

Ou, vous pouvez appeler la méthode GetDesignGlyphAdvances de IDWriteFontFace1, qui fournit également des progrès par rapport à la valeur de designUnitsPerEm. Diviser les valeurs de designUnitsPerEm (qui est souvent une belle valeur ronde comme 2 048) et puis multiplier par la taille exprimée en em spécifiée dans DWRITE_GLYPH_RUN.

Le tableau glyphAdvances est couramment pour espacer les caractères plus près ensemble ou plus loin dehors que les mesures de conception indiquent. Si vous décidez de l'utiliser, vous devez définir glyphAdvances sur un tableau de valeurs qui est au moins la taille du tableau des indices de glyphe, moins un. Une avance n'est pas nécessaire sur le glyphe de final parce que rien ne s'affiche en outre.

Le champ glyphOffsets est un tableau de structures DWRITE_GLYPH_OFFSET, un pour chaque caractère. Les deux champs sont advanceOffset et ascenderOffset, qui indiquent un décalage souhaité (vers la droite et de haut, respectivement) par rapport à la position normale du personnage. Cette installation est souvent utilisée dans les fichiers XPS pour positionner plusieurs glyphes d'une police particulière partout dans la page.

Le programme CenteredGlyphDump montre comment utiliser le champ glyphOffsets pour afficher le tableau dans son intégralité de glyphes provenant d'un fichier de police particulière avec un seul appel de DrawGlyphRun :

context->DrawGlyphRun(Point2F(), &m_glyphRun, m_blackBrush.Get());

Est la coordonnée passée à DrawGlyphRun (0, 0), et glyphAdvances est définie sur un tableau de valeurs nulles pour inhiber l'avancement des glyphes successifs. La position de chaque glyphe est entièrement régie par glyphOffsets. Cette position repose sur la métrologie de glyphe pour centrer chaque glyphe dans sa colonne. La Figure 4 illustre le résultat.

The CenteredGlyphDump Program
Figure 4 le programme de CenteredGlyphDump

Fournir votre propre chargeur de polices

Si un fichier de police fait partie d'un package d'application, il est assez facile de calculer un chemin de fichier, que vous pouvez utiliser avec CreateFontReference. Mais que se passe-t-il si vous avez une police qui se trouve dans un package XPS ou EPUB, peut-être dans un stockage isolé ou dans le nuage ?

Tant que vous pouvez écrire du code qui accède au fichier de polices, DirectX peut accéder. Vous devrez fournir deux classes, une qui implémente IDWriteFontFileLoader et l'autre qui implémente IDWriteFontFileStream. Généralement, la classe qui implémente IDWriteFontFileLoader est un singleton qui accède à tous les fichiers de polices votre application aura besoin et assigne à chacun d'entre eux une clé. La méthode CreateStreamFromKey dans votre implémentation de IDWriteFontFileLoader retourne une instance de IDWriteFontStream pour chaque fichier de police.

Pour utiliser ces deux classes, vous d'abord instanciez une seule instance de la classe qui implémente IDWriteFontFileLoader et passez à la RegisterFontFileLoader de votre objet de IDWriteFactory. Puis, au lieu d'appeler CreateFontFileReference pour obtenir un objet IDWriteFontFile, appelez CreateCustomFontFileReference avec cette instance de IDWriteFontFileLoader et une clé identifiant le fichier de police particulière souhaitée.

Cette technique est démontrée dans le programme CenteredGlyphDump. Le projet comprend deux classes — PrivateFontFileLoader et PrivateFontFileStream, qui implémente les deux interfaces. Les classes polices d'accès des fichiers dans le package d'application, mais ils pourraient être adaptés à d'autres fins.

Il est probable que votre implémentation de IDWriteFontFileLoader devra effectuer des appels de fichier I/O, et dans une application Windows Store, ces appels doivent être asynchrones. Cela fait beaucoup de sens pour la classe IDWriteFontFileLoader définir une méthode asynchrone qui charge toutes les polices en mémoire et pour la IDWriteFontFileStream de pointeurs simplement regagner ces blocs de mémoire. Il s'agit de l'approche que j'ai pris avec PrivateFontFileLoader et PrivateFontFileStream, après avoir examiné attentivement le Direct2D Magazine App échantillon parmi les exemples de code Microsoft pour Windows 8.1.

La clé identifier chaque fichier, j'ai utilisé le nom de fichier. Après que la méthode de chargement asynchrone dans PrivateFontFileLoader est terminée, le programme CenteredGlyphDump obtient les noms de ces fichiers pour la ListBox. C'est pourquoi seuls les noms de fichiers sont affichés dans Figure 4. Le programme ignore les noms de famille de polices associées à chaque fichier.

De caractères aux glyphes

Bien sûr, affichage de texte en référençant des glyphes est très bien si vous savez exactement quels glyphes dont vous avez besoin, mais vous pouvez afficher normales caractères Unicode à l'aide de DrawGlyphRun ?

Vous pouvez, car IDWriteFontFace a une méthode GetGlyphIndices qui convertit des codes de caractère à l'index de glyphes pour le fichier de police particulière. Ce faisant, il choisit le glyphe par défaut pour chaque code de caractère, donc vous n'aurez aucune des alternatives fantaisies.

Mais les codes de caractères, que vous passez à GetGlyphIndices sont sous une forme peut-être unique dans l'ensemble de Windows. Au lieu de caractères 16 bits codes (comme c'est le cas lorsque vous travaillez normalement avec des chaînes de caractères Unicode), vous devez créer un tableau de codes de caractère de 32 bits. Comme vous le savez, Unicode est en fait un personnage de 21 bits défini, mais les caractères sont généralement stockés en tant que valeurs 16 bits (appelés UTF-16), ce qui signifie que certains caractères comprennent deux valeurs 16 bits. Mais GetGlyphIndices veut des valeurs de 32 bits. À moins que votre chaîne de caractères comporte des caractères avec les codes ci-dessus 0xFFFF, vous pouvez transférer simplement les valeurs d'un tableau à l'autre.

Si vous avez affaire à des caractères normaux de l'alphabet Latin, vous pouvez aussi supposer qu'il existe une correspondance biunivoque entre les caractères et les glyphes. Dans le cas contraire, vous devrez peut-être créer un tableau de sortie plus grand pour recevoir les indices.

Cette technique simple est illustrée par le projet HelloGlyphRun. Figure 5 illustre le code qui charge un fichier de polices et met en place une structure DWRITE_GLYPH_RUN. La méthode de mise à jour permet de régler les décalages des glyphes pour atteindre une sorte d'ondulation effet du texte.

La figure 5, définissant un DWRITE_GLYPH_RUN d'une chaîne de caractères

// Convert string to glyph indices
std::wstring str = L"Hello, Glyph Run!";
uint32 glyphCount = str.length();
std::vector<uint32> str32(glyphCount);
for (uint32 i = 0; i < glyphCount; i++)
     str32[i] = str[i];
m_glyphIndices = std::vector<uint16>(glyphCount);
m_fontFace->GetGlyphIndices(str32.data(), glyphCount, m_glyphIndices.data());
// Allocate array for offsets (set during Update)
m_glyphOffsets = std::vector<DWRITE_GLYPH_OFFSET>(glyphCount);
// Get output bounds
Windows::Foundation::Size outputBounds = m_deviceResources->GetOutputBounds();
// Define fields of DWRITE_GLYPH_RUN structure
m_glyphRun.fontFace = m_fontFace.Get();
m_glyphRun.fontEmSize = outputBounds.Width / 8; // Empirical
m_glyphRun.glyphCount = glyphCount;
m_glyphRun.glyphIndices = m_glyphIndices.data();
m_glyphRun.glyphAdvances = nullptr;
m_glyphRun.glyphOffsets = m_glyphOffsets.data();
m_glyphRun.isSideways = false;
m_glyphRun.bidiLevel = 0;

Bien que vous utiliserez probablement DrawGlyphRun uniquement avec les fichiers de polices avec que vous êtes intimement familier, il est possible de déterminer quel type de glyphes sont contenues dans un fichier de police particulière lors de l'exécution. IDWriteFontFace définit une méthode TryGetFontTable qui accède à des tables dans le fichier OpenFont. Utilisez une étiquette de « cmap » pour la table de caractère-à-glyphe et « GSUB » pour la table de substitution de glyphes, mais soyez prêt à passer de nombreuses heures atroces avec la spécification OpenType pour lire ces tableaux avec succès.

Glyphe s'exécute à l'aide des polices système

DrawGlyphRun est seulement bon pour les fichiers de polices que vous fournissez vous-même ? Dans un premier temps, il semblerait donc, mais vous pouvez l'utiliser avec les polices système ainsi. Voici le processus : Utilisez la méthode GetSystemFontCollection de IDWriteFactory pour obtenir un objet IDWriteFontCollection. Cet objet permet de rechercher tous les noms de famille associés avec les polices installées sur le système. La méthode GetFontFamily IDWriteFontCollection retourne un objet de type IDWriteFontFamily. De là, vous pouvez appeler GetMatchingFonts ou GetFirstMatchingFont pour combiner la famille de polices avec attributs italiques, gras et extensibles pour obtenir un IDWriteFont.

Une fois que vous avez un objet IDWriteFont, composez le CreateFontFace pour obtenir un objet IDWriteFontFace. C'est le même type d'objet obtenu à partir de CreateFontFace dans les programmes antérieurs ! Dans cet objet, vous pouvez commencer portant création d'une structure DWRITE_GLYPH_RUN des DrawGlyphRun.

Cela est illustré dans le projet SystemFontGlyphs. Le projet utilise la GetSystemFontCollection dans sa classe DirectXPage pour remplir une zone de liste avec les noms de famille de polices système. Lorsqu'un élément est sélectionné, un objet IDWriteFontFace est dérivé qui est passé le convertisseur.

La classe SystemFontGlyphsRenderer crée une structure DWRITE_GLYPH_RUN basée sur le texte « Effet de texte vibrant Annoying ». La méthode de mise à jour est alors obligée de définir les valeurs du tableau glyphe décalages des nombres aléatoires entre -3 et 3, ce qui semble comme si tous les caractères de la chaîne de texte indépendamment vibrent.

Il ne semble pas être beaucoup de différence conceptuelle entre IDWriteFont et IDWriteFontFace, sauf que IDWriteFont représente toujours une police qui n'est pas partie d'une collection de polices (par exemple, la collection de polices système) tout en IDWriteFontFace besoin. IDWriteFontCollection a une méthode GetFontFromFontFace accepte un IDWriteFontFace et retourne la IDWriteFont correspondante, mais il ne fonctionne que si le fichier de police associé à la IDWriteFontFace appartient à la collection de polices.

Collections de fontes personnalisées

Maintenant, vous avez vu comment vous pouvez utiliser DrawGlyphRun avec des fichiers de police qui se charge de votre application, ainsi qu'avec les polices système. Est-il possible d'utiliser les méthodes de texte-sortie régulières (DrawText et DrawTextLayout) avec vos propres fichiers de polices ?

Oui, tout à fait. Vous vous souvenez que DrawText et DrawTextLayout exigent tous deux un objet IDWriteTextFormat. Vous créez ce en spécifiant un nom de famille de polices et une collection de polices à l'aide de la méthode de CreateTextFormat de IDWriteFactory.

Normalement, vous définissez cet argument de collection de polices pour le nullptr pour indiquer les polices système. Mais vous pouvez également créer une collection de polices personnalisées en appelant la méthode CreateCustomFontCollection de IDWriteFactory. Vous devrez fournir votre propre classe qui implémente l'interface IDWriteFontCollectionLoader et une autre classe qui implémente IDWriteFontFileEnumerator.

Cela est illustré dans le programme ResourceFontLayout. Le programme comprend également les implémentations des interfaces de centré IDWriteFontFileLoader et IDWriteFontFileStream­GlyphDump. Lorsque vous obtenez la liste des familles de fontes de cette collection de polices personnalisées, vous remarquerez que plusieurs polices fichiers sont parfois regroupées dans une famille de caractères identiques.

Le prix en bas de la boîte

À ce stade, l'importance de IDWriteFontFace devrait être assez évident. Vous pouvez créer un objet de IDWriteFontFace de deux directions : soit directement depuis un fichier de police, soit en choisissant une police particulière dans une collection de polices. Ensuite, vous référencez ce IDWriteFontFace dans une structure DWRITE_GLYPH_RUN, ou utilisez pour obtenir des métriques de glyphe ou pour accéder aux tables dans le fichier de police.

IDWriteFontFace définit également une méthode nommée GetGlyphRun­contour. Les arguments de cette méthode sont très sensiblement les mêmes que les champs de la structure DWRITE_GLYPH_RUN, mais un argument supplémentaire est un IDWriteGeometrySink, qui est identique à un ID2D1SimplifiedGeometrySink.

Cela signifie que vous pouvez convertir une chaîne de texte dans un ID2D1PathGeometry et puis afficher et manipuler celui la géométrie en tant que vous voulez. Figure 6 est une capture d'écran du programme OutlinedCharacters qui montre une géométrie de caractère qui a été rayée et remplie ; la même géométrie restituée avec un style pointillé (ce qui est animé de faire les points de voyage autour des personnages) ; et la géométrie s'est creusé et indique, en effet, décrivant les grandes lignes.

The OutlinedCharacters Program
Figure 6 le programme de OutlinedCharacters

Et je suis juste de commencer.

Charles Petzold est un contributeur de longue date à MSDN Magazine et l'auteur de « Programmation Windows, 6e édition » (o ' Reilly Media, 2012), un livre sur l'écriture d'applications pour Windows 8. Son site Web est charlespetzold.com.

Merci aux experts techniques Microsoft suivants d'avoir relu cet article : Jim Galasyn et Justin Panian