DirectWriteテキスト レイアウトは、IDWriteTextRenderer から派生したカスタム テキスト レンダラーによって描画できます。 ビットマップまたは GDI サーフェスへのレンダリング、インライン オブジェクト、クライアント描画効果など、DirectWriteの高度な機能を利用するには、カスタム レンダラーが必要です。 このチュートリアルでは、 IDWriteTextRenderer のメソッドについて説明し、 Direct2D を使用してビットマップ塗りつぶしでテキストをレンダリングする実装例を示します。
このチュートリアルには、次の部分が含まれています。
- コンストラクター
- DrawGlyphRun()
- DrawUnderline() と DrawStrikethrough()
- ピクセル スナップ、DIP あたりのピクセル数、および変換
- DrawInlineObject()
- デストラクター
- カスタム テキスト レンダラーの使用
カスタム テキスト レンダラーでは、 IDWriteTextRenderer リファレンス ページおよび以下に記載されているメソッドに加えて、IUnknown から継承されたメソッドを実装する必要があります。
カスタム テキスト レンダラーの完全なソース コードについては、DirectWrite Hello World サンプルの CustomTextRenderer.cpp ファイルと CustomTextRenderer.h ファイルを参照してください。
コンストラクター
カスタム テキスト レンダラーにはコンストラクターが必要です。 この例では、ソリッド ブラシとビットマップ Direct2D ブラシの両方を使用してテキストをレンダリングします。
このため、コンストラクターは次の表にあるパラメーターと説明を受け取ります。
| パラメーター | 説明 |
|---|---|
| pD2DFactory | 必要な Direct2D リソースを作成するために使用される ID2D1Factory オブジェクトへのポインター。 |
| Prt | テキストがレンダリングされる ID2D1HwndRenderTarget オブジェクトへのポインター。 |
| pOutlineBrush | テキストのアウトラインを描画するために使用する ID2D1SolidColorBrush へのポインター |
| pFillBrush | テキストの入力に使用される ID2D1BitmapBrush へのポインター。 |
これらは、次のコードに示すようにコンストラクターによって格納されます。
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()
DrawGlyphRun メソッドは、テキスト レンダラーのメインコールバック メソッドです。 ベースラインの原点や測定モードなどの情報に加えて、レンダリングされるグリフの実行が渡されます。 また、グリフ実行に適用するクライアント描画効果オブジェクトも渡します。 詳細については、「 テキスト レイアウトにクライアント描画効果を追加する方法 」トピックを参照してください。
このテキスト レンダラーの実装では、グリフの実行を Direct2D ジオメトリに変換し、ジオメトリを描画して塗りつぶすことでレンダリングします。 これは、次の手順で構成されます。
ID2D1PathGeometry オブジェクトを作成し、ID2D1PathGeometry::Open メソッドを使用して ID2D1GeometrySink オブジェクトを取得します。
// 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 ); }DrawGlyphRun に渡されるDWRITE_GLYPH_RUNには、グリフ実行全体のフォント面を表す fontFace という名前の IDWriteFontFace オブジェクトが含まれています。 次のコードに示すように、 IDWriteFontFace:: GetGlyphRunOutline メソッドを使用して、グリフランのアウトラインを geometry シンクに配置します。
// 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 ); }ジオメトリ シンクを埋めてから閉じます。
// Close the geometry sink if (SUCCEEDED(hr)) { hr = pSink->Close(); }グリフ実行の原点は、次のコードに示すように、正しいベースラインの原点からレンダリングされるように変換する必要があります。
// 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 と baselineOriginY は、DrawGlyphRun コールバック メソッドにパラメーターとして渡されます。
ID2D1Factory::CreateTransformedGeometry メソッドを使用し、パス ジオメトリと変換行列を渡して、変換されたジオメトリを作成します。
// Create the transformed geometry ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pPathGeometry, &matrix, &pTransformedGeometry ); }最後に、変換されたジオメトリのアウトラインを描画し、 ID2D1RenderTarget::D rawGeometry メソッドと ID2D1RenderTarget::FillGeometry メソッドと、メンバー変数として格納されている Direct2D ブラシを使用して塗りつぶします。
// Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ );描画が完了したら、このメソッドで作成されたオブジェクトをクリーンすることを忘れないでください。
SafeRelease(&pPathGeometry); SafeRelease(&pSink); SafeRelease(&pTransformedGeometry);
DrawUnderline() と DrawStrikethrough()
IDWriteTextRenderer には、下線と取り消し線を描画するためのコールバックもあります。 次の使用例は、下線または取り消し線の単純な四角形を描画しますが、他の図形を描画できます。
Direct2D を使用して下線を描画するには、次の手順を実行します。
まず、下線のサイズと形状の D2D1_RECT_F 構造を作成します。 DrawUnderline コールバック メソッドに渡されるDWRITE_UNDERLINE構造体は、下線のオフセット、幅、および太さを提供します。
D2D1_RECT_F rect = D2D1::RectF( 0, underline->offset, underline->width, underline->offset + underline->thickness );次に、ID2D1Factory::CreateRectangleGeometry メソッドと初期化されたD2D1_RECT_F構造体を使用して、ID2D1RectangleGeometry オブジェクトを作成します。
ID2D1RectangleGeometry* pRectangleGeometry = NULL; hr = pD2DFactory_->CreateRectangleGeometry( &rect, &pRectangleGeometry );グリフの実行と同様に、 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 ); }最後に、変換されたジオメトリのアウトラインを描画し、 ID2D1RenderTarget::D rawGeometry メソッドと ID2D1RenderTarget::FillGeometry メソッドと、メンバー変数として格納されている Direct2D ブラシを使用して塗りつぶします。
// Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ );描画が完了したら、このメソッドで作成されたオブジェクトをクリーンすることを忘れないでください。
SafeRelease(&pRectangleGeometry); SafeRelease(&pTransformedGeometry);
取り消し線を描画するプロセスは同じです。 ただし、取り消し線のオフセットは異なり、幅と太さが異なる可能性があります。
ピクセル スナップ、DIP あたりのピクセル数、および変換
IsPixelSnappingDisabled()
このメソッドは、ピクセル スナップが無効かどうかを判断するために呼び出されます。 推奨される既定値は FALSE で、この例の出力です。
*isDisabled = FALSE;
GetCurrentTransform()
この例では Direct2D レンダー ターゲットにレンダリングするため、 ID2D1RenderTarget::GetTransform を使用してレンダー ターゲットから変換を転送します。
//forward the render target's transform
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
GetPixelsPerDip()
このメソッドは、デバイスに依存しないピクセル (DIP) あたりのピクセル数を取得するために呼び出されます。
float x, yUnused;
pRT_->GetDpi(&x, &yUnused);
*pixelsPerDip = x / 96;
DrawInlineObject()
カスタム テキスト レンダラーには、インライン オブジェクトを描画するためのコールバックもあります。 この例では、 DrawInlineObject は E_NOTIMPLを返します。 インライン オブジェクトを描画する方法の説明は、このチュートリアルの範囲外です。 詳細については、「 テキスト レイアウトにインライン オブジェクトを追加する方法 」トピックを参照してください。
デストラクター
カスタム テキスト レンダラー クラスで使用されていたポインターを解放することが重要です。
CustomTextRenderer::~CustomTextRenderer()
{
SafeRelease(&pD2DFactory_);
SafeRelease(&pRT_);
SafeRelease(&pOutlineBrush_);
SafeRelease(&pFillBrush_);
}
カスタム テキスト レンダラーの使用
次のコードに示すように 、IDWriteTextLayout::D raw メソッドを使用してカスタム レンダラーを使用してレンダリングします。このメソッドは、 IDWriteTextRenderer から派生したコールバック インターフェイスを引数として受け取ります。
// Draw the text layout using DirectWrite and the CustomTextRenderer class.
hr = pTextLayout_->Draw(
NULL,
pTextRenderer_, // Custom text renderer.
origin.x,
origin.y
);
IDWriteTextLayout::D raw メソッドは、指定したカスタム レンダラー コールバックのメソッドを呼び出します。 上で説明した DrawGlyphRun、DrawUnderline、DrawInlineObject、DrawStrikethrough の各メソッドは、描画関数を実行します。