[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [calligra] krita: assistants: Cache rendering
From:       Geoffry Song <goffrie () gmail ! com>
Date:       2011-12-07 3:23:34
Message-ID: 20111207032334.084E3A60A9 () git ! kde ! org
[Download RAW message or body]

Git commit eb82fab9a76582b318902667665df3d8c61a95b6 by Geoffry Song.
Committed on 07/12/2011 at 04:15.
Pushed by geoffrysong into branch 'master'.

assistants: Cache rendering

This significantly improves performance using the QPainter backend,
as KisPaintingAssistant::drawPath is very expensive.

This also adds some caching to PerspectiveAssistant.

CCBUG: 280086

M  +21   -0    krita/plugins/assistants/RulerAssistant/Ellipse.cc
M  +1    -0    krita/plugins/assistants/RulerAssistant/Ellipse.h
M  +11   -6    krita/plugins/assistants/RulerAssistant/EllipseAssistant.cc
M  +3    -1    krita/plugins/assistants/RulerAssistant/EllipseAssistant.h
M  +59   -32   krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc
M  +11   -1    krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h
M  +2    -5    krita/plugins/assistants/RulerAssistant/RulerAssistant.cc
M  +2    -1    krita/plugins/assistants/RulerAssistant/RulerAssistant.h
M  +1    -5    krita/plugins/assistants/RulerAssistant/SplineAssistant.cc
M  +2    -1    krita/plugins/assistants/RulerAssistant/SplineAssistant.h
M  +4    -1    krita/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc
M  +73   -0    krita/ui/kis_painting_assistant.cc
M  +6    -1    krita/ui/kis_painting_assistant.h
M  +0    -2    krita/ui/kis_painting_assistants_manager.cc

http://commits.kde.org/calligra/eb82fab9a76582b318902667665df3d8c61a95b6

diff --git a/krita/plugins/assistants/RulerAssistant/Ellipse.cc \
b/krita/plugins/assistants/RulerAssistant/Ellipse.cc index 5bc7517..5042dbf 100644
--- a/krita/plugins/assistants/RulerAssistant/Ellipse.cc
+++ b/krita/plugins/assistants/RulerAssistant/Ellipse.cc
@@ -66,6 +66,27 @@ QPointF Ellipse::project(const QPointF& pt) const
 /*    return inverse.map(closest(matrix.map(pt)));*/
 }
 
