Delen via


Renderen met een aangepaste tekstweergave

Een DirectWritetekstindeling kan worden getekend door een aangepaste tekstweergave die is afgeleid van IDWriteTextRenderer-. Een aangepaste renderer is vereist om te profiteren van enkele geavanceerde functies van DirectWrite, zoals het weergeven naar een bitmap- of GDI-oppervlak, inlineobjecten en clienttekeningseffecten. In deze zelfstudie worden de methoden van IDWriteTextRendererbeschreven en wordt een voorbeeld van een implementatie gegeven die gebruikmaakt van Direct2D- om tekst weer te geven met een bitmapvulling.

Deze zelfstudie bevat de volgende onderdelen:

Uw aangepaste tekstweergave moet de methoden implementeren die zijn overgenomen van IUnknown, naast de methoden die worden vermeld op de IDWriteTextRenderer referentiepagina en hieronder.

Zie de bestanden CustomTextRenderer.cpp en CustomTextRenderer.h van de DirectWrite Hello World Samplevoor de volledige broncode voor de aangepaste tekstweergave.

De constructor

Uw aangepaste tekstweergave heeft een constructor nodig. In dit voorbeeld worden zowel effen als bitmap Direct2D borstels gebruikt om de tekst weer te geven.

Daarom gebruikt de constructor de parameters in de onderstaande tabel met beschrijvingen.

Parameter Beschrijving
pD2DFactory Een aanwijzer naar een ID2D1Factory--object dat wordt gebruikt om direct2D-resources te maken die nodig zijn.
pRT Een aanwijzer naar het ID2D1HwndRenderTarget object waarnaar de tekst wordt weergegeven.
pOutlineBrush Een aanwijzer naar de ID2D1SolidColorBrush die wordt gebruikt om een overzicht van de tekst te tekenen
pFillBrush Een aanwijzer naar de ID2D1BitmapBrush die wordt gebruikt om de tekst te vullen.

 

Deze worden opgeslagen door de constructor, zoals wordt weergegeven in de volgende code.

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()

De methode DrawGlyphRun is de belangrijkste callback-methode van de tekstweergave. Er wordt een reeks van glyphs doorgegeven voor weergave, samen met informatie zoals de oorsprong van de basislijn en de meetmodus. Er wordt ook een clienttekeningeffectobject doorgegeven dat moet worden toegepast op de glyph-run. Voor meer informatie, zie het Hoe je Clienttekeningeffecten kunt toevoegen aan een tekstindeling onderwerp.

Deze implementatie van de tekstweergave geeft glyph-uitvoeringen weer door ze te converteren naar Direct2D geometrieën en vervolgens de geometrieën te tekenen en te vullen. Dit bestaat uit de volgende stappen.

  1. Maak een ID2D1PathGeometry-object en haal vervolgens de ID2D1GeometrySink object op met behulp van de methode ID2D1PathGeometry::Open methode.

    // 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
            );
    }
    
  2. De DWRITE_GLYPH_RUN die wordt doorgegeven aan DrawGlyphRun bevat een IDWriteFontFace-object, met de naam fontFace, dat het lettertypegezicht voor de hele uitvoering aangeeft. Plaats de contouren van het glyph-run in de geometriesink met de methode IDWriteFontFace::GetGlyphRunOutline, zoals weergegeven in de volgende code.

    // 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
            );
    }
    
  3. Nadat u de geometriesink hebt gevuld, sluit u deze.

    // Close the geometry sink
    if (SUCCEEDED(hr))
    {
        hr = pSink->Close();
    }
    
  4. De oorsprong van de glyph-uitvoering moet worden vertaald, zodat deze wordt weergegeven vanaf de juiste basislijnoorsprong, zoals wordt weergegeven in de volgende code.

    // 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
        );
    

    De baselineOriginX- en baselineOriginY- worden als parameters doorgegeven aan de methode DrawGlyphRun callback.

  5. Maak de getransformeerde geometrie met behulp van de ID2D1Factory::CreateTransformedGeometry methode en geef de padgeometrie en de vertaalmatrix door.

    // Create the transformed geometry
    ID2D1TransformedGeometry* pTransformedGeometry = NULL;
    if (SUCCEEDED(hr))
    {
        hr = pD2DFactory_->CreateTransformedGeometry(
            pPathGeometry,
            &matrix,
            &pTransformedGeometry
            );
    }
    
  6. Teken ten slotte de omtrek van de getransformeerde geometrie en vul deze met behulp van de methoden ID2D1RenderTarget::DrawGeometry en ID2D1RenderTarget::FillGeometry en de Direct2D penselen die als lidvariabelen zijn opgeslagen.

        // Draw the outline of the glyph run
        pRT_->DrawGeometry(
            pTransformedGeometry,
            pOutlineBrush_
            );
    
        // Fill in the glyph run
        pRT_->FillGeometry(
            pTransformedGeometry,
            pFillBrush_
            );
    
  7. Nu u klaar bent met tekenen, vergeet dan niet om de objecten op te schonen die in deze methode zijn gemaakt.

    SafeRelease(&pPathGeometry);
    SafeRelease(&pSink);
    SafeRelease(&pTransformedGeometry);
    

