On Thursday 16 July 2009, Marco Martin wrote: > On Thursday 16 July 2009, Aaron J. Seigo wrote: > > On Thursday 16 July 2009, Marco Martin wrote: > > > but a sick idea come to my mind: what about encoding the pointer value > > > (or another random number, whatever) into the key? :p > > > a key will have the form > > > 7635865:path_300_200_blahblah > > > > how will this work between sessions? (new pointer values) > > between objects with the same svg at the same size? (should share the > > same cache values) > > tomorrow I'll try another approach: putting the delayed save in just Svg > and use that from FrameSvg, to avoid the code duplication there was before
here it is since i really didn't want to add new protected members i did this dirty thing with accessing svg private in framesvg.. it seems quite a big change to backport tough :) and still, in the case of an applet with many subwidgets, independent timers can do really a big signal storm, so i still kinda like more the pointer approach :p -- Marco Martin
Index: framesvg.cpp =================================================================== --- framesvg.cpp (revision 995762) +++ framesvg.cpp (working copy) @@ -20,6 +20,7 @@ #include "framesvg.h" #include "private/framesvg_p.h" +#include "private/svg_p.h" #include <QPainter> #include <QSize> @@ -621,13 +622,13 @@ //kDebug()<<"Saving to cache frame"<<id; - Theme::defaultTheme()->insertIntoCache(id, frame->cachedBackground); + static_cast<Svg *>(q)->d->insertIntoCacheDelayed(id, prefixToSave, frame->cachedBackground); //insert overlay id = QString::fromLatin1("overlay_%7_%6_%5_%4_%3_%2_%1_"). arg(overlayPos.y()).arg(overlayPos.x()).arg(frame->enabledBorders).arg(size.width()).arg(size.height()).arg(prefixToSave).arg(q->imagePath()); - Theme::defaultTheme()->insertIntoCache(id, frame->cachedBackground); + static_cast<Svg *>(q)->d->insertIntoCacheDelayed(id, prefixToSave+"overlay", frame->cachedBackground); } void FrameSvgPrivate::updateSizes() Index: svg.h =================================================================== --- svg.h (revision 995762) +++ svg.h (working copy) @@ -62,6 +62,8 @@ Q_PROPERTY(QString imagePath READ imagePath WRITE setImagePath) Q_PROPERTY(bool usingRenderingCache READ isUsingRenderingCache WRITE setUsingRenderingCache) + friend class FrameSvg; + public: /** * Constructs an SVG object that implicitly shares and caches rendering Index: private/svg_p.h =================================================================== --- private/svg_p.h (revision 0) +++ private/svg_p.h (revision 0) @@ -0,0 +1,449 @@ +/* + * Copyright 2006-2007 Aaron Seigo <ase...@kde.org> + * Copyright 2008-2009 Marco Martin <notm...@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SVG_P_H +#define SVG_P_H + + +#include <QDir> +#include <QMatrix> +#include <QPainter> +#include <QSharedData> +#include <QTimer> + +#include <kcolorscheme.h> +#include <kconfiggroup.h> +#include <kdebug.h> +#include <kiconeffect.h> +#include <kglobalsettings.h> +#include <ksharedptr.h> +#include <ksvgrenderer.h> + +#include "plasma/applet.h" +#include "plasma/package.h" +#include "plasma/theme.h" +#include "plasma/svg.h" + +namespace Plasma +{ + +class SharedSvgRenderer : public KSvgRenderer, public QSharedData +{ + public: + typedef KSharedPtr<SharedSvgRenderer> Ptr; + + SharedSvgRenderer(QObject *parent = 0) + : KSvgRenderer(parent) + {} + + SharedSvgRenderer(const QString &filename, QObject *parent = 0) + : KSvgRenderer(filename, parent) + {} + + SharedSvgRenderer(const QByteArray &contents, QObject *parent = 0) + : KSvgRenderer(contents, parent) + {} + + ~SharedSvgRenderer() + { + //kDebug() << "leaving this world for a better one."; + } +}; + +class SvgPrivate +{ + public: + SvgPrivate(Svg *svg) + : q(svg), + theme(0), + renderer(0), + lastModified(0), + multipleImages(false), + themed(false), + applyColors(false), + cacheRendering(true) + { + saveTimer = new QTimer(q); + saveTimer->setSingleShot(true); + QObject::connect(saveTimer, SIGNAL(timeout()), q, SLOT(scheduledCacheUpdate())); + } + + ~SvgPrivate() + { + eraseRenderer(); + } + + //This function is meant for the rects cache + QString cacheId(const QString &elementId) + { + if (size.isValid() && size != naturalSize) { + return QString("%3_%2_%1").arg(int(size.height())) + .arg(int(size.width())) + .arg(elementId); + } else { + return QString("%2_%1").arg("Natural") + .arg(elementId); + } + } + + //This function is meant for the pixmap cache + QString cachePath(const QString &path, const QSize &size) + { + return QString("%3_%2_%1_").arg(int(size.height())) + .arg(int(size.width())) + .arg(path); + } + + bool setImagePath(const QString &imagePath) + { + bool isThemed = !QDir::isAbsolutePath(imagePath); + + // lets check to see if we're already set to this file + if (isThemed == themed && + ((themed && themePath == imagePath) || + (!themed && path == imagePath))) { + return false; + } + + // if we don't have any path right now and are going to set one, + // then lets not schedule a repaint because we are just initializing! + bool updateNeeded = true; //!path.isEmpty() || !themePath.isEmpty(); + + if (themed) { + QObject::disconnect(actualTheme(), SIGNAL(themeChanged()), + q, SLOT(themeChanged())); + } + + themed = isThemed; + path.clear(); + themePath.clear(); + localRectCache.clear(); + + if (themed) { + themePath = imagePath; + QObject::connect(actualTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged())); + } else if (QFile::exists(imagePath)) { + path = imagePath; + } else { + kDebug() << "file '" << path << "' does not exist!"; + } + + // check if svg wants colorscheme applied + QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), + q, SLOT(colorsChanged())); + + checkApplyColorHint(); + if (applyColors && !actualTheme()->colorScheme()) { + QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), + q, SLOT(colorsChanged())); + } + + // also images with absolute path needs to have a natural size initialized, + // even if looks a bit weird using Theme to store non-themed stuff + if (themed || QFile::exists(imagePath)) { + QRectF rect; + bool found = actualTheme()->findInRectsCache(path, "_Natural", rect); + + if (!found) { + createRenderer(); + naturalSize = renderer->defaultSize(); + //kDebug() << "natural size for" << path << "from renderer is" << naturalSize; + actualTheme()->insertIntoRectsCache(path, "_Natural", QRectF(QPointF(0,0), naturalSize)); + } else { + naturalSize = rect.size(); + //kDebug() << "natural size for" << path << "from cache is" << naturalSize; + } + } + + if (!themed) { + QFile f(imagePath); + QFileInfo info(f); + lastModified = info.lastModified().toTime_t(); + } + + return updateNeeded; + } + + Theme *actualTheme() + { + if (!theme) { + theme = Plasma::Theme::defaultTheme(); + } + + return theme; + } + + QPixmap findInCache(const QString &elementId, const QSizeF &s = QSizeF()) + { + QSize size; + if (elementId.isEmpty() || (multipleImages && s.isValid())) { + size = s.toSize(); + } else { + size = elementRect(elementId).size().toSize(); + } + + if (size.isEmpty()) { + return QPixmap(); + } + + QString id = cachePath(path, size); + + if (!elementId.isEmpty()) { + id.append(elementId); + } + + //kDebug() << "id is " << id; + + QPixmap p; + if (cacheRendering) { + if (actualTheme()->findInCache(id, p, lastModified)) { + //kDebug() << "found cached version of " << id << p.size(); + return p; + } + } + + //kDebug() << "didn't find cached version of " << id << ", so re-rendering"; + + //kDebug() << "size for " << elementId << " is " << s; + // we have to re-render this puppy + + p = QPixmap(size); + + p.fill(Qt::transparent); + QPainter renderPainter(&p); + + createRenderer(); + if (elementId.isEmpty()) { + renderer->render(&renderPainter); + } else { + renderer->render(&renderPainter, elementId); + } + + renderPainter.end(); + + // Apply current color scheme if the svg asks for it + if (applyColors) { + QImage itmp = p.toImage(); + KIconEffect::colorize(itmp, actualTheme()->color(Theme::BackgroundColor), 1.0); + p = p.fromImage(itmp); + } + + if (cacheRendering) { + insertIntoCacheDelayed(id, elementId, p); + } + + return p; + } + + void createRenderer() + { + if (renderer) { + return; + } + + //kDebug() << kBacktrace(); + if (themed && path.isEmpty()) { + Applet *applet = qobject_cast<Applet*>(q->parent()); + if (applet && applet->package()) { + path = applet->package()->filePath("images", themePath + ".svg"); + + if (path.isEmpty()) { + path = applet->package()->filePath("images", themePath + ".svgz"); + } + } + + if (path.isEmpty()) { + path = actualTheme()->imagePath(themePath); + if (path.isEmpty()) { + kWarning() << "No image path found for" << themePath; + } + } + } + + //kDebug() << "********************************"; + //kDebug() << "FAIL! **************************"; + //kDebug() << path << "**"; + + QHash<QString, SharedSvgRenderer::Ptr>::const_iterator it = s_renderers.constFind(path); + + if (it != s_renderers.constEnd()) { + //kDebug() << "gots us an existing one!"; + renderer = it.value(); + } else { + if (path.isEmpty()) + renderer = new SharedSvgRenderer(); + else + renderer = new SharedSvgRenderer(path); + s_renderers[path] = renderer; + } + + if (size == QSizeF()) { + size = renderer->defaultSize(); + } + } + + void eraseRenderer() + { + if (renderer && renderer.count() == 2) { + // this and the cache reference it + s_renderers.erase(s_renderers.find(path)); + + if (theme) { + theme->releaseRectsCache(path); + } + } + + renderer = 0; + localRectCache.clear(); + } + + QRectF elementRect(const QString &elementId) + { + if (themed && path.isEmpty()) { + path = actualTheme()->imagePath(themePath); + } + + QString id = cacheId(elementId); + if (localRectCache.contains(id)) { + return localRectCache.value(id); + } + + QRectF rect; + bool found = actualTheme()->findInRectsCache(path, id, rect); + + if (found) { + localRectCache.insert(id, rect); + return rect; + } + + return findAndCacheElementRect(elementId); + } + + QRectF findAndCacheElementRect(const QString &elementId) + { + createRenderer(); + QRectF elementRect = renderer->elementExists(elementId) ? + renderer->boundsOnElement(elementId) : QRectF(); + naturalSize = renderer->defaultSize(); + //kDebug() << "natural size for" << path << "is" << naturalSize; + qreal dx = size.width() / naturalSize.width(); + qreal dy = size.height() / naturalSize.height(); + + elementRect = QRectF(elementRect.x() * dx, elementRect.y() * dy, + elementRect.width() * dx, elementRect.height() * dy); + + actualTheme()->insertIntoRectsCache(path, cacheId(elementId), elementRect); + return elementRect; + } + + QMatrix matrixForElement(const QString &elementId) + { + createRenderer(); + return renderer->matrixForElement(elementId); + } + + void checkApplyColorHint() + { + applyColors = elementRect("hint-apply-color-scheme").isValid(); + } + + void themeChanged() + { + // check if new theme svg wants colorscheme applied + bool wasApplyColors = applyColors; + checkApplyColorHint(); + if (applyColors && actualTheme()->colorScheme()) { + if (!wasApplyColors) { + QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), + q, SLOT(colorsChanged())); + } + } else { + QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), + q, SLOT(colorsChanged())); + } + + if (!themed) { + return; + } + + QString currentPath = themePath; + themePath.clear(); + eraseRenderer(); + setImagePath(currentPath); + + //kDebug() << themePath << ">>>>>>>>>>>>>>>>>> theme changed"; + emit q->repaintNeeded(); + } + + void colorsChanged() + { + if (!applyColors) { + return; + } + + eraseRenderer(); + //kDebug() << "repaint needed from colorsChanged"; + emit q->repaintNeeded(); + } + + void insertIntoCacheDelayed(const QString& key, const QString& id, const QPixmap& pix) + { + if (cacheRendering) { + pixmapsToCache.insert(id, QPair<QString, QPixmap>(key, pix)); + saveTimer->start(600); + } + } + + void scheduledCacheUpdate() + { + //kDebug()<< "Saving to cache:"; + QHash<QString, QPair<QString, QPixmap> >::const_iterator it = pixmapsToCache.constBegin(); + + while (it != pixmapsToCache.constEnd()) { + //kDebug()<< "Saving item to cache: " << it.key(); + actualTheme()->insertIntoCache(it.value().first, it.value().second); + ++it; + } + + pixmapsToCache.clear(); + } + + static QHash<QString, SharedSvgRenderer::Ptr> s_renderers; + + Svg *q; + QPointer<Theme> theme; + QHash<QString, QRectF> localRectCache; + SharedSvgRenderer::Ptr renderer; + QString themePath; + QString path; + QSizeF size; + QSizeF naturalSize; + QHash<QString, QPair<QString, QPixmap> > pixmapsToCache; + QTimer *saveTimer; + unsigned int lastModified; + bool multipleImages : 1; + bool themed : 1; + bool applyColors : 1; + bool cacheRendering : 1; +}; + +} + +#endif Index: svg.cpp =================================================================== --- svg.cpp (revision 995762) +++ svg.cpp (working copy) @@ -18,11 +18,13 @@ */ #include "svg.h" +#include "private/svg_p.h" #include <QDir> #include <QMatrix> #include <QPainter> #include <QSharedData> +#include <QTimer> #include <kcolorscheme.h> #include <kconfiggroup.h> @@ -39,379 +41,6 @@ namespace Plasma { -class SharedSvgRenderer : public KSvgRenderer, public QSharedData -{ - public: - typedef KSharedPtr<SharedSvgRenderer> Ptr; - - SharedSvgRenderer(QObject *parent = 0) - : KSvgRenderer(parent) - {} - - SharedSvgRenderer(const QString &filename, QObject *parent = 0) - : KSvgRenderer(filename, parent) - {} - - SharedSvgRenderer(const QByteArray &contents, QObject *parent = 0) - : KSvgRenderer(contents, parent) - {} - - ~SharedSvgRenderer() - { - //kDebug() << "leaving this world for a better one."; - } -}; - -class SvgPrivate -{ - public: - SvgPrivate(Svg *svg) - : q(svg), - theme(0), - renderer(0), - lastModified(0), - multipleImages(false), - themed(false), - applyColors(false), - cacheRendering(true) - { - } - - ~SvgPrivate() - { - eraseRenderer(); - } - - //This function is meant for the rects cache - QString cacheId(const QString &elementId) - { - if (size.isValid() && size != naturalSize) { - return QString("%3_%2_%1").arg(int(size.height())) - .arg(int(size.width())) - .arg(elementId); - } else { - return QString("%2_%1").arg("Natural") - .arg(elementId); - } - } - - //This function is meant for the pixmap cache - QString cachePath(const QString &path, const QSize &size) - { - return QString("%3_%2_%1_").arg(int(size.height())) - .arg(int(size.width())) - .arg(path); - } - - bool setImagePath(const QString &imagePath) - { - bool isThemed = !QDir::isAbsolutePath(imagePath); - - // lets check to see if we're already set to this file - if (isThemed == themed && - ((themed && themePath == imagePath) || - (!themed && path == imagePath))) { - return false; - } - - // if we don't have any path right now and are going to set one, - // then lets not schedule a repaint because we are just initializing! - bool updateNeeded = true; //!path.isEmpty() || !themePath.isEmpty(); - - if (themed) { - QObject::disconnect(actualTheme(), SIGNAL(themeChanged()), - q, SLOT(themeChanged())); - } - - themed = isThemed; - path.clear(); - themePath.clear(); - localRectCache.clear(); - - if (themed) { - themePath = imagePath; - QObject::connect(actualTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged())); - } else if (QFile::exists(imagePath)) { - path = imagePath; - } else { - kDebug() << "file '" << path << "' does not exist!"; - } - - // check if svg wants colorscheme applied - QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), - q, SLOT(colorsChanged())); - - checkApplyColorHint(); - if (applyColors && !actualTheme()->colorScheme()) { - QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), - q, SLOT(colorsChanged())); - } - - // also images with absolute path needs to have a natural size initialized, - // even if looks a bit weird using Theme to store non-themed stuff - if (themed || QFile::exists(imagePath)) { - QRectF rect; - bool found = actualTheme()->findInRectsCache(path, "_Natural", rect); - - if (!found) { - createRenderer(); - naturalSize = renderer->defaultSize(); - //kDebug() << "natural size for" << path << "from renderer is" << naturalSize; - actualTheme()->insertIntoRectsCache(path, "_Natural", QRectF(QPointF(0,0), naturalSize)); - } else { - naturalSize = rect.size(); - //kDebug() << "natural size for" << path << "from cache is" << naturalSize; - } - } - - if (!themed) { - QFile f(imagePath); - QFileInfo info(f); - lastModified = info.lastModified().toTime_t(); - } - - return updateNeeded; - } - - Theme *actualTheme() - { - if (!theme) { - theme = Plasma::Theme::defaultTheme(); - } - - return theme; - } - - QPixmap findInCache(const QString &elementId, const QSizeF &s = QSizeF()) - { - QSize size; - if (elementId.isEmpty() || (multipleImages && s.isValid())) { - size = s.toSize(); - } else { - size = elementRect(elementId).size().toSize(); - } - - if (size.isEmpty()) { - return QPixmap(); - } - - QString id = cachePath(path, size); - - if (!elementId.isEmpty()) { - id.append(elementId); - } - - //kDebug() << "id is " << id; - - QPixmap p; - if (cacheRendering) { - if (actualTheme()->findInCache(id, p, lastModified)) { - //kDebug() << "found cached version of " << id << p.size(); - return p; - } - } - - //kDebug() << "didn't find cached version of " << id << ", so re-rendering"; - - //kDebug() << "size for " << elementId << " is " << s; - // we have to re-render this puppy - - p = QPixmap(size); - - p.fill(Qt::transparent); - QPainter renderPainter(&p); - - createRenderer(); - if (elementId.isEmpty()) { - renderer->render(&renderPainter); - } else { - renderer->render(&renderPainter, elementId); - } - - renderPainter.end(); - - // Apply current color scheme if the svg asks for it - if (applyColors) { - QImage itmp = p.toImage(); - KIconEffect::colorize(itmp, actualTheme()->color(Theme::BackgroundColor), 1.0); - p = p.fromImage(itmp); - } - - if (cacheRendering) { - actualTheme()->insertIntoCache(id, p); - } - - return p; - } - - void createRenderer() - { - if (renderer) { - return; - } - - //kDebug() << kBacktrace(); - if (themed && path.isEmpty()) { - Applet *applet = qobject_cast<Applet*>(q->parent()); - if (applet && applet->package()) { - path = applet->package()->filePath("images", themePath + ".svg"); - - if (path.isEmpty()) { - path = applet->package()->filePath("images", themePath + ".svgz"); - } - } - - if (path.isEmpty()) { - path = actualTheme()->imagePath(themePath); - if (path.isEmpty()) { - kWarning() << "No image path found for" << themePath; - } - } - } - - //kDebug() << "********************************"; - //kDebug() << "FAIL! **************************"; - //kDebug() << path << "**"; - - QHash<QString, SharedSvgRenderer::Ptr>::const_iterator it = s_renderers.constFind(path); - - if (it != s_renderers.constEnd()) { - //kDebug() << "gots us an existing one!"; - renderer = it.value(); - } else { - if (path.isEmpty()) - renderer = new SharedSvgRenderer(); - else - renderer = new SharedSvgRenderer(path); - s_renderers[path] = renderer; - } - - if (size == QSizeF()) { - size = renderer->defaultSize(); - } - } - - void eraseRenderer() - { - if (renderer && renderer.count() == 2) { - // this and the cache reference it - s_renderers.erase(s_renderers.find(path)); - - if (theme) { - theme->releaseRectsCache(path); - } - } - - renderer = 0; - localRectCache.clear(); - } - - QRectF elementRect(const QString &elementId) - { - if (themed && path.isEmpty()) { - path = actualTheme()->imagePath(themePath); - } - - QString id = cacheId(elementId); - if (localRectCache.contains(id)) { - return localRectCache.value(id); - } - - QRectF rect; - bool found = actualTheme()->findInRectsCache(path, id, rect); - - if (found) { - localRectCache.insert(id, rect); - return rect; - } - - return findAndCacheElementRect(elementId); - } - - QRectF findAndCacheElementRect(const QString &elementId) - { - createRenderer(); - QRectF elementRect = renderer->elementExists(elementId) ? - renderer->boundsOnElement(elementId) : QRectF(); - naturalSize = renderer->defaultSize(); - //kDebug() << "natural size for" << path << "is" << naturalSize; - qreal dx = size.width() / naturalSize.width(); - qreal dy = size.height() / naturalSize.height(); - - elementRect = QRectF(elementRect.x() * dx, elementRect.y() * dy, - elementRect.width() * dx, elementRect.height() * dy); - - actualTheme()->insertIntoRectsCache(path, cacheId(elementId), elementRect); - return elementRect; - } - - QMatrix matrixForElement(const QString &elementId) - { - createRenderer(); - return renderer->matrixForElement(elementId); - } - - void checkApplyColorHint() - { - applyColors = elementRect("hint-apply-color-scheme").isValid(); - } - - void themeChanged() - { - // check if new theme svg wants colorscheme applied - bool wasApplyColors = applyColors; - checkApplyColorHint(); - if (applyColors && actualTheme()->colorScheme()) { - if (!wasApplyColors) { - QObject::connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), - q, SLOT(colorsChanged())); - } - } else { - QObject::disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), - q, SLOT(colorsChanged())); - } - - if (!themed) { - return; - } - - QString currentPath = themePath; - themePath.clear(); - eraseRenderer(); - setImagePath(currentPath); - - //kDebug() << themePath << ">>>>>>>>>>>>>>>>>> theme changed"; - emit q->repaintNeeded(); - } - - void colorsChanged() - { - if (!applyColors) { - return; - } - - eraseRenderer(); - //kDebug() << "repaint needed from colorsChanged"; - emit q->repaintNeeded(); - } - - static QHash<QString, SharedSvgRenderer::Ptr> s_renderers; - - Svg *q; - QPointer<Theme> theme; - QHash<QString, QRectF> localRectCache; - SharedSvgRenderer::Ptr renderer; - QString themePath; - QString path; - QSizeF size; - QSizeF naturalSize; - unsigned int lastModified; - bool multipleImages : 1; - bool themed : 1; - bool applyColors : 1; - bool cacheRendering : 1; -}; - QHash<QString, SharedSvgRenderer::Ptr> SvgPrivate::s_renderers; Svg::Svg(QObject *parent)
_______________________________________________ Plasma-devel mailing list Plasma-devel@kde.org https://mail.kde.org/mailman/listinfo/plasma-devel