Rendu de texte avec Direct2D et DirectWrite

Contrairement à d’autres API, telles que GDI, GDI+ ou WPF, Direct2D interagit avec une autre API, DirectWrite, pour manipuler et restituer du texte. Cette rubrique décrit les avantages et l’interopérabilité de ces composants distincts.

Cette rubrique contient les sections suivantes.

Direct2D permet l’adoption incrémentielle

Le déplacement d’une application d’une API graphique à une autre peut être difficile ou non ce que vous souhaitez pour différentes raisons. Cela peut être dû au fait que vous devez prendre en charge des plug-ins qui prennent toujours les anciennes interfaces, parce que l’application elle-même est trop grande pour être redirigée vers une nouvelle API dans une version ou parce qu’une partie de l’API plus récente est souhaitable, mais que l’ancienne API fonctionne suffisamment bien pour d’autres parties de l’application.

Étant donné que Direct2D et DirectWrite sont implémentés en tant que composants distincts, vous pouvez mettre à niveau l’ensemble de votre système graphique 2D ou simplement la partie texte de celui-ci. Par exemple, vous pouvez mettre à jour une application pour utiliser DirectWrite pour le texte, mais toujours utiliser GDI ou GDI+ pour le rendu.

Services de texte et rendu de texte

À mesure que les applications ont évolué, leurs exigences en matière de traitement de texte sont de plus en plus complexes. Au début, le texte était généralement limité à l’interface utilisateur statique, et le texte était rendu dans une zone bien définie, comme un bouton. Comme les applications ont commencé à être disponibles dans un nombre croissant de langues, cette approche est devenue plus difficile à maintenir, car la largeur et la hauteur du texte traduit peuvent varier considérablement d’une langue à l’autre. Pour s’adapter, les applications ont commencé à disposer dynamiquement leur interface utilisateur pour dépendre de la taille réelle rendue du texte, au lieu de l’inverse.

Pour aider les applications à effectuer cette tâche, DirectWrite fournit l’interface IDWriteTextLayout. Cette API permet à une application de spécifier un morceau de texte avec des caractéristiques complexes telles que différentes polices et tailles de police, soulignements, contours, texte bidirectionnel, effets, points de suspension et même caractères non-glyphes incorporés (par exemple, un émoticône bitmap ou une icône). L’application peut ensuite modifier différentes caractéristiques du texte à mesure qu’elle détermine de manière itérative sa disposition d’interface utilisateur. L’exemple DirectWrite Hello World, qui est illustré dans l’illustration suivante et dans le tutoriel : Prise en main avec DirectWrite rubrique, montre un grand nombre de ces effets.

capture d’écran de l’exemple « hello world ».

La disposition peut soit positionner les glyphes idéalement en fonction de leurs largeurs (comme le fait WPF), soit aligner les glyphes sur les positions de pixels les plus proches (comme le fait GDI ).

En plus d’obtenir des mesures de texte, l’application peut tester différentes parties du texte. Par exemple, il peut être nécessaire de savoir qu’un lien hypertexte dans le texte est cliqué. (Pour plus d’informations sur le test d’accès, consultez la rubrique Comment effectuer un test d’accès sur une disposition de texte .)

L’interface de disposition de texte est découplée de l’API de rendu utilisée par l’application, comme le montre le diagramme suivant :

diagramme d’API de disposition de texte et graphiques.

Cette séparation est possible, car DirectWrite fournit une interface de rendu (IDWriteTextRenderer) que les applications peuvent implémenter pour restituer du texte à l’aide de l’API graphique de votre choix. La méthode de rappel IDWriteTextRenderer::D rawGlyphRun implémentée par l’application est appelée par DirectWrite lors du rendu d’une disposition de texte. Il incombe à cette méthode d’effectuer les opérations de dessin ou de les transmettre.

Pour dessiner des glyphes, Direct2D fournit ID2D1RenderTarget::D rawGlyphRun pour le dessin sur une surface Direct2D et DirectWrite fournit IDWriteBitmapRenderTarget::D rawGlyphRun pour le dessin sur une surface GDI qui peut ensuite être transféré vers une fenêtre à l’aide de GDI. Facilement, DrawGlyphRun dans Direct2D et DirectWrite ont des paramètres exactement compatibles avec la méthode DrawGlyphRun que l’application implémente sur IDWriteTextRenderer.

