Search code examples
c++comdirectxdirect2ddirectwrite

Calls To ID2D1RenderTarget::DrawTextLayout() Not Working


Basically, given the following test code:

CComPtr<IDWriteTextLayout> layout;
wstring text2 = L"Here is some text.";
this->currentLevelText->Formatting->TextFactory->CreateTextLayout(text2.c_str(), text2.length(), this->matrixHeaderTextInfo->TextFormat, FLT_MAX, FLT_MAX, &layout);
target->DrawTextLayout(D2D1::Point2F(30, 30), layout, this->textBrush);

The target->DrawTextLayout method is not drawing anything. However, the following call to DrawTextW does work:

target->DrawTextW(this->currentLevelText->Text.c_str(), this->currentLevelText->Text.length(), 
    this->currentLevelText->Formatting->TextFormat, this->currentLevelText->ActualRectangle.DrawingRectangle,
    this->textBrush);

Here is a summary of what I know:

  • TextFactory is a pointer to an IDWriteFactory object, TextFormat is an IDWriteTextFormat object, and target is a valid ID2D1HwndRenderTarget.
  • TextFormat is a valid IDWriteTextFormat object, as I can draw text with it properly via the DrawTextW method.
  • The call to CreateTextLayout does not return an error code, it returns the S_OK success code.
  • TextFormat and the text layout object were both created using the same DirectWrite factory, which is also the only DirectWrite factory existing in my application.
  • The ID2D1SolidColorBrush textBrush is a valid brush with opacity 1.0 and set to the color black. I know this is not the problem because DrawTextW is using this brush to successfully draw to the window.
  • Calling the GetMetrics method of the ID2D1TextLayout object returns valid metrics; in other words, the width and height of the text stored in the object is not 0 or negative.
  • The call to ID2D1RenderTarget::EndDraw() does not return an error code, it returns the S_OK success code.
  • Most baffling of all, in another section of my code (which happens to be in another dll file), the calls to DrawTextLayout do work. Even though this code is in a dll file, it is using the same DirectWrite Factory. I really wouldn't think being in another dll file should make a difference.

Both code samples I provided execute one after the other, and should both draw text successfully. However, only DrawTextW is drawing text. I am not doing anything complex with drawing, such as using Direct 2D Effects. The code is not any more complicated than the samples I've provided. For now I can just use the DrawTextW method, but I'd prefer not to, as I read somewhere that simply creates an IDWriteTextLayout object, draws it, and then destroys the object. That is a lot of unnecessary work that can be alleviated by using a text layout object myself.

Does anyone have any idea why this might be happening? I am completely out of ideas of why this is happening, though I'll keep trying to find a connection somewhere.


Solution

  • I believe I've found the fix. The TextFormat object was created with a Paragraph Alignment of DWRITE_PARAGRAPH_ALIGNMENT_CENTER, text alignment of DWRITE_TEXT_ALIGNMENT_CENTER, and the layout has a bounding box size of FLT_MAX (simulate no boundaries so the text will never be forced to wrap).

    I did not realize this, but DWRITE_PARAGRAPH_ALIGNMENT refers to the vertical alignment of the text. DWRITE_PARAGRAPH_ALIGNMENT_NEAR means align to top, DWRITE_PARAGRAPH_ALIGNMENT_FAR means align to bottom, and DWRITE_PARAGRAPH_ALIGNMENT_CENTER means vertical align center.

    Since the layout container was FLT_MAX * FLT_MAX, the text is not going to be visible anywhere on the screen, no matter what origin position I specify, because it will always about FLT_MAX / 2 pixels away in both the x and y directions.

    Changing the paragraph alignment of the text format from DWRITE_PARAGRAPH_ALIGNMENT_CENTER to DWRITE_PARAGRAPH_ALIGNMENT_NEAR was the first step to fixing the problem. However, I noticed the text still was not showing up. I realized that DWRITE_TEXT_ALIGNMENT_CENTER was not going to work with FLT_MAX width either, for the same reason that the paragraph alignment was not working as I was expecting. Centering the text when there is FLT_MAX width to draw in will, again, put the text way off the screen to the right.

    So, even though using FLT_MAX has not given me issues up until now (I must not have had need to use centering alignments up until now), giving specific sizing constraints for the layout and using "Near" paragraph alignment is what solved my problem.