Rendre en utilisant le convertisseur de texte personnalisé
une disposition de texte DirectWrite peut être dessinée par un convertisseur de texte personnalisé dérivé de IDWriteTextRenderer. un convertisseur personnalisé est nécessaire pour tirer parti de certaines fonctionnalités avancées de DirectWrite, telles que le rendu sur une surface bitmap ou GDI, les objets inline et les effets de dessin client. Ce didacticiel décrit les méthodes de IDWriteTextRenderer et fournit un exemple d’implémentation qui utilise Direct2D pour restituer le texte avec un remplissage bitmap.
Ce didacticiel contient les éléments suivants :
- Le constructeur
- DrawGlyphRun ()
- DrawUnderline () et DrawStrikethrough ()
- Accrochage des pixels, pixels par DIP et transformation
- DrawInlineObject()
- Destructeur
- Utilisation du convertisseur de texte personnalisé
Votre convertisseur de texte personnalisé doit implémenter les méthodes héritées de IUnknown en plus des méthodes listées dans la page de référence IDWriteTextRenderer et ci-dessous.
pour obtenir le code source complet du convertisseur de texte personnalisé, consultez les fichiers CustomTextRenderer. cpp et CustomTextRenderer. h de l' exemple DirectWrite Hello World.
Le constructeur
Votre convertisseur de texte personnalisé aura besoin d’un constructeur. Cet exemple utilise à la fois des pinceaux et des pinceaux Direct2D solides et bitmap pour restituer le texte.
Pour cette raison, le constructeur prend les paramètres figurant dans le tableau ci-dessous avec les descriptions.
| Paramètre | Description |
|---|---|
| pD2DFactory | Pointeur vers un objet ID2D1Factory qui sera utilisé pour créer toutes les ressources Direct2D nécessaires. |
| pRT | Pointeur vers l’objet ID2D1HwndRenderTarget dans lequel le texte sera restitué. |
| pOutlineBrush | Pointeur vers le ID2D1SolidColorBrush qui sera utilisé pour dessiner le contour du texte |
| pFillBrush | Pointeur vers le ID2D1BitmapBrush qui sera utilisé pour remplir le texte. |
Celles-ci seront stockées par le constructeur comme indiqué dans le code suivant.
CustomTextRenderer::CustomTextRenderer(
ID2D1Factory* pD2DFactory,
ID2D1HwndRenderTarget* pRT,
ID2D1SolidColorBrush* pOutlineBrush,
ID2D1BitmapBrush* pFillBrush
)
:
cRefCount_(0),
pD2DFactory_(pD2DFactory),
pRT_(pRT),
pOutlineBrush_(pOutlineBrush),
pFillBrush_(pFillBrush)
{
pD2DFactory_->AddRef();
pRT_->AddRef();
pOutlineBrush_->AddRef();
pFillBrush_->AddRef();
}
DrawGlyphRun ()
La méthode DrawGlyphRun est la méthode de rappel principale du convertisseur de texte. Une série de glyphes est passée pour être rendue en plus des informations telles que l’origine de la ligne de base et le mode de mesure. Il passe également un objet d’effet de dessin client à appliquer à l’exécution du glyphe. Pour plus d’informations, consultez la rubrique comment ajouter des effets de dessin client à une disposition de texte .
Cette implémentation de convertisseur de texte affiche les exécutions de glyphe en les convertissant en géométries Direct2D , puis en dessinant et remplissant les géométries. Cela comprend les étapes suivantes.
Créez un objet ID2D1PathGeometry , puis récupérez l’objet ID2D1GeometrySink à l’aide de la méthode ID2D1PathGeometry :: Open .
// Create the path geometry. ID2D1PathGeometry* pPathGeometry = NULL; hr = pD2DFactory_->CreatePathGeometry( &pPathGeometry ); // Write to the path geometry using the geometry sink. ID2D1GeometrySink* pSink = NULL; if (SUCCEEDED(hr)) { hr = pPathGeometry->Open( &pSink ); }L' _ _ exécution de glyphes DWRITE transmise à DrawGlyphRun contient un objet IDWriteFontFace , nommé fontFace, qui représente le type de police pour l’exécution de glyphe entière. Placez le contour du glyphe dans le récepteur Geometry à l’aide de la méthode IDWriteFontFace :: GetGlyphRunOutline , comme indiqué dans le code suivant.
// Get the glyph run outline geometries back from DirectWrite and place them within the // geometry sink. if (SUCCEEDED(hr)) { hr = glyphRun->fontFace->GetGlyphRunOutline( glyphRun->fontEmSize, glyphRun->glyphIndices, glyphRun->glyphAdvances, glyphRun->glyphOffsets, glyphRun->glyphCount, glyphRun->isSideways, glyphRun->bidiLevel%2, pSink ); }Après avoir rempli le récepteur de géométrie, fermez-le.
// Close the geometry sink if (SUCCEEDED(hr)) { hr = pSink->Close(); }L’origine de l’exécution du glyphe doit être traduite afin d’être rendue à partir de l’origine de la ligne de base correcte, comme indiqué dans le code suivant.
// Initialize a matrix to translate the origin of the glyph run. D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY );BaselineOriginX et baselineOriginY sont passés comme paramètres à la méthode de rappel DrawGlyphRun .
Créez la géométrie transformée à l’aide de la méthode ID2D1Factory :: CreateTransformedGeometry et en passant la géométrie du tracé et la matrice de translation.
// Create the transformed geometry ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pPathGeometry, &matrix, &pTransformedGeometry ); }Enfin, dessinez le contour de la géométrie transformée et remplissez-le à l’aide des méthodes ID2D1RenderTarget ::D rawgeometry et ID2D1RenderTarget :: FillGeometry et des pinceaux Direct2D stockés en tant que variables membres.
// Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ );Maintenant que vous avez terminé le dessin, n’oubliez pas de nettoyer les objets qui ont été créés dans cette méthode.
SafeRelease(&pPathGeometry); SafeRelease(&pSink); SafeRelease(&pTransformedGeometry);
DrawUnderline () et DrawStrikethrough ()
IDWriteTextRenderer a également des rappels pour dessiner le trait de soulignement et le barré. Cet exemple dessine un rectangle simple pour un trait de soulignement ou barré, mais d’autres formes peuvent être dessinées.
Le fait de dessiner un soulignement à l’aide de Direct2D comprend les étapes suivantes.
Tout d’abord, créez une structure d2d1 _ rect _ F de la taille et de la forme du soulignement. La structure de _ soulignement DWRITE transmise à la méthode de rappel DrawUnderline fournit le décalage, la largeur et l’épaisseur du soulignement.
D2D1_RECT_F rect = D2D1::RectF( 0, underline->offset, underline->width, underline->offset + underline->thickness );Ensuite, créez un objet ID2D1RectangleGeometry à l’aide de la méthode ID2D1Factory :: CreateRectangleGeometry et de la structure d2d1 _ rect _ F initialisée.
ID2D1RectangleGeometry* pRectangleGeometry = NULL; hr = pD2DFactory_->CreateRectangleGeometry( &rect, &pRectangleGeometry );Comme pour l’exécution de glyphes, l’origine de la géométrie du soulignement doit être traduite en fonction des valeurs d’origine de la ligne de base, à l’aide de la méthode CreateTransformedGeometry .
// Initialize a matrix to translate the origin of the underline D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY ); ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pRectangleGeometry, &matrix, &pTransformedGeometry ); }Enfin, dessinez le contour de la géométrie transformée et remplissez-le à l’aide des méthodes ID2D1RenderTarget ::D rawgeometry et ID2D1RenderTarget :: FillGeometry et des pinceaux Direct2D stockés en tant que variables membres.
// Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ );Maintenant que vous avez terminé le dessin, n’oubliez pas de nettoyer les objets qui ont été créés dans cette méthode.
SafeRelease(&pRectangleGeometry); SafeRelease(&pTransformedGeometry);
Le processus de dessin d’un barré est le même. Toutefois, le barré aura un décalage différent et probablement une largeur et une épaisseur différentes.
Accrochage des pixels, pixels par DIP et transformation
IsPixelSnappingDisabled()
Cette méthode est appelée pour déterminer si l’alignement des pixels est désactivé. La valeur par défaut recommandée est false, ce qui correspond à la sortie de cet exemple.
*isDisabled = FALSE;
GetCurrentTransform()
Cet exemple effectue un rendu sur une cible de rendu Direct2D. par conséquent, transférez la transformation à partir de la cible de rendu à l’aide de ID2D1RenderTarget :: GetTransform.
//forward the render target's transform
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
GetPixelsPerDip()
Cette méthode est appelée pour récupérer le nombre de pixels par DIP (Device Independent Pixel).
float x, yUnused;
pRT_->GetDpi(&x, &yUnused);
*pixelsPerDip = x / 96;
DrawInlineObject()
Un convertisseur de texte personnalisé a également un rappel pour dessiner des objets insérés. Dans cet exemple, DrawInlineObject retourne E _ NOTIMPL. Ce didacticiel présente en outre une explication sur la façon de dessiner des objets en ligne. Pour plus d’informations, consultez la rubrique comment ajouter des objets Inline à une disposition de texte .
Destructeur
Il est important de libérer tous les pointeurs utilisés par la classe de convertisseur de texte personnalisée.
CustomTextRenderer::~CustomTextRenderer()
{
SafeRelease(&pD2DFactory_);
SafeRelease(&pRT_);
SafeRelease(&pOutlineBrush_);
SafeRelease(&pFillBrush_);
}
Utilisation du convertisseur de texte personnalisé
Vous le rendez avec le convertisseur personnalisé à l’aide de la méthode IDWriteTextLayout ::D RAW , qui prend une interface de rappel dérivée de IDWriteTextRenderer comme argument, comme indiqué dans le code suivant.
// Draw the text layout using DirectWrite and the CustomTextRenderer class.
hr = pTextLayout_->Draw(
NULL,
pTextRenderer_, // Custom text renderer.
origin.x,
origin.y
);
La méthode IDWriteTextLayout ::D RAW appelle les méthodes du rappel de convertisseur personnalisé que vous fournissez. Les méthodes DrawGlyphRun, DrawUnderline, DrawInlineObjectet DrawStrikethrough décrites ci-dessus effectuent les fonctions de dessin.