c++directwrite

RTL text width in DirectWrite


I use IDWriteTextAnalysisSink / AnalyzeScript to display mixed LTR (English) and RTL (Hebrew) text in DirectWrite (C++), and I compute text width from:

textwidth = 0;
for (UINT glyph=0; glyph<actualGlyphCount; glyph++) 
  textwidth += glyphAdvances[glyph];

with glyphAdvances returned from GetGlyphPlacements.

However for Right To Left text, this is often inaccurate, leading to overlapping text, etc. Is this the right method?

Thanks.


Solution

  • You may not need to do quite so much work with IDWriteTextAnalysisSink / AnalyzeScript.

        HRESULT hr = S_OK;
        ComPtr<IDWriteTextFormat> textFormat;
        ComPtr<IDWriteTextLayout> textLayout;
    
        // Error checking omitted for brevity
        hr = textFactory->CreateTextFormat(L"Arial", nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 30.0f, L"", textFormat.GetAddressOf());
        hr = textFormat->SetReadingDirection(DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
        hr = textFactory->CreateTextLayout(L"[HEBREW TEXT HERE]", textsize, textFormat.Get(), 0.0f, 0.0f, textLayout.GetAddressOf());
    

    Render Code:

        renderTarget->Clear(BG_COLOR);
        auto size = renderTarget->GetSize();
    
        auto margin = 50.0f;
        size.width -= margin * 2.0f;
        size.height -= margin * 2.0f;
    
        if (S_OK == textLayout->SetMaxWidth(size.width) &&
            S_OK == textLayout->SetMaxHeight(size.height))
        {
            renderTarget->DrawTextLayout(Point2F(margin, margin), textLayout.Get(), brush.Get(), D2D1_DRAW_TEXT_OPTIONS_NONE);
        }
    

    Screenshot from reading hebrew file: enter image description here

    (Note: My solution is based on a sample from Kenny Kerr) I realize you are mixing LTR and RTL, however I am not sure that warrants the added complexity of IDWriteTextAnalysisSink / AnalyzeScript.