Après une séparation similaire, les fonctionnalités propres au texte (telles que l’énumération et la gestion des polices, l’analyse des glyphes, etc.) sont gérées par DirectWrite au lieu de Direct2D. Les objets DirectWrite sont acceptés directement par Direct2D. Pour aider les applications GDI existantes à tirer parti de DirectWrite, il fournit l’interface de méthode IDWriteGdiInterop avec les méthodes permettant d’effectuer les opérations suivantes :

Glyphes et texte

Le texte est un ensemble de points de code Unicode (caractères), avec différents modificateurs stylistiques (polices, poids, soulignements, barrés, etc.) disposés dans un rectangle. Un glyphe, en revanche, est un index particulier dans un fichier de police particulier. Un glyphe définit un ensemble de courbes qui peuvent être rendues, mais il n’a pas de signification textuelle. Il existe potentiellement un mappage plusieurs-à-plusieurs entre les glyphes et les caractères. Une séquence de glyphes qui proviennent du même visage de police et qui sont disposés séquentiellement sur une base de référence est appelée GlyphRun. Les deux DirectWrite et Direct2D appellent leur API de rendu de glyphe la plus précise DrawGlyphRun et ils ont des signatures très similaires. Les éléments suivants proviennent d’ID2D1RenderTarget dans Direct2D :

STDMETHOD_(void, DrawGlyphRun)(
        D2D1_POINT_2F baselineOrigin,
        __in CONST DWRITE_GLYPH_RUN *glyphRun,
        __in ID2D1Brush *foregroundBrush,
        DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL 
        ) PURE;

Et cette méthode provient d’IDWriteBitmapRenderTarget dans DirectWrite :

STDMETHOD(DrawGlyphRun)(
        FLOAT baselineOriginX,
        FLOAT baselineOriginY,
        DWRITE_MEASURING_MODE measuringMode,
        __in DWRITE_GLYPH_RUN const* glyphRun,
        IDWriteRenderingParams* renderingParams,
        COLORREF textColor,
        __out_opt RECT* blackBoxRect = NULL
        ) PURE;

La version DirectWrite conserve l’origine de base, le mode de mesure et les paramètres d’exécution du glyphe et inclut des paramètres supplémentaires.

DirectWrite vous permet également d’utiliser un convertisseur personnalisé pour les glyphes en implémentant l’interface IDWriteTextRenderer. Cette interface a également une méthode DrawGlyphRun , comme le montre l’exemple de code suivant.

STDMETHOD(DrawGlyphRun)(
        __maybenull void* clientDrawingContext,
        FLOAT baselineOriginX,
        FLOAT baselineOriginY,
        DWRITE_MEASURING_MODE measuringMode,
        __in DWRITE_GLYPH_RUN const* glyphRun,
        __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
        __maybenull IUnknown* clientDrawingEffect
        ) PURE;

