Gfx: Handle failed creation of D2D text layout

This commit is contained in:
Birunthan Mohanathas 2013-10-15 17:08:40 +03:00
parent 6d243711a6
commit ca41a4575c
3 changed files with 81 additions and 82 deletions

View File

@ -318,69 +318,68 @@ void CanvasD2D::DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& forma
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solidBrush; Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solidBrush;
HRESULT hr = m_Target->CreateSolidColorBrush(ToColorF(color), solidBrush.GetAddressOf()); HRESULT hr = m_Target->CreateSolidColorBrush(ToColorF(color), solidBrush.GetAddressOf());
if (SUCCEEDED(hr)) if (FAILED(hr)) return;
TextFormatD2D& formatD2D = (TextFormatD2D&)format;
if (!formatD2D.CreateLayout(
str, strLen, rect.Width, rect.Height, !m_AccurateText && m_TextAntiAliasing)) return;
D2D1_POINT_2F drawPosition;
drawPosition.x = [&]()
{ {
TextFormatD2D& formatD2D = (TextFormatD2D&)format; if (!m_AccurateText)
formatD2D.CreateLayout(
str, strLen, rect.Width, rect.Height, !m_AccurateText && m_TextAntiAliasing);
D2D1_POINT_2F drawPosition;
drawPosition.x = [&]()
{ {
if (!m_AccurateText) const float xOffset = formatD2D.m_TextFormat->GetFontSize() / 6.0f;
switch (formatD2D.GetHorizontalAlignment())
{ {
const float xOffset = formatD2D.m_TextFormat->GetFontSize() / 6.0f; case HorizontalAlignment::Left: return rect.X + xOffset;
switch (formatD2D.GetHorizontalAlignment()) case HorizontalAlignment::Right: return rect.X - xOffset;
{
case HorizontalAlignment::Left: return rect.X + xOffset;
case HorizontalAlignment::Right: return rect.X - xOffset;
}
}
return rect.X;
} ();
drawPosition.y = [&]()
{
// GDI+ compatibility.
float yPos = rect.Y - formatD2D.m_LineGap;
switch (formatD2D.GetVerticalAlignment())
{
case VerticalAlignment::Bottom: yPos -= formatD2D.m_ExtraHeight; break;
case VerticalAlignment::Center: yPos -= formatD2D.m_ExtraHeight / 2; break;
}
return yPos;
} ();
if (formatD2D.m_Trimming)
{
D2D1_RECT_F clipRect = ToRectF(rect);
if (m_CanUseAxisAlignClip)
{
m_Target->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_ALIASED);
}
else
{
const D2D1_LAYER_PARAMETERS layerParams =
D2D1::LayerParameters(clipRect, nullptr, D2D1_ANTIALIAS_MODE_ALIASED);
m_Target->PushLayer(layerParams, nullptr);
} }
} }
m_Target->DrawTextLayout(drawPosition, formatD2D.m_TextLayout.Get(), solidBrush.Get()); return rect.X;
} ();
if (formatD2D.m_Trimming) drawPosition.y = [&]()
{
// GDI+ compatibility.
float yPos = rect.Y - formatD2D.m_LineGap;
switch (formatD2D.GetVerticalAlignment())
{ {
if (m_CanUseAxisAlignClip) case VerticalAlignment::Bottom: yPos -= formatD2D.m_ExtraHeight; break;
{ case VerticalAlignment::Center: yPos -= formatD2D.m_ExtraHeight / 2; break;
m_Target->PopAxisAlignedClip(); }
}
else return yPos;
{ } ();
m_Target->PopLayer();
} if (formatD2D.m_Trimming)
{
D2D1_RECT_F clipRect = ToRectF(rect);
if (m_CanUseAxisAlignClip)
{
m_Target->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_ALIASED);
}
else
{
const D2D1_LAYER_PARAMETERS layerParams =
D2D1::LayerParameters(clipRect, nullptr, D2D1_ANTIALIAS_MODE_ALIASED);
m_Target->PushLayer(layerParams, nullptr);
}
}
m_Target->DrawTextLayout(drawPosition, formatD2D.m_TextLayout.Get(), solidBrush.Get());
if (formatD2D.m_Trimming)
{
if (m_CanUseAxisAlignClip)
{
m_Target->PopAxisAlignedClip();
}
else
{
m_Target->PopLayer();
} }
} }
} }