DrawUnderline() en DrawStrikethrough()

IDWriteTextRenderer heeft ook callbacks voor het tekenen van de onderstreping en doorhalen. In dit voorbeeld wordt een eenvoudige rechthoek getekend voor een onderstreping of doorhalen, maar er kunnen ook andere vormen worden getekend.

Een onderstreping tekenen met behulp van Direct2D- bestaat uit de volgende stappen.

  1. Maak eerst een D2D1_RECT_F structuur van de grootte en vorm van de onderstreping. De DWRITE_UNDERLINE structuur die wordt doorgegeven aan de DrawUnderline callback-methode biedt de offset, breedte en dikte van de onderstreping.

    D2D1_RECT_F rect = D2D1::RectF(
        0,
        underline->offset,
        underline->width,
        underline->offset + underline->thickness
        );
    
  2. Maak vervolgens een ID2D1RectangleGeometry object met behulp van de ID2D1Factory::CreateRectangleGeometry methode en de geïnitialiseerde D2D1_RECT_F structuur.

    ID2D1RectangleGeometry* pRectangleGeometry = NULL;
    hr = pD2DFactory_->CreateRectangleGeometry(
            &rect, 
            &pRectangleGeometry
            );
    
  3. Net als bij de uitvoering van de glyph moet de oorsprong van de onderstrepingsgeometrie worden vertaald, op basis van de basislijnwaarden, met behulp van de methode 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
            );
    }
    
  4. Teken ten slotte het overzicht van de getransformeerde geometrie, en vul deze door gebruik te maken van de methoden ID2D1RenderTarget::DrawGeometry en ID2D1RenderTarget::FillGeometry, evenals de Direct2D penselen die zijn opgeslagen als lidvariabelen.

        // Draw the outline of the glyph run
        pRT_->DrawGeometry(
            pTransformedGeometry,
            pOutlineBrush_
            );
    
        // Fill in the glyph run
        pRT_->FillGeometry(
            pTransformedGeometry,
            pFillBrush_
            );
    
  5. Nu u klaar bent met tekenen, vergeet dan niet om de objecten op te schonen die in deze methode zijn gemaakt.

    SafeRelease(&pRectangleGeometry);
    SafeRelease(&pTransformedGeometry);
    

Het proces voor het tekenen van een doorhalen is hetzelfde. Het doorhalingseffect zal echter een andere verschuiving hebben en vermoedelijk een andere breedte en dikte.

Pixel vastmaken, pixels per DIP en transformatie

IsPixelSnappingDisabled()

Deze methode wordt aangeroepen om te bepalen of pixel-snapping is uitgeschakeld. De aanbevolen standaardwaarde is FALSEen dat is de uitvoer van dit voorbeeld.

*isDisabled = FALSE;

GetCurrentTransform()

Dit voorbeeld wordt weergegeven naar een Direct2D-renderdoel, dus stuur de transformatie van het renderdoel door met behulp van ID2D1RenderTarget::GetTransform.

//forward the render target's transform
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));

GetPixelsPerDip()

Deze methode wordt aangeroepen om het aantal pixels per Device Independent Pixel (DIP) op te halen.

float x, yUnused;

pRT_->GetDpi(&x, &yUnused);
*pixelsPerDip = x / 96;

DrawInlineObject()

Een aangepaste tekstweergave heeft ook een callback voor het tekenen van inlineobjecten. In dit voorbeeld retourneert DrawInlineObject E_NOTIMPL. Een uitleg over het tekenen van inlineobjecten valt buiten het bereik van deze zelfstudie. Zie voor meer informatie de Hoe inline-objecten aan een tekstopmaak toe te voegen rubriek.

De Vernietiger

Het is belangrijk om aanwijzers vrij te geven die zijn gebruikt door de aangepaste tekstweergaveklasse.

CustomTextRenderer::~CustomTextRenderer()
{
    SafeRelease(&pD2DFactory_);
    SafeRelease(&pRT_);
    SafeRelease(&pOutlineBrush_);
    SafeRelease(&pFillBrush_);
}

De aangepaste tekstweergave gebruiken

U rendert met behulp van de aangepaste renderer door de IDWriteTextLayout::Draw methode te gebruiken, die een callback-interface afgeleid van IDWriteTextRenderer als argument neemt, zoals weergegeven in de volgende code.

// Draw the text layout using DirectWrite and the CustomTextRenderer class.
hr = pTextLayout_->Draw(
        NULL,
        pTextRenderer_,  // Custom text renderer.
        origin.x,
        origin.y
        );

Met de methode IDWriteTextLayout::Draw worden de methoden aangeroepen van de door u opgegeven aangepaste renderer-callback. De DrawGlyphRun, DrawUnderline, DrawInlineObjecten DrawStrikethrough methoden die hierboven worden beschreven, voeren de tekenfuncties uit.