Revert "Initial implementation of fine-grained text analysis (#9202)"

This reverts commit 1c414a7723.

Fixes #10034.
This commit is contained in:
Dustin Howett 2021-05-11 14:14:17 -05:00
parent b132fbe4a6
commit 440b626ee3
2 changed files with 41 additions and 52 deletions

View file

@ -27,7 +27,8 @@ CustomTextLayout::CustomTextLayout(gsl::not_null<DxFontRenderData*> const fontRe
_runs{},
_breakpoints{},
_runIndex{ 0 },
_width{ gsl::narrow_cast<size_t>(fontRenderData->GlyphCell().width()) }
_width{ gsl::narrow_cast<size_t>(fontRenderData->GlyphCell().width()) },
_isEntireTextSimple{ false }
{
_localeName.resize(gsl::narrow_cast<size_t>(fontRenderData->DefaultTextFormat()->GetLocaleNameLength()) + 1); // +1 for null
THROW_IF_FAILED(fontRenderData->DefaultTextFormat()->GetLocaleName(_localeName.data(), gsl::narrow<UINT32>(_localeName.size())));
@ -45,6 +46,7 @@ try
_runs.clear();
_breakpoints.clear();
_runIndex = 0;
_isEntireTextSimple = false;
_textClusterColumns.clear();
_text.clear();
_glyphScaleCorrections.clear();
@ -101,6 +103,7 @@ CATCH_RETURN()
_formatInUse = _fontRenderData->DefaultTextFormat().Get();
_fontInUse = _fontRenderData->DefaultFontFace().Get();
RETURN_IF_FAILED(_AnalyzeTextComplexity());
RETURN_IF_FAILED(_AnalyzeRuns());
RETURN_IF_FAILED(_ShapeGlyphRuns());
@ -135,6 +138,7 @@ CATCH_RETURN()
_formatInUse = drawingContext->useItalicFont ? _fontRenderData->ItalicTextFormat().Get() : _fontRenderData->DefaultTextFormat().Get();
_fontInUse = drawingContext->useItalicFont ? _fontRenderData->ItalicFontFace().Get() : _fontRenderData->DefaultFontFace().Get();
RETURN_IF_FAILED(_AnalyzeTextComplexity());
RETURN_IF_FAILED(_AnalyzeRuns());
RETURN_IF_FAILED(_ShapeGlyphRuns());
RETURN_IF_FAILED(_CorrectGlyphRuns());
@ -150,9 +154,8 @@ CATCH_RETURN()
// Routine Description:
// - Uses the internal text information and the analyzers/font information from construction
// to determine the complexity of the text. During the process we break the text into initial
// runs based on their complexity. This allows us to further optimize the layout process
// of simple runs.
// to determine the complexity of the text. If the text is determined to be entirely simple,
// we'll have more chances to optimize the layout process.
// Arguments:
// - <none> - Uses internal state
// Return Value:
@ -167,30 +170,21 @@ CATCH_RETURN()
UINT32 uiLengthRead = 0;
// Start from the beginning.
UINT32 pos = 0;
const UINT32 glyphStart = 0;
_glyphIndices.resize(textLength);
while (pos < textLength)
{
const HRESULT hr = _fontRenderData->Analyzer()->GetTextComplexity(
&_text.at(pos),
textLength,
_fontInUse,
&isTextSimple,
&uiLengthRead,
&_glyphIndices.at(pos));
const HRESULT hr = _fontRenderData->Analyzer()->GetTextComplexity(
_text.c_str(),
textLength,
_fontInUse,
&isTextSimple,
&uiLengthRead,
&_glyphIndices.at(glyphStart));
RETURN_IF_FAILED(hr);
_SetCurrentRun(pos);
_SplitCurrentRun(pos);
pos += std::max(uiLengthRead, 1u);
while (uiLengthRead > 0)
{
auto& run = _FetchNextRun(uiLengthRead);
run.isTextSimple = isTextSimple;
}
}
RETURN_IF_FAILED(hr);
_isEntireTextSimple = isTextSimple && uiLengthRead == textLength;
}
CATCH_RETURN();
return S_OK;
@ -224,26 +218,15 @@ CATCH_RETURN()
// Allocate enough room to have one breakpoint per code unit.
_breakpoints.resize(_text.size());
RETURN_IF_FAILED(_AnalyzeTextComplexity());
std::vector<std::pair<UINT32, UINT32>> complexRanges;
for (auto& run : _runs)
{
if (!run.isTextSimple)
{
complexRanges.push_back(std::make_pair(run.textStart, run.textLength));
}
}
for (auto& range : complexRanges)
if (!_isEntireTextSimple)
{
// Call each of the analyzers in sequence, recording their results.
RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeLineBreakpoints(this, range.first, range.second, this));
RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeBidi(this, range.first, range.second, this));
RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeScript(this, range.first, range.second, this));
RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeNumberSubstitution(this, range.first, range.second, this));
RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeLineBreakpoints(this, 0, textLength, this));
RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeBidi(this, 0, textLength, this));
RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeScript(this, 0, textLength, this));
RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeNumberSubstitution(this, 0, textLength, this));
// Perform our custom font fallback analyzer that mimics the pattern of the real analyzers.
RETURN_IF_FAILED(_AnalyzeFontFallback(this, range.first, range.second));
RETURN_IF_FAILED(_AnalyzeFontFallback(this, 0, textLength));
}
// Ensure that a font face is attached to every run
@ -283,7 +266,6 @@ CATCH_RETURN()
_glyphOffsets.resize(estimatedGlyphCount);
_glyphAdvances.resize(estimatedGlyphCount);
_glyphClusters.resize(textLength);
_glyphDesignUnitAdvances.resize(textLength);
UINT32 glyphStart = 0;
@ -357,7 +339,7 @@ CATCH_RETURN()
_glyphIndices.resize(totalGlyphsArrayCount);
}
if (run.isTextSimple)
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
@ -366,6 +348,10 @@ CATCH_RETURN()
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);
USHORT designUnitsPerEm = metrics.designUnitsPerEm;
RETURN_IF_FAILED(_fontInUse->GetDesignGlyphAdvances(
@ -374,14 +360,14 @@ CATCH_RETURN()
&_glyphDesignUnitAdvances.at(glyphStart),
run.isSideways));
for (UINT32 i = glyphStart; i < glyphStart + textLength; i++)
for (size_t i = glyphStart; i < _glyphAdvances.size(); i++)
{
_glyphAdvances.at(i) = (float)_glyphDesignUnitAdvances.at(i) / designUnitsPerEm * _formatInUse->GetFontSize() * run.fontScale;
}
// Set all the clusters as sequential. In a simple run, we're going 1 to 1.
// Fill the clusters sequentially from 0 to N-1.
std::iota(_glyphClusters.begin() + glyphStart, _glyphClusters.begin() + glyphStart + textLength, gsl::narrow_cast<unsigned short>(0));
std::iota(_glyphClusters.begin(), _glyphClusters.end(), gsl::narrow_cast<unsigned short>(0));
run.glyphCount = textLength;
glyphStart += textLength;
@ -486,6 +472,12 @@ CATCH_RETURN()
{
try
{
// For simple text, there is no need to correct runs.
if (_isEntireTextSimple)
{
return S_OK;
}
// Correct each run separately. This is needed whenever script, locale,
// or reading direction changes.
for (UINT32 runIndex = 0; runIndex < _runs.size(); ++runIndex)
@ -625,11 +617,6 @@ try
return S_FALSE; // Nothing to do..
}
if (run.isTextSimple)
{
return S_OK; // No need to correct run.
}
// We're going to walk through and check for advances that don't match the space that we expect to give out.
// Glyph Indices represents the number inside the selected font where the glyph image/paths are found.

View file

@ -76,7 +76,6 @@ namespace Microsoft::Console::Render
glyphCount(),
bidiLevel(),
script(),
isTextSimple(),
isNumberSubstituted(),
isSideways(),
fontFace{ nullptr },
@ -91,7 +90,6 @@ namespace Microsoft::Console::Render
UINT32 glyphCount; // number of glyphs associated with this run of text
DWRITE_SCRIPT_ANALYSIS script;
UINT8 bidiLevel;
bool isTextSimple;
bool isNumberSubstituted;
bool isSideways;
::Microsoft::WRL::ComPtr<IDWriteFontFace1> fontFace;
@ -178,6 +176,10 @@ namespace Microsoft::Console::Render
UINT32 _runIndex;
// 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.