From d3b5b6c24ae47eaa19d426ff428b8e0f58d4678c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4=C3=A4tt=C3=A4?= Date: Thu, 6 May 2021 11:00:08 +0300 Subject: Add text bounds cache Improve performance by caching recently used text bounds. Charts keeps requesting bounds for the same text multiple times. Store the recently requested bounds to a cache to improve performance. In android device reduces the frame time by about 30 % and in windows reduces the total time spent in native text function used to get the bounds from 8.5% to 3.1%. Fixes: QTBUG-59040 Change-Id: I8a2fd89f2f2076e0c9364618a4cdc2596e0087a1 Reviewed-by: Miikka Heikkinen (cherry picked from commit 1fb4a3ef2bd86d650495e15a23c7efc1e600a59a) Reviewed-by: Qt Cherry-pick Bot --- src/charts/chartpresenter.cpp | 51 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/charts/chartpresenter.cpp b/src/charts/chartpresenter.cpp index 6407a270..98bca1a1 100644 --- a/src/charts/chartpresenter.cpp +++ b/src/charts/chartpresenter.cpp @@ -478,18 +478,59 @@ ChartTitle *ChartPresenter::titleElement() return m_title; } +template +struct TextBoundCache +{ + struct element + { + quint32 lastUsed; + QRectF bounds; + }; + QHash elements; + quint32 usedCounter = 0; + QGraphicsTextItem dummyText; + + QRectF bounds(const QFont &font, const QString &text) + { + const QString key = font.key() + text; + auto elem = elements.find(key); + if (elem != elements.end()) { + usedCounter++; + elem->lastUsed = usedCounter; + return elem->bounds; + } + dummyText.setFont(font); + dummyText.setHtml(text); + const QRectF bounds = dummyText.boundingRect(); + if (elements.size() >= TSize) { + auto elem = std::min_element(elements.begin(), elements.end(), + [](const element &a, const element &b) { + return a.lastUsed < b.lastUsed; + }); + if (elem != elements.end()) { + const QString key = elem.key(); + elements.remove(key); + } + } + elements.insert(key, {usedCounter++, bounds}); + return bounds; + } + QTextDocument *document() + { + return dummyText.document(); + } +}; + QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle) { - static QGraphicsTextItem dummyTextItem; + static TextBoundCache<32> textBoundCache; static bool initMargin = true; if (initMargin) { - dummyTextItem.document()->setDocumentMargin(textMargin()); + textBoundCache.document()->setDocumentMargin(textMargin()); initMargin = false; } - dummyTextItem.setFont(font); - dummyTextItem.setHtml(text); - QRectF boundingRect = dummyTextItem.boundingRect(); + QRectF boundingRect = textBoundCache.bounds(font, text); // Take rotation into account if (angle) { -- cgit v1.2.3 From 230ac625403d52107c1b8050dbf6978bdd72790e Mon Sep 17 00:00:00 2001 From: Dimitrios Apostolou Date: Mon, 10 May 2021 16:20:41 +0200 Subject: Add comments and clarify some code Change-Id: Ib0280e18d8e788631ae3c11674398c2725cbafa6 Reviewed-by: Miikka Heikkinen (cherry picked from commit b1e5084099c28c0b937f4f9ab070d6d5556cf54d) Reviewed-by: Qt Cherry-pick Bot --- src/charts/axis/chartaxiselement.cpp | 6 +++++- src/charts/axis/horizontalaxis.cpp | 13 ++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/charts/axis/chartaxiselement.cpp b/src/charts/axis/chartaxiselement.cpp index 9ca59b08..17f36e61 100644 --- a/src/charts/axis/chartaxiselement.cpp +++ b/src/charts/axis/chartaxiselement.cpp @@ -419,7 +419,11 @@ QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks, return labels; if (format.isEmpty()) { - int n = qMax(int(-qFloor(std::log10((max - min) / (ticks - 1)))), 0) + 1; + // Calculate how many decimal digits are needed to show difference between ticks, + // for example tick marks 1.002 and 1.003 have a difference of 0.001 and need 3 decimals. + // For differences >= 1 (positive log10) use always 1 decimal. + double l10 = std::log10((max - min) / (ticks - 1)); + int n = qMax(int(-qFloor(l10)), 0) + 1; if (tickType == QValueAxis::TicksFixed) { for (int i = 0; i < ticks; i++) { qreal value = min + (i * (max - min) / (ticks - 1)); diff --git a/src/charts/axis/horizontalaxis.cpp b/src/charts/axis/horizontalaxis.cpp index 64f7eb3e..9389c236 100644 --- a/src/charts/axis/horizontalaxis.cpp +++ b/src/charts/axis/horizontalaxis.cpp @@ -102,7 +102,6 @@ void HorizontalAxis::updateGeometry() else if (axis()->alignment() == Qt::AlignBottom) arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top()); - qreal width = 0; const QLatin1String ellipsis("..."); //title @@ -133,6 +132,8 @@ void HorizontalAxis::updateGeometry() QList lines = gridItems(); QList shades = shadeItems(); + qreal last_label_max_x = 0; + for (int i = 0; i < layout.size(); ++i) { //items QGraphicsLineItem *gridItem = static_cast(lines.at(i)); @@ -160,6 +161,7 @@ void HorizontalAxis::updateGeometry() labelItem->setHtml(text); } else { qreal labelWidth = axisRect.width() / layout.count() - (2 * labelPadding()); + // Replace digits with ellipsis "..." if number does not fit QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text, axis()->labelsAngle(), labelWidth, @@ -255,13 +257,14 @@ void HorizontalAxis::updateGeometry() labelItem->setPos(labelPos.toPoint()); //label overlap detection - compensate one pixel for rounding errors - if ((labelItem->pos().x() < width && labelItem->toPlainText() == ellipsis) || forceHide || - (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) || - (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right()) { + if ((labelItem->pos().x() < last_label_max_x && labelItem->toPlainText() == ellipsis) + || forceHide + || (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) + || (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right()) { labelItem->setVisible(false); } else { labelItem->setVisible(true); - width = boundingRect.width() + labelItem->pos().x(); + last_label_max_x = boundingRect.width() + labelItem->pos().x(); } //shades -- cgit v1.2.3 From 9aacc8367dff20f559689dd5245049b7b1fb161f Mon Sep 17 00:00:00 2001 From: Dimitrios Apostolou Date: Mon, 10 May 2021 16:21:18 +0200 Subject: Fix X axis labels to not draw over each other When the label numbers on the Y axis become too wide then the plot area width is shrunk to accommodate for that. But the X axis label numbers were calculated for the wider X axis, and printed on the shrunk X axis, so they overlapped each other. This is addressed in the Qt::AlignBottom part of the fix. Presumably the same issue happens with different alignments so respective change has been applied to those too. Fixes: QTBUG-79218 Change-Id: I2ad8c62f8c8d6308ab13b9da42fa6bd5e9192ee3 Reviewed-by: Miikka Heikkinen (cherry picked from commit 5b6e1042bd0aa4514df71209e7784b23490dbd1e) Reviewed-by: Qt Cherry-pick Bot --- src/charts/layout/cartesianchartlayout.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/charts/layout/cartesianchartlayout.cpp b/src/charts/layout/cartesianchartlayout.cpp index af22b93d..355a7605 100644 --- a/src/charts/layout/cartesianchartlayout.cpp +++ b/src/charts/layout/cartesianchartlayout.cpp @@ -193,14 +193,18 @@ QRectF CartesianChartLayout::calculateAxisGeometry(const QRectF &geometry, if (leftSqueezeRatio < 1.0) width *= leftSqueezeRatio; leftOffset+=width; - axis->setGeometry(QRect(chartRect.left()-leftOffset, geometry.top(),width, geometry.bottom()),chartRect); + axis->setGeometry(QRect(chartRect.left() - leftOffset, chartRect.top(), + width, chartRect.bottom()), + chartRect); break; } case Qt::AlignRight:{ qreal width = size.width(); if (rightSqueezeRatio < 1.0) width *= rightSqueezeRatio; - axis->setGeometry(QRect(chartRect.right()+rightOffset,geometry.top(),width,geometry.bottom()),chartRect); + axis->setGeometry(QRect(chartRect.right() + rightOffset, chartRect.top(), + width, chartRect.bottom()), + chartRect); rightOffset+=width; break; } @@ -208,7 +212,9 @@ QRectF CartesianChartLayout::calculateAxisGeometry(const QRectF &geometry, qreal height = size.height(); if (topSqueezeRatio < 1.0) height *= topSqueezeRatio; - axis->setGeometry(QRect(geometry.left(), chartRect.top() - topOffset - height, geometry.width(), height), chartRect); + axis->setGeometry(QRect(chartRect.left(), chartRect.top() - topOffset - height, + chartRect.width(), height), + chartRect); topOffset += height; break; } @@ -216,7 +222,9 @@ QRectF CartesianChartLayout::calculateAxisGeometry(const QRectF &geometry, qreal height = size.height(); if (bottomSqueezeRatio < 1.0) height *= bottomSqueezeRatio; - axis->setGeometry(QRect(geometry.left(), chartRect.bottom() + bottomOffset, geometry.width(), height), chartRect); + axis->setGeometry(QRect(chartRect.left(), chartRect.bottom() + bottomOffset, + chartRect.width(), height), + chartRect); bottomOffset += height; break; } -- cgit v1.2.3 From 861404492dbf66b4eb6a73e63908b1724159fa09 Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Thu, 20 May 2021 14:48:41 +0300 Subject: Bump version Change-Id: I904e658301a63842841f4f80ca7bab6dbd28c7da --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 7dc754c7..0eeba9a5 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ load(qt_build_config) DEFINES += QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST -MODULE_VERSION = 5.15.4 +MODULE_VERSION = 5.15.5 -- cgit v1.2.3