From bfeae1922dc13484f57b42567cff56173e4e6621 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 10 Jun 2020 23:36:03 +0200 Subject: [PATCH] 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. --- src/common/textmeasurecmn.cpp | 23 +++++++++++++++-------- tests/benchmarks/graphics.cpp | 9 ++++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/common/textmeasurecmn.cpp b/src/common/textmeasurecmn.cpp index 8d828d4b71..16448d2664 100644 --- a/src/common/textmeasurecmn.cpp +++ b/src/common/textmeasurecmn.cpp @@ -105,17 +105,27 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text, wxCoord *height, 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); wxCoord widthTextMax = 0, widthLine, heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; - wxString curLine; + wxString::const_iterator lineStart = text.begin(); for ( wxString::const_iterator pc = text.begin(); ; ++pc ) { 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 // and height and an empty line should count in height @@ -137,7 +147,7 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text, } else { - CallGetTextExtent(curLine, &widthLine, &heightLine); + CallGetTextExtent(wxString(lineStart, pc), &widthLine, &heightLine); if ( widthLine > widthTextMax ) widthTextMax = widthLine; heightTextTotal += heightLine; @@ -149,13 +159,10 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text, } else // '\n' { - curLine.clear(); + lineStart = pc; + ++lineStart; } } - else - { - curLine += *pc; - } } if ( width ) diff --git a/tests/benchmarks/graphics.cpp b/tests/benchmarks/graphics.cpp index e2714de5de..bbbec0cd5a 100644 --- a/tests/benchmarks/graphics.cpp +++ b/tests/benchmarks/graphics.cpp @@ -66,6 +66,7 @@ struct GraphicsBenchmarkOptions testCircles = testEllipses = testTextExtent = + testMultiLineTextExtent = testPartialTextExtents = false; usePaint = @@ -95,6 +96,7 @@ struct GraphicsBenchmarkOptions testCircles, testEllipses, testTextExtent, + testMultiLineTextExtent, testPartialTextExtents; bool usePaint, @@ -634,7 +636,10 @@ private: wxStopWatch sw; 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(); @@ -847,6 +852,7 @@ public: { wxCMD_LINE_SWITCH, "", "circles" }, { wxCMD_LINE_SWITCH, "", "ellipses" }, { wxCMD_LINE_SWITCH, "", "textextent" }, + { wxCMD_LINE_SWITCH, "", "multilinetextextent" }, { wxCMD_LINE_SWITCH, "", "partialtextextents" }, { wxCMD_LINE_SWITCH, "", "paint" }, { wxCMD_LINE_SWITCH, "", "client" }, @@ -922,6 +928,7 @@ public: opts.testCircles = parser.Found("circles"); opts.testEllipses = parser.Found("ellipses"); opts.testTextExtent = parser.Found("textextent"); + opts.testMultiLineTextExtent = parser.Found("multilinetextextent"); opts.testPartialTextExtents = parser.Found("partialtextextents"); if ( !(opts.testBitmaps || opts.testImages || opts.testLines || opts.testRawBitmaps || opts.testRectangles