View File

@ -43,7 +43,7 @@ void TextFormatD2D::Dispose()
m_LineGap = 0.0f; m_LineGap = 0.0f;
} }
void TextFormatD2D::CreateLayout( bool TextFormatD2D::CreateLayout(
const WCHAR* str, UINT strLen, float maxW, float maxH, bool gdiEmulation) const WCHAR* str, UINT strLen, float maxW, float maxH, bool gdiEmulation)
{ {
bool strChanged = false; bool strChanged = false;
@ -84,38 +84,38 @@ void TextFormatD2D::CreateLayout(
{ {
CanvasD2D::c_DWFactory->CreateTextLayout( CanvasD2D::c_DWFactory->CreateTextLayout(
str, strLen, m_TextFormat.Get(), maxW, maxH, m_TextLayout.ReleaseAndGetAddressOf()); str, strLen, m_TextFormat.Get(), maxW, maxH, m_TextLayout.ReleaseAndGetAddressOf());
if (!m_TextLayout) return false;
if (m_TextLayout) if (gdiEmulation)
{ {
if (gdiEmulation) Microsoft::WRL::ComPtr<IDWriteTextLayout1> textLayout1;
{ m_TextLayout.As(&textLayout1);
Microsoft::WRL::ComPtr<IDWriteTextLayout1> textLayout1;
m_TextLayout.As(&textLayout1);
const float xOffset = m_TextFormat->GetFontSize() / 6.0f; const float xOffset = m_TextFormat->GetFontSize() / 6.0f;
const float emOffset = xOffset / 24.0f; const float emOffset = xOffset / 24.0f;
const DWRITE_TEXT_RANGE range = {0, strLen}; const DWRITE_TEXT_RANGE range = {0, strLen};
textLayout1->SetCharacterSpacing(emOffset, emOffset, 0.0f, range); textLayout1->SetCharacterSpacing(emOffset, emOffset, 0.0f, range);
} }
UINT32 lineCount = 0; UINT32 lineCount = 0;
DWRITE_LINE_METRICS lineMetrics[2]; DWRITE_LINE_METRICS lineMetrics[2];
HRESULT hr = m_TextLayout->GetLineMetrics(lineMetrics, _countof(lineMetrics), &lineCount); HRESULT hr = m_TextLayout->GetLineMetrics(lineMetrics, _countof(lineMetrics), &lineCount);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{
// If only one line is visible, disable wrapping so that as much text as possible is shown
// after trimming.
// TODO: Fix this for when more than one line is visible.
if (lineCount >= 2 &&
lineMetrics[0].isTrimmed &&
lineMetrics[1].isTrimmed &&
lineMetrics[1].height == 0.0f)
{ {
// If only one line is visible, disable wrapping so that as much text as possible is shown m_TextLayout->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
// after trimming.
// TODO: Fix this for when more than one line is visible.
if (lineCount >= 2 &&
lineMetrics[0].isTrimmed &&
lineMetrics[1].isTrimmed &&
lineMetrics[1].height == 0.0f)
{
m_TextLayout->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
}
} }
} }
} }
return true;
} }
void TextFormatD2D::SetProperties( void TextFormatD2D::SetProperties(

View File

@ -55,8 +55,8 @@ private:
// Creates a new DirectWrite text layout if |str| has changed since last call. Since creating // Creates a new DirectWrite text layout if |str| has changed since last call. Since creating
// the layout is costly, it is more efficient to keep reusing the text layout until the text // the layout is costly, it is more efficient to keep reusing the text layout until the text
// changes. // changes. Returns true if the layout is valid for use.
void CreateLayout(const WCHAR* str, UINT strLen, float maxW, float maxH, bool gdiEmulation); bool CreateLayout(const WCHAR* str, UINT strLen, float maxW, float maxH, bool gdiEmulation);
DWRITE_TEXT_METRICS GetMetrics( DWRITE_TEXT_METRICS GetMetrics(
const WCHAR* str, UINT strLen, bool gdiEmulation, float maxWidth = 10000.0f); const WCHAR* str, UINT strLen, bool gdiEmulation, float maxWidth = 10000.0f);