Mercurial > hg > svgui
view widgets/IconLoader.cpp @ 1614:c6f5c822b10d
Fix potential divide-by-zero (depending on a race elsewhere)
author | Chris Cannam |
---|---|
date | Tue, 30 Jun 2020 10:56:56 +0100 |
parents | 705d1d979ae4 |
children |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* Sonic Visualiser An audio file viewer and annotation editor. Centre for Digital Music, Queen Mary, University of London. This file copyright 2007 QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include "IconLoader.h" #include <QPixmap> #include <QApplication> #include <QPainter> #include <QPalette> #include <QFile> #include <QSvgRenderer> #include <QSettings> #include <QMutex> #include <QMutexLocker> #include <vector> #include <set> #include <map> #include "base/Debug.h" #include "base/Profiler.h" using namespace std; static set<QString> autoInvertExceptions { // These are the icons that look OK in their default colours, even // in a colour scheme with a black background. (They may also be // icons that would look worse if we tried to auto-invert them.) // If we have icons that look bad when auto-inverted but that are // not suitable for use without being inverted, we'll need to // supply inverted versions -- the loader will load xx_inverse.png // in preference to xx.png if a dark background is found.) "fileclose", "filenew", "fileopen", "fileopenaudio", "fileopensession", "filesave", "filesaveas", "filesaveas-sv", "help", "editcut", "editcopy", "editpaste", "editdelete", "exit", "zoom-fit", "zoom-in", "zoom-out", "zoom" }; QIcon IconLoader::load(QString name) { Profiler profiler("IconLoader::load"); static QMutex mutex; static map<QString, QIcon> icons; static const vector<int> sizes { 0, 16, 22, 24, 32, 48, 64, 128 }; QMutexLocker locker(&mutex); if (icons.find(name) != icons.end()) { return icons.at(name); } QIcon icon; for (int sz: sizes) { QPixmap pmap(loadPixmap(name, sz)); if (!pmap.isNull()) icon.addPixmap(pmap); } icons[name] = icon; return icon; } bool IconLoader::shouldInvert() const { QSettings settings; settings.beginGroup("IconLoader"); if (!settings.value("invert-icons-on-dark-background", true).toBool()) { return false; } QColor bg = QApplication::palette().window().color(); bool darkBackground = (bg.red() + bg.green() + bg.blue() <= 384); return darkBackground; } bool IconLoader::shouldAutoInvert(QString name) const { if (shouldInvert()) { return (autoInvertExceptions.find(name) == autoInvertExceptions.end()); } else { return false; } } QPixmap IconLoader::loadPixmap(QString name, int size) { bool invert = shouldInvert(); QString scalableName, nonScalableName; QPixmap pmap; // attempt to load a pixmap with the right size and inversion nonScalableName = makeNonScalableFilename(name, size, invert); pmap = QPixmap(nonScalableName); if (pmap.isNull() && size > 0) { // if that failed, load a scalable vector with the right // inversion and scale it scalableName = makeScalableFilename(name, invert); pmap = loadScalable(scalableName, size); } if (pmap.isNull() && invert) { // if that failed, and we were asking for an inverted pixmap, // that may mean we don't have an inverted version of it. We // could either auto-invert or use the uninverted version nonScalableName = makeNonScalableFilename(name, size, false); pmap = QPixmap(nonScalableName); if (pmap.isNull() && size > 0) { scalableName = makeScalableFilename(name, false); pmap = loadScalable(scalableName, size); } if (!pmap.isNull() && shouldAutoInvert(name)) { pmap = invertPixmap(pmap); } } return pmap; } QPixmap IconLoader::loadScalable(QString name, int size) { if (!QFile(name).exists()) { // cerr << "loadScalable: no such file as: \"" << name << "\"" << endl; return QPixmap(); } QPixmap pmap(size, size); pmap.fill(Qt::transparent); QSvgRenderer renderer(name); QPainter painter; painter.begin(&pmap); // cerr << "calling renderer for " << name << " at size " << size << "..." << endl; renderer.render(&painter); // cerr << "renderer completed" << endl; painter.end(); return pmap; } QString IconLoader::makeNonScalableFilename(QString name, int size, bool invert) { if (invert) { if (size == 0) { return QString(":icons/%1_inverse.png").arg(name); } else { return QString(":icons/%1-%2_inverse.png").arg(name).arg(size); } } else { if (size == 0) { return QString(":icons/%1.png").arg(name); } else { return QString(":icons/%1-%2.png").arg(name).arg(size); } } } QString IconLoader::makeScalableFilename(QString name, bool invert) { if (invert) { return QString(":icons/scalable/%1_inverse.svg").arg(name); } else { return QString(":icons/scalable/%1.svg").arg(name); } } QPixmap IconLoader::invertPixmap(QPixmap pmap) { // No suitable inverted icon found for black background; try to // auto-invert the default one QImage img = pmap.toImage().convertToFormat(QImage::Format_ARGB32); for (int y = 0; y < img.height(); ++y) { for (int x = 0; x < img.width(); ++x) { QRgb rgba = img.pixel(x, y); QColor colour = QColor (qRed(rgba), qGreen(rgba), qBlue(rgba), qAlpha(rgba)); int alpha = colour.alpha(); if (colour.saturation() < 5 && colour.alpha() > 10) { colour.setHsv(colour.hue(), colour.saturation(), 255 - colour.value()); colour.setAlpha(alpha); img.setPixel(x, y, colour.rgba()); } } } pmap = QPixmap::fromImage(img); return pmap; }