Minor optimizations in GetMultiLineTextExtent()

Handle the case of a single line string specially, it's faster to do
this than use slow loop over all characters.

Also avoid constructing the string with the characters to measure one by
one and do it all at once instead.

Add a possibility to benchmark GetMultiLineTextExtent() rather than
GetTextExtent() in the graphics benchmark.
This commit is contained in:
Vadim Zeitlin 2020-06-10 23:36:03 +02:00
parent 09ecfaec8f
commit bfeae1922d
2 changed files with 23 additions and 9 deletions

View File

@ -105,17 +105,27 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
wxCoord *height, wxCoord *height,
wxCoord *heightOneLine) wxCoord *heightOneLine)
{ {
// It's noticeably faster to handle the case of a string which isn't
// actually multiline specially here, to skip iteration above in this case.
if ( text.find('\n') == wxString::npos )
{
GetTextExtent(text, width, height);
if ( heightOneLine && height )
*heightOneLine = *height;
return;
}
MeasuringGuard guard(*this); MeasuringGuard guard(*this);
wxCoord widthTextMax = 0, widthLine, wxCoord widthTextMax = 0, widthLine,
heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
wxString curLine; wxString::const_iterator lineStart = text.begin();
for ( wxString::const_iterator pc = text.begin(); ; ++pc ) for ( wxString::const_iterator pc = text.begin(); ; ++pc )
{ {
if ( pc == text.end() || *pc == wxS('\n') ) if ( pc == text.end() || *pc == wxS('\n') )
{ {
if ( curLine.empty() ) if ( pc == lineStart )
{ {
// we can't use GetTextExtent - it will return 0 for both width // we can't use GetTextExtent - it will return 0 for both width
// and height and an empty line should count in height // and height and an empty line should count in height
@ -137,7 +147,7 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
} }
else else
{ {
CallGetTextExtent(curLine, &widthLine, &heightLine); CallGetTextExtent(wxString(lineStart, pc), &widthLine, &heightLine);
if ( widthLine > widthTextMax ) if ( widthLine > widthTextMax )
widthTextMax = widthLine; widthTextMax = widthLine;
heightTextTotal += heightLine; heightTextTotal += heightLine;
@ -149,13 +159,10 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
} }
else // '\n' else // '\n'
{ {
curLine.clear(); lineStart = pc;
++lineStart;
} }
} }
else
{
curLine += *pc;
}
} }
if ( width ) if ( width )

View File

@ -66,6 +66,7 @@ struct GraphicsBenchmarkOptions
testCircles = testCircles =
testEllipses = testEllipses =
testTextExtent = testTextExtent =
testMultiLineTextExtent =
testPartialTextExtents = false; testPartialTextExtents = false;
usePaint = usePaint =
@ -95,6 +96,7 @@ struct GraphicsBenchmarkOptions
testCircles, testCircles,
testEllipses, testEllipses,
testTextExtent, testTextExtent,
testMultiLineTextExtent,
testPartialTextExtents; testPartialTextExtents;
bool usePaint, bool usePaint,
@ -634,7 +636,10 @@ private:
wxStopWatch sw; wxStopWatch sw;
for ( long n = 0; n < opts.numIters; n++ ) for ( long n = 0; n < opts.numIters; n++ )
{ {
size += dc.GetTextExtent(str); if ( opts.testMultiLineTextExtent )
size += dc.GetMultiLineTextExtent(str);
else
size += dc.GetTextExtent(str);
} }
const long t = sw.Time(); const long t = sw.Time();
@ -847,6 +852,7 @@ public:
{ wxCMD_LINE_SWITCH, "", "circles" }, { wxCMD_LINE_SWITCH, "", "circles" },
{ wxCMD_LINE_SWITCH, "", "ellipses" }, { wxCMD_LINE_SWITCH, "", "ellipses" },
{ wxCMD_LINE_SWITCH, "", "textextent" }, { wxCMD_LINE_SWITCH, "", "textextent" },
{ wxCMD_LINE_SWITCH, "", "multilinetextextent" },
{ wxCMD_LINE_SWITCH, "", "partialtextextents" }, { wxCMD_LINE_SWITCH, "", "partialtextextents" },
{ wxCMD_LINE_SWITCH, "", "paint" }, { wxCMD_LINE_SWITCH, "", "paint" },
{ wxCMD_LINE_SWITCH, "", "client" }, { wxCMD_LINE_SWITCH, "", "client" },
@ -922,6 +928,7 @@ public:
opts.testCircles = parser.Found("circles"); opts.testCircles = parser.Found("circles");
opts.testEllipses = parser.Found("ellipses"); opts.testEllipses = parser.Found("ellipses");
opts.testTextExtent = parser.Found("textextent"); opts.testTextExtent = parser.Found("textextent");
opts.testMultiLineTextExtent = parser.Found("multilinetextextent");
opts.testPartialTextExtents = parser.Found("partialtextextents"); opts.testPartialTextExtents = parser.Found("partialtextextents");
if ( !(opts.testBitmaps || opts.testImages || opts.testLines if ( !(opts.testBitmaps || opts.testImages || opts.testLines
|| opts.testRawBitmaps || opts.testRectangles || opts.testRawBitmaps || opts.testRectangles