Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip glyph shaping analysis when the entire text is simple #6206

Merged
7 commits merged into from
Jun 1, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 57 additions & 8 deletions src/renderer/dx/CustomTextLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ CustomTextLayout::CustomTextLayout(gsl::not_null<IDWriteFactory1*> const factory

_text += text;
}

const auto textLength = gsl::narrow<UINT32>(_text.size());

BOOL isTextSimple = FALSE;
UINT32 uiLengthRead = 0;
const UINT32 glyphStart = 0;

_glyphIndices.resize(textLength);

const HRESULT hr = _analyzer->GetTextComplexity(
_text.c_str(),
textLength,
_font.Get(),
&isTextSimple,
&uiLengthRead,
&_glyphIndices.at(glyphStart));

_isEntireTextSimple = SUCCEEDED(hr) && isTextSimple && uiLengthRead == textLength;
miniksa marked this conversation as resolved.
Show resolved Hide resolved
}

// Routine Description:
Expand Down Expand Up @@ -149,11 +167,7 @@ CustomTextLayout::CustomTextLayout(gsl::not_null<IDWriteFactory1*> const factory
// Allocate enough room to have one breakpoint per code unit.
_breakpoints.resize(_text.size());

BOOL isTextSimple = FALSE;
UINT32 uiLengthRead = 0;
RETURN_IF_FAILED(_analyzer->GetTextComplexity(_text.c_str(), textLength, _font.Get(), &isTextSimple, &uiLengthRead, NULL));

if (!(isTextSimple && uiLengthRead == _text.size()))
if (!_isEntireTextSimple)
{
// Call each of the analyzers in sequence, recording their results.
RETURN_IF_FAILED(_analyzer->AnalyzeLineBreakpoints(this, 0, textLength, this));
Expand Down Expand Up @@ -274,6 +288,39 @@ CustomTextLayout::CustomTextLayout(gsl::not_null<IDWriteFactory1*> const factory
_glyphIndices.resize(totalGlyphsArrayCount);
}

if (_isEntireTextSimple)
{
// When the entire text is simple, we can skip GetGlyphs and directly retrieve glyph indices and
// advances(in font design unit). With the help of font metrics, we can calculate the actual glyph
// advances without the need of GetGlyphPlacements. This shortcut will significantly reduce the time
// needed for text analysis.
DWRITE_FONT_METRICS1 metrics;
run.fontFace->GetMetrics(&metrics);

// With simple text, there's only one run. The actual glyph count is the same as textLength.
_glyphDesignUnitAdvances.resize(textLength);
_glyphAdvances.resize(textLength);
_glyphOffsets.resize(textLength);

USHORT designUnitsPerEm = metrics.designUnitsPerEm;

RETURN_IF_FAILED(_font->GetDesignGlyphAdvances(
textLength,
&_glyphIndices.at(glyphStart),
&_glyphDesignUnitAdvances.at(glyphStart),
run.isSideways));

for (size_t i = glyphStart; i < _glyphAdvances.size(); i++)
{
_glyphAdvances.at(i) = (float)_glyphDesignUnitAdvances.at(i) / designUnitsPerEm * _format->GetFontSize() * run.fontScale;
}

run.glyphCount = textLength;
glyphStart += textLength;

return S_OK;
}

miniksa marked this conversation as resolved.
Show resolved Hide resolved
std::vector<DWRITE_SHAPING_TEXT_PROPERTIES> textProps(textLength);
std::vector<DWRITE_SHAPING_GLYPH_PROPERTIES> glyphProps(maxGlyphCount);

Expand Down Expand Up @@ -369,6 +416,11 @@ CustomTextLayout::CustomTextLayout(gsl::not_null<IDWriteFactory1*> const factory
// - S_OK or suitable DirectWrite or STL error code
[[nodiscard]] HRESULT CustomTextLayout::_CorrectGlyphRuns() noexcept
{
if (_isEntireTextSimple)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave a comment why this is OK.

{
return S_OK;
}

try
{
// Correct each run separately. This is needed whenever script, locale,
Expand Down Expand Up @@ -508,9 +560,6 @@ try

// We're going to walk through and check for advances that don't match the space that we expect to give out.

DWRITE_FONT_METRICS1 metrics;
miniksa marked this conversation as resolved.
Show resolved Hide resolved
run.fontFace->GetMetrics(&metrics);

// Glyph Indices represents the number inside the selected font where the glyph image/paths are found.
// Text represents the original text we gave in.
// Glyph Clusters represents the map between Text and Glyph Indices.
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/dx/CustomTextLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ namespace Microsoft::Console::Render

// Glyph shaping results

// Whether the entire text is determined to be simple and does not require full script shaping.
bool _isEntireTextSimple;

std::vector<DWRITE_GLYPH_OFFSET> _glyphOffsets;

// Clusters are complicated. They're in respect to each individual run.
Expand All @@ -191,6 +194,9 @@ namespace Microsoft::Console::Render
// This appears to be the index of the glyph inside each font.
std::vector<UINT16> _glyphIndices;

// This is for calculating glyph advances when the entire text is simple.
std::vector<INT32> _glyphDesignUnitAdvances;

std::vector<float> _glyphAdvances;

struct ScaleCorrection
Expand Down