Cette version inclut d’autres paramètres utiles lorsque vous implémentez un convertisseur de texte personnalisé. Le paramètre final est utilisé pour les effets de dessin personnalisés implémentés par l’application. (Pour plus d’informations sur les effets de dessin client , consultez Comment ajouter des effets de dessin client à une disposition de texte.

Chaque exécution de glyphe commence à une origine et est placée sur une ligne à partir de cette origine. Les glyphes sont modifiés par la transformation du monde actuelle et les paramètres de rendu de texte sélectionnés sur la cible de rendu associée. Cette API est généralement appelée directement par les applications qui font leur propre disposition (par exemple, un processeur Word) ou par une application qui a implémenté l’interface IDWriteTextRenderer.

DirectWrite et Direct2D

Direct2D fournit des services de rendu au niveau du glyphe via DrawGlyphRun. Toutefois, cela nécessite que l’application implémente les détails du rendu, ce qui reproduit les fonctionnalités de l’API DrawText à partir de GDI seule.

Par conséquent, Direct2D fournit des API qui acceptent du texte au lieu des glyphes : ID2D1RenderTarget::D rawTextLayout et ID2D1RenderTarget::D rawText. Les deux méthodes s’affichent sur une surface Direct2D. Pour effectuer un rendu sur une surface GDI, IDWriteBitmapRenderTarget::D rawGlyphRun est fourni. Toutefois, cette méthode nécessite l’implémentation d’un convertisseur de texte personnalisé par l’application. (Pour plus d’informations, consultez la rubrique Rendu sur une Surface GDI .)

L’utilisation du texte par une application commence généralement simplement : placez OK ou Annuler sur un bouton de disposition fixe, par exemple. Toutefois, au fil du temps, elle devient plus complexe à mesure que l’internationalisation et d’autres fonctionnalités sont ajoutées. À terme, de nombreuses applications devront utiliser les objets de disposition de texte de DirectWrite et implémenter le convertisseur de texte.

Par conséquent, Direct2D fournit des API en couches qui permettent à une application de démarrer simplement et de devenir plus sophistiquée sans avoir à effectuer un back-track ou à abandonner son code de travail. Un affichage simplifié est illustré dans le diagramme suivant :

diagramme d’application directwrite et direct2d.

DrawText

DrawText est la plus simple des API à utiliser. Il prend une chaîne Unicode, un pinceau de premier plan, un objet de format unique et un rectangle de destination. Il permet d’afficher et d’afficher la chaîne entière dans le rectangle de disposition, et éventuellement de la couper. Cela est utile lorsque vous placez un simple morceau de texte dans une partie de l’interface utilisateur à disposition fixe.

DrawTextLayout

En créant un objet IDWriteTextLayout , une application peut commencer à mesurer et à organiser le texte et d’autres éléments d’interface utilisateur, et prendre en charge plusieurs polices, styles, soulignements et barrés. Direct2D fournit l’API DrawTextLayout qui accepte directement cet objet et affiche le texte à un point donné. (La largeur et la hauteur sont fournies par l’objet layout). En plus d’implémenter toutes les fonctionnalités de disposition de texte attendues, Direct2D interprète n’importe quel objet d’effet comme un pinceau et applique ce pinceau à la plage de glyphes sélectionnée. Il appelle également tous les objets inline. Une application peut ensuite insérer des caractères autres que des glyphes (icônes) dans le texte si elle le souhaite. Un autre avantage de l’utilisation d’un objet de disposition de texte est que les positions de glyphe sont mises en cache dans celui-ci. Par conséquent, un gain de performances important est possible en réutilisant le même objet de disposition pour plusieurs appels de dessin et en évitant de recalculer les positions de glyphe pour chaque appel. Cette fonctionnalité n’est pas présente pour le DrawText de GDI.

DrawGlyphRun

Enfin, l’application peut implémenter l’interface IDWriteTextRenderer elle-même et appeler DrawGlyphRun et FillRectangle eux-mêmes, ou toute autre API de rendu. Toute l’interaction existante avec l’objet Disposition de texte reste inchangée.

Pour obtenir un exemple d’implémentation d’un convertisseur de texte personnalisé, consultez la rubrique Rendu à l’aide d’un convertisseur de texte personnalisé .

Rendu du glyphe

L’ajout de DirectWrite à une application GDI existante permet à l’application d’utiliser l’API IDWriteBitmapRenderTarget pour afficher des glyphes. La méthode IDWriteBitmapRenderTarget::D rawGlyphRun que DirectWrite fournit s’affiche en couleur unie dans un contrôleur de domaine mémoire sans nécessiter d’API supplémentaires, telles que Direct2D.

Cela permet à l’application d’obtenir des fonctionnalités de rendu de texte avancées telles que les suivantes :

  • Sous-pixel ClearType permet à une application de placer des glyphes sur des positions de sous-pixels pour permettre à la fois un rendu de glyphe net et une disposition de glyphe.
  • L’anti-aaliasing de direction Y permet un rendu plus lisse des courbes sur les glyphes plus grands.

Une application qui passe à Direct2D obtient également les fonctionnalités suivantes :

  • Accélération matérielle.
  • Possibilité de remplir le texte avec un pinceau Direct2D arbitraire, comme des dégradés radiales, des dégradés linéaires et des bitmaps.
  • Prise en charge supplémentaire de la superposition et du découpage via les API PushAxisAlignedClip, PushLayer et CreateCompatibleRenderTarget .
  • Possibilité de prendre en charge le rendu de texte en nuances de gris. Cela remplit correctement le canal alpha de destination en fonction de l’opacité du pinceau du texte et de l’anti-aaliasing du texte.

Pour prendre en charge efficacement l’accélération matérielle, Direct2D utilise une approximation légèrement différente de la correction gamma appelée correction alpha. Cela ne nécessite pas que Direct2D inspecte le pixel de couleur cible de rendu lors du rendu du texte.

Conclusion

Cette rubrique explique les différences et les similitudes entre Direct2D et DirectWrite, ainsi que les motivations architecturales pour les fournir en tant qu’API coopératives distinctes.