[graphics/krita] /: Avoid using toLower() for of canse-insensitive comparison

Dmitry Kazakov null at kde.org
Mon Oct 26 16:58:51 GMT 2026


Git commit fbd5e1f712bacc941736353a1a665012973858c8 by Dmitry Kazakov.
Committed on 26/10/2026 at 16:54.
Pushed by dkazakov into branch 'master'.

Avoid using toLower() for of canse-insensitive comparison

toLower() allocates heap memory, which is extremely
slow on Windows, so we should avoid doing that in hot
loops.

CC:kimageshop at kde.org

M  +9    -0    HACKING
M  +2    -2    libs/flake/text/KoFFWWSConverter.cpp
M  +9    -9    libs/flake/text/KoSvgTextContentElement.cpp
M  +3    -3    libs/flake/text/KoSvgTextProperties.cpp
M  +6    -6    libs/pigment/KoColor.cpp
M  +1    -1    libs/resources/KisResourceModel.cpp
M  +3    -3    libs/resources/KisTagModel.cpp
M  +1    -1    libs/resources/KisTagResourceModel.cpp

https://invent.kde.org/graphics/krita/-/commit/fbd5e1f712bacc941736353a1a665012973858c8

diff --git a/HACKING b/HACKING
index ccca6137f89..1aa2997d181 100644
--- a/HACKING
+++ b/HACKING
@@ -388,6 +388,15 @@ On menu action names: "Group layers" vs "Group layer(s)"
 
       i18ncp("@action:inmenu", "Group layer", "Group layers")
 
+Case insensitive string comparison
+
+    Instead of using `str.toLower() == "abc"` prefer using
+    `str.compare("abc", Qt::CaseInsensitive) == 0`, especially in hot
+    places
+
+    The `QString::toLower()` call is expensive on Winodws, since it allocates
+    memory on heap. It is more efficient to perform the comparison in place.
+
 With Krita now supporting Python scripting, we need guidelines for these as well.
 These guidelines are preliminary and may be further refined in the future.
 
diff --git a/libs/flake/text/KoFFWWSConverter.cpp b/libs/flake/text/KoFFWWSConverter.cpp
index f6948113734..f95997a45db 100644
--- a/libs/flake/text/KoFFWWSConverter.cpp
+++ b/libs/flake/text/KoFFWWSConverter.cpp
@@ -146,7 +146,7 @@ struct FontFamilyNode {
     static FontFamilyNode createWWSFamilyNode(const FontFamilyNode &child, const FontFamilyNode &typographic, QStringList existingWWSNames) {
         FontFamilyNode wwsFamily;
         if (child.type != KoSvgText::OpenTypeFontType) {
-            if (child.fontStyle.toLower() == "regular") {
+            if (child.fontStyle.compare("regular", Qt::CaseInsensitive) == 0) {
                 wwsFamily.fontFamily = child.fontFamily;
             } else {
                 wwsFamily.fontFamily = child.fontFamily + " " + child.fontStyle;
@@ -763,7 +763,7 @@ void KoFFWWSConverter::sortIntoWWSFamilies()
                         // Like, it is technically correct, because it allows us to select fonts with CSS
                         // that would otherwise be unselectable, but this does mean that other applications
                         // would need to have our exact idea of a CSS family name.
-                        if (wws->fontStyle.toLower() != "regular"
+                        if (wws->fontStyle.compare("regular", Qt::CaseInsensitive) != 0
                                 && !font->fontStyle.contains(wws->fontStyle)) {
                             continue;
                         }
diff --git a/libs/flake/text/KoSvgTextContentElement.cpp b/libs/flake/text/KoSvgTextContentElement.cpp
index 741169dae10..93d0c88741d 100644
--- a/libs/flake/text/KoSvgTextContentElement.cpp
+++ b/libs/flake/text/KoSvgTextContentElement.cpp
@@ -157,8 +157,8 @@ KoSvgTextProperties adjustPropertiesForFontSizeWorkaround(const KoSvgTextPropert
 
 }
 
-const QString TEXT_STYLE_TYPE = "krita:style-type";
-const QString TEXT_STYLE_RES = "krita:style-resolution";
+const QLatin1String TEXT_STYLE_TYPE("krita:style-type");
+const QLatin1String TEXT_STYLE_RES("krita:style-resolution");
 
 bool KoSvgTextContentElement::loadSvg(const QDomElement &e, SvgLoadingContext &context, bool rootNode)
 {
@@ -232,11 +232,11 @@ bool KoSvgTextContentElement::loadSvg(const QDomElement &e, SvgLoadingContext &c
         }
     }
 
-    if (e.hasAttribute(TEXT_STYLE_TYPE.toLatin1().data())) {
-        properties.setProperty(KoSvgTextProperties::KraTextStyleType, e.attribute(TEXT_STYLE_TYPE.toLatin1().data()));
-        if (e.hasAttribute(TEXT_STYLE_RES.toLatin1().data())) {
-            QString resolution = e.attribute(TEXT_STYLE_RES.toLatin1().data()).toLower();
-            if (resolution.endsWith("dpi")) {
+    if (e.hasAttribute(TEXT_STYLE_TYPE)) {
+        properties.setProperty(KoSvgTextProperties::KraTextStyleType, e.attribute(TEXT_STYLE_TYPE));
+        if (e.hasAttribute(TEXT_STYLE_RES)) {
+            QString resolution = e.attribute(TEXT_STYLE_RES);
+            if (resolution.endsWith("dpi", Qt::CaseInsensitive)) {
                 resolution.chop(3);
             }
             properties.setProperty(KoSvgTextProperties::KraTextStyleResolution, KisDomUtils::toInt(resolution));
@@ -367,9 +367,9 @@ bool KoSvgTextContentElement::saveSvg(SvgSavingContext &context,
     }
 
     if (properties.hasProperty(KoSvgTextProperties::KraTextStyleType)) {
-        context.shapeWriter().addAttribute(TEXT_STYLE_TYPE.toLatin1().data(), properties.property(KoSvgTextProperties::KraTextStyleType).toString());
+        context.shapeWriter().addAttribute(TEXT_STYLE_TYPE.data(), properties.property(KoSvgTextProperties::KraTextStyleType).toString());
         if (properties.hasProperty(KoSvgTextProperties::KraTextStyleResolution)) {
-            context.shapeWriter().addAttribute(TEXT_STYLE_RES.toLatin1().data(), QString::number(properties.property(KoSvgTextProperties::KraTextStyleResolution).toInt())+"dpi");
+            context.shapeWriter().addAttribute(TEXT_STYLE_RES.data(), QString::number(properties.property(KoSvgTextProperties::KraTextStyleResolution).toInt())+"dpi");
         }
     }
 
diff --git a/libs/flake/text/KoSvgTextProperties.cpp b/libs/flake/text/KoSvgTextProperties.cpp
index b442a6d422c..1d81ae828e0 100644
--- a/libs/flake/text/KoSvgTextProperties.cpp
+++ b/libs/flake/text/KoSvgTextProperties.cpp
@@ -306,10 +306,10 @@ QVariantMap parseFeatureSettingsStringList(const QStringList features) {
         } else {
             bool ok = false;
             int featureVal = tag.second.toInt(&ok);
-            if (tag.second.toLower() == "on") {
+            if (tag.second.compare("on", Qt::CaseInsensitive) == 0) {
                 featureVal = 1;
                 ok = true;
-            } else if (tag.second.toLower() == "off") {
+            } else if (tag.second.compare("off", Qt::CaseInsensitive) == 0) {
                 featureVal = 0;
                 ok = true;
             }
@@ -335,7 +335,7 @@ void KoSvgTextProperties::parseSvgTextAttribute(const SvgLoadingContext &context
                              << "0deg"
                              << "90"
                              << "90deg";
-        if (acceptedOrientations.contains(value.toLower())) {
+        if (acceptedOrientations.contains(value, Qt::CaseInsensitive)) {
             if (!autoValue.isAuto) {
                 autoValue.customValue = kisRadiansToDegrees(roundToStraightAngle(autoValue.customValue));
             }
diff --git a/libs/pigment/KoColor.cpp b/libs/pigment/KoColor.cpp
index c75970d0ff6..b53e396e81a 100644
--- a/libs/pigment/KoColor.cpp
+++ b/libs/pigment/KoColor.cpp
@@ -456,9 +456,9 @@ KoColor KoColor::fromXML(const QString &xml)
     QString channelDepthID = root.attribute("channeldepth", Integer16BitsColorDepthID.id());
 
     bool ok;
-    if (child.hasAttribute("space") || child.tagName().toLower() == "srgb") {
+    if (child.hasAttribute("space") || child.tagName().compare("srgb", Qt::CaseInsensitive) == 0) {
         c = KoColor::fromXML(child, channelDepthID, &ok);
-    } else if (root.hasAttribute("space") || root.tagName().toLower() == "srgb"){
+    } else if (root.hasAttribute("space") || root.tagName().compare("srgb", Qt::CaseInsensitive) == 0){
         c = KoColor::fromXML(root, channelDepthID, &ok);
     } else {
         qWarning() << "Cannot parse color from xml" << xml;
@@ -532,7 +532,7 @@ KoColor KoColor::fromSVG11(const QString value, QHash<QString, const KoColorProf
     KoColor parsed(KoColorSpaceRegistry::instance()->rgb16(KoColorSpaceRegistry::instance()->p709SRGBProfile()));
     parsed.setOpacity(1.0);
 
-    if (value.toLower() == "none") {
+    if (value.compare("none", Qt::CaseInsensitive) == 0) {
         return parsed;
     }
 
@@ -559,7 +559,7 @@ KoColor KoColor::fromSVG11(const QString value, QHash<QString, const KoColorProf
     dbgPigment << "Color definitions found during svg11parsing" << colorDefinitions;
 
     for (QString def : colorDefinitions) {
-        if (def.toLower() == "currentcolor") {
+        if (def.compare("currentcolor", Qt::CaseInsensitive) == 0) {
             parsed = current;
 #if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
         } else if (QColor::isValidColor(def)) {
@@ -567,7 +567,7 @@ KoColor KoColor::fromSVG11(const QString value, QHash<QString, const KoColorProf
         } else if (QColor::isValidColorName(def)) {
 #endif
             parsed.fromQColor(QColor(def));
-        } else if (def.toLower().startsWith("rgb")) {
+        } else if (def.startsWith("rgb", Qt::CaseInsensitive)) {
             QString parse = def.trimmed();
             QStringList colors = parse.split(',');
             QString r = colors[0].right((colors[0].length() - 4)).trimmed();
@@ -590,7 +590,7 @@ KoColor KoColor::fromSVG11(const QString value, QHash<QString, const KoColorProf
             }
             parsed.fromQColor(QColor(r.toInt(), g.toInt(), b.toInt()));
 
-        } else if (def.toLower().startsWith("icc-color")) {
+        } else if (def.startsWith("icc-color", Qt::CaseInsensitive)) {
             QStringList values = def.split(",");
             QString iccprofilename = values.first().split("(").last();
             values.removeFirst();
diff --git a/libs/resources/KisResourceModel.cpp b/libs/resources/KisResourceModel.cpp
index 9f15fa61646..71e2ec49979 100644
--- a/libs/resources/KisResourceModel.cpp
+++ b/libs/resources/KisResourceModel.cpp
@@ -1113,7 +1113,7 @@ bool KisResourceModel::lessThan(const QModelIndex &source_left, const QModelInde
     QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAbstractResourceModel::Name).toString();
     QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAbstractResourceModel::Name).toString();
 
-    return nameLeft.toLower() < nameRight.toLower();
+    return nameLeft.compare(nameRight, Qt::CaseInsensitive) < 0;
 }
 
 QVector<KoResourceSP> KisResourceModel::filterByColumn(const QString filter, KisAbstractResourceModel::Columns column) const
diff --git a/libs/resources/KisTagModel.cpp b/libs/resources/KisTagModel.cpp
index 2df9bc0a34e..f310fa44390 100644
--- a/libs/resources/KisTagModel.cpp
+++ b/libs/resources/KisTagModel.cpp
@@ -729,8 +729,8 @@ bool KisTagModel::lessThan(const QModelIndex &source_left, const QModelIndex &so
     } else if (rightIsFakeRow) {
         return false;
     } else {
-        QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAllTagsModel::Name).toString().toLower();
-        QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAllTagsModel::Name).toString().toLower();
-        return (nameLeft < nameRight);
+        QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAllTagsModel::Name).toString();
+        QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAllTagsModel::Name).toString();
+        return nameLeft.compare(nameRight, Qt::CaseInsensitive) < 0;
     }
 }
diff --git a/libs/resources/KisTagResourceModel.cpp b/libs/resources/KisTagResourceModel.cpp
index 675a07eeced..05d9dbd6f07 100644
--- a/libs/resources/KisTagResourceModel.cpp
+++ b/libs/resources/KisTagResourceModel.cpp
@@ -873,7 +873,7 @@ bool KisTagResourceModel::lessThan(const QModelIndex &source_left, const QModelI
 {
     QString nameLeft = sourceModel()->data(source_left, Qt::UserRole + KisAllTagResourceModel::ResourceName).toString();
     QString nameRight = sourceModel()->data(source_right, Qt::UserRole + KisAllTagResourceModel::ResourceName).toString();
-    return nameLeft.toLower() < nameRight.toLower();
+    return nameLeft.compare(nameRight, Qt::CaseInsensitive) < 0;
 }
 
 void KisTagResourceModel::storageChanged(const QString &location)


More information about the kimageshop mailing list