+inline QPointF rotate90(const QPointF& p) {
+    return QPointF(p.y(), -p.x());
+}
+
+QRectF Ellipse::boundingRect() const
+{
+    const QPointF centre = (p1 + p2) * 0.5;
+    const QPointF d = rotate90((p2 - p1) * 0.5 * b / a);
+    const QPointF pts[4] = {
+        p1 + d,
+        p1 - d,
+        p2 + d,
+        p2 - d
+    };
+    QRectF ret;
+    for (int i = 0; i < 4; ++i) {
+        ret = ret.united(QRectF(pts[i], QSizeF(0.0001, 0.0001)));
+    }
+    return ret;
+}
+
 inline qreal sqrlength(const QPointF& vec)
 {
     return vec.x() * vec.x() + vec.y() * vec.y();
diff --git a/krita/plugins/assistants/RulerAssistant/Ellipse.h \
b/krita/plugins/assistants/RulerAssistant/Ellipse.h index 95142cb..b64e6bc 100644
--- a/krita/plugins/assistants/RulerAssistant/Ellipse.h
+++ b/krita/plugins/assistants/RulerAssistant/Ellipse.h
@@ -29,6 +29,7 @@ public:
     ~Ellipse();
     
     QPointF project(const QPointF&) const; // find a close point on the ellipse
+    QRectF boundingRect() const; // find an axis-aligned box bounding this ellipse \
(inexact)  
     bool set(const QPointF& m1, const QPointF& m2, const QPointF& p); // set all \
points  
diff --git a/krita/plugins/assistants/RulerAssistant/EllipseAssistant.cc \
b/krita/plugins/assistants/RulerAssistant/EllipseAssistant.cc index 7c88f41..45851f1 \
                100644
--- a/krita/plugins/assistants/RulerAssistant/EllipseAssistant.cc
+++ b/krita/plugins/assistants/RulerAssistant/EllipseAssistant.cc
@@ -46,26 +46,22 @@ QPointF EllipseAssistant::adjustPosition(const QPointF& pt, const \
QPointF& /*str  return project(pt);
 }
 
-void EllipseAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter *converter) +void EllipseAssistant::drawCache(QPainter& gc, \
const KisCoordinatesConverter *converter)  {
-    Q_UNUSED(updateRect);
     if (handles().size() < 2) return;
     QTransform initialTransform = converter->documentToWidgetTransform();
     if (handles().size() == 2) {
         // just draw the axis
-        gc.save();
         gc.setTransform(initialTransform);
         QPainterPath path;
         path.moveTo(*handles()[0]);
         path.lineTo(*handles()[1]);
         drawPath(gc, path);
-        gc.restore();
         return;
     }
     if (e.set(*handles()[0], *handles()[1], *handles()[2])) {
         // valid ellipse
 
-        gc.save();
         gc.setTransform(initialTransform);
         gc.setTransform(e.getInverse(), true);
         QPainterPath path;
@@ -74,7 +70,16 @@ void EllipseAssistant::drawAssistant(QPainter& gc, const QRectF& \
updateRect, con  // Draw the ellipse
         path.addEllipse(QPointF(0, 0), e.semiMajor(), e.semiMinor());
         drawPath(gc, path);
-        gc.restore();
+    }
+}
+
+QRect EllipseAssistant::boundingRect() const
+{
+    if (handles().size() != 3) return KisPaintingAssistant::boundingRect();
+    if (e.set(*handles()[0], *handles()[1], *handles()[2])) {
+        return e.boundingRect().adjusted(-2, -2, 2, 2).toAlignedRect();
+    } else {
+        return QRect();
     }
 }
 
diff --git a/krita/plugins/assistants/RulerAssistant/EllipseAssistant.h \
b/krita/plugins/assistants/RulerAssistant/EllipseAssistant.h index 3e55788..f6fd83b \
                100644
--- a/krita/plugins/assistants/RulerAssistant/EllipseAssistant.h
+++ b/krita/plugins/assistants/RulerAssistant/EllipseAssistant.h
@@ -28,9 +28,11 @@ class EllipseAssistant : public KisPaintingAssistant
 public:
     EllipseAssistant();
     virtual QPointF adjustPosition(const QPointF& point, const QPointF& \
                strokeBegin);
-    void drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter *converter);  virtual QPointF buttonPosition() const;
     virtual int numHandles() const { return 3; }
+protected:
+    virtual QRect boundingRect() const;
+    virtual void drawCache(QPainter& gc, const KisCoordinatesConverter *converter);
 private:
     QPointF project(const QPointF& pt) const;
     mutable Ellipse e;
diff --git a/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc \
b/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc index \
                36eef16..bd313a7 100644
--- a/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc
+++ b/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.cc
@@ -52,7 +52,8 @@ QPointF PerspectiveAssistant::project(const QPointF& pt, const \
QPointF& strokeBe  Q_ASSERT(handles().size() == 4);
     if (snapLine.isNull()) {
         QPolygonF poly;
-        if (!quad(poly)) return nullPoint;
+        QTransform transform;
+        if (!getTransform(poly, transform)) return nullPoint;
         // avoid problems with multiple assistants: only snap if starting in the \
                grid
         if (!poly.containsPoint(strokeBegin, Qt::OddEvenFill)) return nullPoint;
 
@@ -65,8 +66,6 @@ QPointF PerspectiveAssistant::project(const QPointF& pt, const \
QPointF& strokeBe  }
 
         // construct transformation
-        QTransform transform;
-        if (!QTransform::squareToQuad(poly, transform)) return nullPoint; // \
shouldn't happen  bool invertible;
         const QTransform inverse = transform.inverted(&invertible);
         if (!invertible) return nullPoint; // shouldn't happen
@@ -152,9 +151,8 @@ inline qreal inverseMaxLocalScale(const QTransform& transform)
 qreal PerspectiveAssistant::distance(const QPointF& pt) const
 {
     QPolygonF poly;
-    if (!quad(poly)) return 1.0;
     QTransform transform;
-    if (!QTransform::squareToQuad(poly, transform)) return 1.0;
+    if (!getTransform(poly, transform)) return 1.0;
     bool invertible;
     QTransform inverse = transform.inverted(&invertible);
     if (!invertible) return 1.0;
@@ -166,24 +164,41 @@ qreal PerspectiveAssistant::distance(const QPointF& pt) const
 }
 
 // draw a vanishing point marker
-inline QPainterPath drawX(QPainter& gc, const QPointF& pt)
+inline QPainterPath drawX(const QPointF& pt)
 {
-    Q_UNUSED(gc);
     QPainterPath path;
     path.moveTo(QPointF(pt.x() - 5.0, pt.y() - 5.0)); path.lineTo(QPointF(pt.x() + \
                5.0, pt.y() + 5.0));
     path.moveTo(QPointF(pt.x() - 5.0, pt.y() + 5.0)); path.lineTo(QPointF(pt.x() + \
5.0, pt.y() - 5.0));  return path;
 }
 
-void PerspectiveAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, \
const KisCoordinatesConverter *converter) +void \
PerspectiveAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter* converter, bool cached)  {
-    Q_UNUSED(updateRect);
-
+    gc.save();
+    gc.resetTransform();
     QTransform initialTransform = converter->documentToWidgetTransform();
     QPolygonF poly;
-    gc.save();
-    gc.setTransform(initialTransform);
-    if (!quad(poly)) {
+    QTransform transform; // unused, but computed for caching purposes
+    if (getTransform(poly, transform)) {
+        // draw vanishing points
+        QPointF intersection(0, 0);
+        if (QLineF(poly[0], poly[1]).intersect(QLineF(poly[2], poly[3]), \
&intersection) != QLineF::NoIntersection) { +            drawPath(gc, \
drawX(initialTransform.map(intersection))); +        }
+        if (QLineF(poly[1], poly[2]).intersect(QLineF(poly[3], poly[0]), \
&intersection) != QLineF::NoIntersection) { +            drawPath(gc, \
drawX(initialTransform.map(intersection))); +        }
+    }
+    gc.restore();
+    KisPaintingAssistant::drawAssistant(gc, updateRect, converter, cached);
+}
+
+void PerspectiveAssistant::drawCache(QPainter& gc, const KisCoordinatesConverter \
*converter) +{
+    gc.setTransform(converter->documentToWidgetTransform());
+    QPolygonF poly;
+    QTransform transform;
+    if (!getTransform(poly, transform)) {
         // color red for an invalid transform, but not for an incomplete one
         if(handles().size() == 4)
         {
@@ -194,17 +209,8 @@ void PerspectiveAssistant::drawAssistant(QPainter& gc, const \
QRectF& updateRect,  path.addPolygon(poly);
             drawPath(gc, path);
         }
-        gc.restore();
     } else {
         gc.setPen(QColor(0, 0, 0, 125));
-
-        QTransform transform;
-        if (!QTransform::squareToQuad(poly, transform)) {
-            qWarning("Failed to create perspective mapping");
-            // bail out
-            gc.restore();
-            return;
-        }
         gc.setTransform(transform, true);
         QPainterPath path;
         for (int y = 0; y <= 8; ++y)
@@ -218,16 +224,6 @@ void PerspectiveAssistant::drawAssistant(QPainter& gc, const \
QRectF& updateRect,  path.lineTo(QPointF(x * 0.125, 1.0));
         }
         drawPath(gc, path);
-        gc.restore();
-
-        // draw vanishing points
-        QPointF intersection(0, 0);
-        if (QLineF(poly[0], poly[1]).intersect(QLineF(poly[2], poly[3]), \
                &intersection) != QLineF::NoIntersection) {
-            drawPath(gc, drawX(gc, initialTransform.map(intersection)));
-        }
-        if (QLineF(poly[1], poly[2]).intersect(QLineF(poly[3], poly[0]), \
                &intersection) != QLineF::NoIntersection) {
-            drawPath(gc, drawX(gc, initialTransform.map(intersection)));
-        }
     }
 }
 
@@ -294,6 +290,37 @@ bool PerspectiveAssistant::quad(QPolygonF& poly) const
     return true;
 }
 
+bool PerspectiveAssistant::getTransform(QPolygonF& poly, QTransform& transform) \
const +{
+    if (cachedPolygon.size() != 0 && handles().size() == 4) {
+        for (int i = 0; i <= 4; ++i) {
+            if (i == 4) {
+                poly = cachedPolygon;
+                transform = cachedTransform;
+                return cacheValid;
+            }
+            if (cachedPoints[i] != *handles()[i]) break;
+        }
+    }
+    cachedPolygon.clear();
+    cacheValid = false;
+    if (!quad(poly)) {
+        cachedPolygon = poly;
+        return false;
+    }
+    if (!QTransform::squareToQuad(poly, transform)) {
+        qWarning("Failed to create perspective mapping");
+        return false;
+    }
+    for (int i = 0; i < 4; ++i) {
+        cachedPoints[i] = *handles()[i];
+    }
+    cachedPolygon = poly;
+    cachedTransform = transform;
+    cacheValid = true;
+    return true;
+}
+
 PerspectiveAssistantFactory::PerspectiveAssistantFactory()
 {
 }
diff --git a/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h \
b/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h index \
                19fea0e..c064d0b 100644
--- a/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h
+++ b/krita/plugins/assistants/RulerAssistant/PerspectiveAssistant.h
@@ -24,6 +24,7 @@
 #include <QObject>
 #include <QPolygonF>
 #include <QLineF>
+#include <QTransform>
 
 class PerspectiveAssistant : public KisPaintingAssistant, public \
KisAbstractPerspectiveGrid  {
@@ -31,19 +32,28 @@ public:
     PerspectiveAssistant();
     virtual QPointF adjustPosition(const QPointF& point, const QPointF& \
strokeBegin);  virtual void endStroke();
-    void drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter *converter);  virtual QPointF buttonPosition() const;
     virtual int numHandles() const { return 4; }
+    virtual void drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter* converter, bool cached = true);  
     virtual bool contains(const QPointF& point) const;
     virtual qreal distance(const QPointF& point) const;
+protected:
+    virtual void drawCache(QPainter& gc, const KisCoordinatesConverter *converter);
 private:
     QPointF project(const QPointF& pt, const QPointF& strokeBegin);
     // creates the convex hull, returns false if it's not a quadrilateral
     bool quad(QPolygonF& out) const;
+    // finds the transform from perspective coordinates (a unit square) to the \
document +    bool getTransform(QPolygonF& polyOut, QTransform& transformOut) const;
  
     // which direction to snap to (in transformed coordinates)
     QLineF snapLine;
+    // cached information
+    mutable QTransform cachedTransform;
+    mutable QPolygonF cachedPolygon;
+    mutable QPointF cachedPoints[4];
+    mutable bool cacheValid;
 };
 
 class PerspectiveAssistantFactory : public KisPaintingAssistantFactory
diff --git a/krita/plugins/assistants/RulerAssistant/RulerAssistant.cc \
b/krita/plugins/assistants/RulerAssistant/RulerAssistant.cc index 7cf6e25..4357a2b \
                100644
--- a/krita/plugins/assistants/RulerAssistant/RulerAssistant.cc
+++ b/krita/plugins/assistants/RulerAssistant/RulerAssistant.cc
@@ -72,24 +72,21 @@ inline double norm2(const QPointF& p)
     return sqrt(p.x() * p.x() + p.y() * p.y());
 }
 
-void RulerAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter *converter) +void RulerAssistant::drawCache(QPainter& gc, \
const KisCoordinatesConverter *converter)  {
-    Q_UNUSED(updateRect);
     if (handles().size() < 2) return;
 
     QTransform initialTransform = converter->documentToWidgetTransform();
 
-    // Draw the gradient
+    // Draw the line
     QPointF p1 = *handles()[0];
     QPointF p2 = *handles()[1];
 
-    gc.save();
     gc.setTransform(initialTransform);
     QPainterPath path;
     path.moveTo(p1);
     path.lineTo(p2);
     drawPath(gc, path);
-    gc.restore();
 }
 
 QPointF RulerAssistant::buttonPosition() const
diff --git a/krita/plugins/assistants/RulerAssistant/RulerAssistant.h \
b/krita/plugins/assistants/RulerAssistant/RulerAssistant.h index b5ce3b2..2dd0307 \
                100644
--- a/krita/plugins/assistants/RulerAssistant/RulerAssistant.h
+++ b/krita/plugins/assistants/RulerAssistant/RulerAssistant.h
@@ -27,9 +27,10 @@ class RulerAssistant : public KisPaintingAssistant
 public:
     RulerAssistant();
     virtual QPointF adjustPosition(const QPointF& point, const QPointF& \
                strokeBegin);
-    void drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter *converter);  virtual QPointF buttonPosition() const;
     virtual int numHandles() const { return 2; }
+protected:
+    virtual void drawCache(QPainter& gc, const KisCoordinatesConverter *converter);
 private:
     QPointF project(const QPointF& pt) const;
 };
diff --git a/krita/plugins/assistants/RulerAssistant/SplineAssistant.cc \
b/krita/plugins/assistants/RulerAssistant/SplineAssistant.cc index fee1f1d..7a1a2bb \
                100644
--- a/krita/plugins/assistants/RulerAssistant/SplineAssistant.cc
+++ b/krita/plugins/assistants/RulerAssistant/SplineAssistant.cc
@@ -87,9 +87,8 @@ QPointF SplineAssistant::adjustPosition(const QPointF& pt, const \
QPointF& /*stro  return project(pt);
 }
 
-void SplineAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter *converter) +void SplineAssistant::drawCache(QPainter& gc, \
const KisCoordinatesConverter *converter)  {
-    Q_UNUSED(updateRect);
     if (handles().size() < 2) return;
 
     QTransform initialTransform = converter->documentToWidgetTransform();
@@ -100,7 +99,6 @@ void SplineAssistant::drawAssistant(QPainter& gc, const QRectF& \
updateRect, cons  pts[2] = (handles().size() >= 3) ? (*handles()[2]) : \
                (*handles()[0]);
     pts[3] = (handles().size() >= 4) ? (*handles()[3]) : (handles().size() >= 3) ? \
(*handles()[2]) : (*handles()[1]);  
-    gc.save();
     gc.setTransform(initialTransform);
     gc.setPen(QColor(0, 0, 0, 75));
     // Draw control lines
@@ -112,8 +110,6 @@ void SplineAssistant::drawAssistant(QPainter& gc, const QRectF& \
updateRect, cons  path.moveTo(pts[0]);
     path.cubicTo(pts[2], pts[3], pts[1]);
     drawPath(gc, path);
-
-    gc.restore();
 }
 
 QPointF SplineAssistant::buttonPosition() const
diff --git a/krita/plugins/assistants/RulerAssistant/SplineAssistant.h \
b/krita/plugins/assistants/RulerAssistant/SplineAssistant.h index 8ed81f4..76fdfe4 \
                100644
--- a/krita/plugins/assistants/RulerAssistant/SplineAssistant.h
+++ b/krita/plugins/assistants/RulerAssistant/SplineAssistant.h
@@ -27,9 +27,10 @@ class SplineAssistant : public KisPaintingAssistant
 public:
     SplineAssistant();
     virtual QPointF adjustPosition(const QPointF& point, const QPointF& \
                strokeBegin);
-    void drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter *converter);  virtual QPointF buttonPosition() const;
     virtual int numHandles() const { return 4; }
+protected:
+    virtual void drawCache(QPainter& gc, const KisCoordinatesConverter *converter);
 private:
     QPointF project(const QPointF& pt) const;
 };
diff --git a/krita/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc \
b/krita/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc index \
                d450a84..b2f9d31 100644
--- a/krita/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc
+++ b/krita/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.cc
@@ -114,6 +114,7 @@ void KisRulerAssistantTool::mousePressEvent(KoPointerEvent \
*event)  }
         if (m_handleDrag) {
             if (event->modifiers() & Qt::ShiftModifier) {
+                m_handleDrag->uncache();
                 m_handleDrag = m_handleDrag->split()[0];
                 m_handles = m_canvas->view()->paintingAssistantManager()->handles();
             }
@@ -187,6 +188,7 @@ void KisRulerAssistantTool::mouseMoveEvent(KoPointerEvent *event)
     } else if(MOVE_CONDITION(event, KisTool::PAINT_MODE)) {
         if (m_handleDrag) {
             *m_handleDrag = event->point;
+            m_handleDrag->uncache();
 
             m_handleCombine = 0;
             if (!(event->modifiers() & Qt::ShiftModifier)) {
@@ -227,6 +229,7 @@ void KisRulerAssistantTool::mouseReleaseEvent(KoPointerEvent \
*event)  if (m_handleDrag) {
             if (!(event->modifiers() & Qt::ShiftModifier) && m_handleCombine) {
                 m_handleCombine->mergeWith(m_handleDrag);
+                m_handleCombine->uncache();
                 m_handles = m_canvas->view()->paintingAssistantManager()->handles();
             }
             m_handleDrag = m_handleCombine = 0;
@@ -248,7 +251,7 @@ void KisRulerAssistantTool::paint(QPainter& _gc, const \
KoViewConverter &_convert  QColor handlesColor(0, 0, 0, 125);
 
     if (m_newAssistant) {
-        m_newAssistant->drawAssistant(_gc, QRectF(QPointF(0, 0), \
QSizeF(m_canvas->image()->size())), m_canvas->coordinatesConverter()); +        \
m_newAssistant->drawAssistant(_gc, QRectF(QPointF(0, 0), \
                QSizeF(m_canvas->image()->size())), m_canvas->coordinatesConverter(), \
                false);
         foreach(const KisPaintingAssistantHandleSP handle, \
m_newAssistant->handles()) {  QPainterPath path;
             path.addEllipse(QRectF(_converter.documentToView(*handle) -  QPointF(6, \
                6), QSizeF(12, 12)));
diff --git a/krita/ui/kis_painting_assistant.cc b/krita/ui/kis_painting_assistant.cc
index db46c4c..a42beb9 100644
--- a/krita/ui/kis_painting_assistant.cc
+++ b/krita/ui/kis_painting_assistant.cc
@@ -18,11 +18,13 @@
  */
 
 #include "kis_painting_assistant.h"
+#include "kis_coordinates_converter.h"
 #include "kis_debug.h"
 
 #include <kglobal.h>
 #include <QPen>
 #include <QPainter>
+#include <QPixmapCache>
 
 struct KisPaintingAssistantHandle::Private {
     QList<KisPaintingAssistant*> assistants;
@@ -92,11 +94,28 @@ QList<KisPaintingAssistantHandleSP> \
KisPaintingAssistantHandle::split()  return newHandles;
 }
 
+void KisPaintingAssistantHandle::uncache()
+{
+    foreach(KisPaintingAssistant* assistant, d->assistants) {
+        assistant->uncache();
+    }
+}
+
 
 struct KisPaintingAssistant::Private {
     QString id;
     QString name;
     QList<KisPaintingAssistantHandleSP> handles;
+    QPixmapCache::Key cached;
+    QRect cachedRect; // relative to boundingRect().topLeft()
+    struct TranslationInvariantTransform {
+        qreal m11, m12, m21, m22;
+        TranslationInvariantTransform() { }
+        TranslationInvariantTransform(const QTransform& t) : m11(t.m11()), \
m12(t.m12()), m21(t.m21()), m22(t.m22()) { } +        bool operator==(const \
TranslationInvariantTransform& b) { +            return m11 == b.m11 && m12 == b.m12 \
&& m21 == b.m21 && m22 == b.m22; +        }
+    } cachedTransform;
 };
 
 KisPaintingAssistant::KisPaintingAssistant(const QString& id, const QString& name) : \
d(new Private) @@ -162,6 +181,60 @@ void \
KisPaintingAssistant::addHandle(KisPaintingAssistantHandleSP handle)  \
handle->registerAssistant(this);  }
 
+void KisPaintingAssistant::drawAssistant(QPainter& gc, const QRectF& updateRect, \
const KisCoordinatesConverter* converter, bool useCache) +{
+    Q_UNUSED(updateRect);
+
+    if (!useCache) {
+        gc.save();
+        drawCache(gc, converter);
+        gc.restore();
+        return;
+    }
+    const QRect bound = boundingRect();
+    if (bound.isEmpty()) return;
+    const QTransform transform = converter->documentToWidgetTransform();
+    const QRect widgetBound = transform.mapRect(bound);
+
+    const QRect paintRect = transform.mapRect(bound).intersected(gc.viewport());
+    if (paintRect.isEmpty()) return;
+
+    QPixmap cached;
+    if (!(QPixmapCache::find(d->cached, &cached) &&
+          d->cachedTransform == transform &&
+          d->cachedRect.translated(widgetBound.topLeft()).contains(paintRect))) {
+        const QRect cacheRect = gc.viewport().adjusted(-100, -100, 100, \
100).intersected(widgetBound); +        Q_ASSERT(!cacheRect.isEmpty());
+        if (cached.isNull() || cached.size() != cacheRect.size()) {
+            cached = QPixmap(cacheRect.size());
+        }
+        cached.fill(Qt::transparent);
+        QPainter painter(&cached);
+        painter.setRenderHint(QPainter::Antialiasing);
+        painter.setWindow(cacheRect);
+        drawCache(painter, converter);
+        painter.end();
+        d->cachedTransform = transform;
+        d->cachedRect = cacheRect.translated(-widgetBound.topLeft());
+        d->cached = QPixmapCache::insert(cached);
+    }
+    gc.drawPixmap(paintRect, cached, paintRect.translated(-widgetBound.topLeft() - \
d->cachedRect.topLeft())); +}
+
+void KisPaintingAssistant::uncache()
+{
+    d->cached = QPixmapCache::Key();
+}
+
+QRect KisPaintingAssistant::boundingRect() const
+{
+    QRectF r;
+    foreach (KisPaintingAssistantHandleSP h, handles()) {
+        r = r.united(QRectF(*h, QSizeF(1,1)));
+    }
+    return r.adjusted(-2, -2, 2, 2).toAlignedRect();
+}
+
 const QList<KisPaintingAssistantHandleSP>& KisPaintingAssistant::handles() const
 {
     return d->handles;
diff --git a/krita/ui/kis_painting_assistant.h b/krita/ui/kis_painting_assistant.h
index 16189bf..34757b4 100644
--- a/krita/ui/kis_painting_assistant.h
+++ b/krita/ui/kis_painting_assistant.h
@@ -21,6 +21,7 @@
 
 #include <QString>
 #include <QPointF>
+#include <QRect>
 
 #include <krita_export.h>
 #include <kis_shared.h>
@@ -52,6 +53,7 @@ public:
     ~KisPaintingAssistantHandle();
     void mergeWith(KisPaintingAssistantHandleSP);
     QList<KisPaintingAssistantHandleSP> split();
+    void uncache();
     KisPaintingAssistantHandle& operator=(const QPointF&);
 private:
     void registerAssistant(KisPaintingAssistant*);
@@ -80,11 +82,12 @@ public:
      */
     virtual QPointF adjustPosition(const QPointF& point, const QPointF& strokeBegin) \
= 0;  virtual void endStroke() { }
-    virtual void drawAssistant(QPainter& gc, const QRectF& updateRect, const \
KisCoordinatesConverter *converter) = 0;  virtual QPointF buttonPosition() const = 0;
     virtual int numHandles() const = 0;
     void replaceHandle(KisPaintingAssistantHandleSP _handle, \
KisPaintingAssistantHandleSP _with);  void addHandle(KisPaintingAssistantHandleSP \
handle); +    virtual void drawAssistant(QPainter& gc, const QRectF& updateRect, \
const KisCoordinatesConverter *converter, bool cached = true); +    void uncache();
     const QList<KisPaintingAssistantHandleSP>& handles() const;
     QList<KisPaintingAssistantHandleSP> handles();
 public:
@@ -93,6 +96,8 @@ public:
      */
     static void drawPath(QPainter& painter, const QPainterPath& path);
 protected:
+    virtual QRect boundingRect() const;
+    virtual void drawCache(QPainter& gc, const KisCoordinatesConverter *converter) = \
0;  void initHandles(QList<KisPaintingAssistantHandleSP> _handles);
 private:
     struct Private;
diff --git a/krita/ui/kis_painting_assistants_manager.cc \
b/krita/ui/kis_painting_assistants_manager.cc index aaa3cad..7a59ae4 100644
--- a/krita/ui/kis_painting_assistants_manager.cc
+++ b/krita/ui/kis_painting_assistants_manager.cc
@@ -116,9 +116,7 @@ void KisPaintingAssistantsManager::setup(KActionCollection * \
collection)  void KisPaintingAssistantsManager::drawDecoration(QPainter& gc, const \
QRectF& updateRect, const KisCoordinatesConverter *converter)  {
     foreach(KisPaintingAssistant* assistant, d->assistants) {
-        gc.save();
         assistant->drawAssistant(gc, updateRect, converter);
-        gc.restore();
     }
 }
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic