[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.19-706-ge5415e9

oliver at apple.com oliver at apple.com
Thu Feb 4 21:29:49 UTC 2010


The following commit has been merged in the webkit-1.1 branch:
commit 092f9a13cbe1324eb9076d41e43861418a2ba7a9
Author: oliver at apple.com <oliver at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Wed Jan 27 21:14:03 2010 +0000

    2010-01-27  Oliver Hunt  <oliver at apple.com>
    
            Reviewed by Simon Fraser.
    
            Animated scaling of background-image is too slow
            https://bugs.webkit.org/show_bug.cgi?id=33808
    
            Implement a version of the RenderImage animated scaling optimisation
            for background images.  Due to the possibility of arbitrary transforms
            being applied to containing elements we explicitly check the current
            CTM of the context for scaling or rotation.
    
            * platform/graphics/GraphicsContext.cpp:
            (WebCore::GraphicsContext::drawTiledImage):
            * platform/graphics/GraphicsContext.h:
            * platform/graphics/transforms/TransformationMatrix.h:
            (WebCore::TransformationMatrix::isIdentityOrTranslation):
            * rendering/RenderBoxModelObject.cpp:
            (WebCore::RenderBoxModelScaleData::RenderBoxModelScaleData):
            (WebCore::RenderBoxModelScaleData::~RenderBoxModelScaleData):
            (WebCore::RenderBoxModelScaleData::size):
            (WebCore::RenderBoxModelScaleData::time):
            (WebCore::RenderBoxModelScaleData::useLowQualityScale):
            (WebCore::RenderBoxModelScaleData::hiqhQualityRepaintTimer):
            (WebCore::RenderBoxModelScaleData::setSize):
            (WebCore::RenderBoxModelScaleData::setTime):
            (WebCore::RenderBoxModelScaleData::setUseLowQualityScale):
            (WebCore::RenderBoxModelScaleObserver::boxModelObjectDestroyed):
            (WebCore::RenderBoxModelScaleObserver::highQualityRepaintTimerFired):
            (WebCore::RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality):
            (WebCore::RenderBoxModelObject::highQualityRepaintTimerFired):
            (WebCore::RenderBoxModelObject::~RenderBoxModelObject):
            (WebCore::RenderBoxModelObject::paintFillLayerExtended):
            * rendering/RenderBoxModelObject.h:
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@53949 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 573a1ab..11c379b 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,38 @@
+2010-01-27  Oliver Hunt  <oliver at apple.com>
+
+        Reviewed by Simon Fraser.
+
+        Animated scaling of background-image is too slow
+        https://bugs.webkit.org/show_bug.cgi?id=33808
+
+        Implement a version of the RenderImage animated scaling optimisation
+        for background images.  Due to the possibility of arbitrary transforms
+        being applied to containing elements we explicitly check the current
+        CTM of the context for scaling or rotation.
+
+        * platform/graphics/GraphicsContext.cpp:
+        (WebCore::GraphicsContext::drawTiledImage):
+        * platform/graphics/GraphicsContext.h:
+        * platform/graphics/transforms/TransformationMatrix.h:
+        (WebCore::TransformationMatrix::isIdentityOrTranslation):
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelScaleData::RenderBoxModelScaleData):
+        (WebCore::RenderBoxModelScaleData::~RenderBoxModelScaleData):
+        (WebCore::RenderBoxModelScaleData::size):
+        (WebCore::RenderBoxModelScaleData::time):
+        (WebCore::RenderBoxModelScaleData::useLowQualityScale):
+        (WebCore::RenderBoxModelScaleData::hiqhQualityRepaintTimer):
+        (WebCore::RenderBoxModelScaleData::setSize):
+        (WebCore::RenderBoxModelScaleData::setTime):
+        (WebCore::RenderBoxModelScaleData::setUseLowQualityScale):
+        (WebCore::RenderBoxModelScaleObserver::boxModelObjectDestroyed):
+        (WebCore::RenderBoxModelScaleObserver::highQualityRepaintTimerFired):
+        (WebCore::RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality):
+        (WebCore::RenderBoxModelObject::highQualityRepaintTimerFired):
+        (WebCore::RenderBoxModelObject::~RenderBoxModelObject):
+        (WebCore::RenderBoxModelObject::paintFillLayerExtended):
+        * rendering/RenderBoxModelObject.h:
+
 2010-01-27  Yael Aharon  <yael.aharon at nokia.com>
 
         Reviewed by Laszlo Gombos.
diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp
index 652c1cb..8b412d6 100644
--- a/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -411,24 +411,35 @@ void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const
         restore();
 }
 
-void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op)
+void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op, bool useLowQualityScale)
 {
     if (paintingDisabled() || !image)
         return;
-
+    if (useLowQualityScale) {
+        save();
+        setImageInterpolationQuality(InterpolationLow);
+    }
     image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op);
+    if (useLowQualityScale)
+        restore();
 }
 
-void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op)
+void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op, bool useLowQualityScale)
 {
     if (paintingDisabled() || !image)
         return;
 
+    if (useLowQualityScale) {
+        save();
+        setImageInterpolationQuality(InterpolationLow);
+    }
     if (hRule == Image::StretchTile && vRule == Image::StretchTile)
         // Just do a scale.
-        return drawImage(image, styleColorSpace, dest, srcRect, op);
-
-    image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
+        drawImage(image, styleColorSpace, dest, srcRect, op);
+    else
+        image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op);
+    if (useLowQualityScale)
+        restore();
 }
 
 void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index 1946b97..443af3c 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -220,10 +220,10 @@ namespace WebCore {
         void drawImage(Image*, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1),
                        CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
         void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize,
-                       CompositeOperator = CompositeSourceOver);
+                       CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
         void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect,
                             Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile,
-                            CompositeOperator = CompositeSourceOver);
+                            CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
 
         void setImageInterpolationQuality(InterpolationQuality);
         InterpolationQuality imageInterpolationQuality() const;
diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h
index 787b3ab..cc8c8fa 100644
--- a/WebCore/platform/graphics/transforms/TransformationMatrix.h
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h
@@ -319,27 +319,27 @@ public:
     operator XFORM() const;
 #endif
 
+    bool isIdentityOrTranslation() const
+    {
+        return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0
+            && m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0
+            && m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0
+            && m_matrix[3][3] == 1;
+    }
+
 private:
     // multiply passed 2D point by matrix (assume z=0)
     void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
-    
+
     // multiply passed 3D point by matrix
     void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const;
-    
+
     void setMatrix(const Matrix4 m)
     {
         if (m && m != m_matrix)
             memcpy(m_matrix, m, sizeof(Matrix4));
     }
-    
-    bool isIdentityOrTranslation() const
-    {
-        return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 &&
-               m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 &&
-               m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 &&
-               m_matrix[3][3] == 1;
-    }
-    
+
     Matrix4 m_matrix;
 };
 
diff --git a/WebCore/rendering/RenderBoxModelObject.cpp b/WebCore/rendering/RenderBoxModelObject.cpp
index af94524..9cf1274 100644
--- a/WebCore/rendering/RenderBoxModelObject.cpp
+++ b/WebCore/rendering/RenderBoxModelObject.cpp
@@ -44,6 +44,134 @@ bool RenderBoxModelObject::s_wasFloating = false;
 bool RenderBoxModelObject::s_hadLayer = false;
 bool RenderBoxModelObject::s_layerWasSelfPainting = false;
 
+static const double cInterpolationCutoff = 800. * 800.;
+static const double cLowQualityTimeThreshold = 0.500; // 500 ms
+
+class RenderBoxModelScaleData : public Noncopyable {
+public:
+    RenderBoxModelScaleData(RenderBoxModelObject* object, const IntSize& size, double time, bool lowQualityScale)
+        : m_size(size)
+        , m_lastPaintTime(time)
+        , m_lowQualityScale(lowQualityScale)
+        , m_highQualityRepaintTimer(object, &RenderBoxModelObject::highQualityRepaintTimerFired)
+    {
+    }
+
+    ~RenderBoxModelScaleData()
+    {
+        m_highQualityRepaintTimer.stop();
+    }
+
+    Timer<RenderBoxModelObject>& hiqhQualityRepaintTimer() { return m_highQualityRepaintTimer; }
+
+    const IntSize& size() const { return m_size; }
+    void setSize(const IntSize& s) { m_size = s; }
+    double lastPaintTime() const { return m_lastPaintTime; }
+    void setLastPaintTime(double t) { m_lastPaintTime = t; }
+    bool useLowQualityScale() const { return m_lowQualityScale; }
+    void setUseLowQualityScale(bool b)
+    {
+        m_highQualityRepaintTimer.stop();
+        m_lowQualityScale = b;
+        if (b)
+            m_highQualityRepaintTimer.startOneShot(cLowQualityTimeThreshold);
+    }
+
+private:
+    IntSize m_size;
+    double m_lastPaintTime;
+    bool m_lowQualityScale;
+    Timer<RenderBoxModelObject> m_highQualityRepaintTimer;
+};
+
+class RenderBoxModelScaleObserver {
+public:
+    static bool shouldPaintBackgroundAtLowQuality(GraphicsContext*, RenderBoxModelObject*, Image*, const IntSize&);
+
+    static void boxModelObjectDestroyed(RenderBoxModelObject* object)
+    {
+        if (gBoxModelObjects) {
+            RenderBoxModelScaleData* data = gBoxModelObjects->take(object);
+            delete data;
+            if (!gBoxModelObjects->size()) {
+                delete gBoxModelObjects;
+                gBoxModelObjects = 0;
+            }
+        }
+    }
+
+    static void highQualityRepaintTimerFired(RenderBoxModelObject* object)
+    {
+        RenderBoxModelScaleObserver::boxModelObjectDestroyed(object);
+        object->repaint();
+    }
+
+    static HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* gBoxModelObjects;
+};
+
+bool RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(GraphicsContext* context, RenderBoxModelObject* object, Image* image, const IntSize& size)
+{
+    // If the image is not a bitmap image, then none of this is relevant and we just paint at high
+    // quality.
+    if (!image->isBitmapImage())
+        return false;
+
+    // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image
+    // is actually being scaled.
+    IntSize imageSize(image->width(), image->height());
+
+    // Look ourselves up in the hashtable.
+    RenderBoxModelScaleData* data = 0;
+    if (gBoxModelObjects)
+        data = gBoxModelObjects->get(object);
+
+    bool contextIsScaled = !context->getCTM().isIdentityOrTranslation();
+    if (!contextIsScaled && imageSize == size) {
+        // There is no scale in effect.  If we had a scale in effect before, we can just delete this data.
+        if (data) {
+            gBoxModelObjects->remove(object);
+            delete data;
+        }
+        return false;
+    }
+
+    // There is no need to hash scaled images that always use low quality mode when the page demands it.  This is the iChat case.
+    if (object->document()->page()->inLowQualityImageInterpolationMode()) {
+        double totalPixels = static_cast<double>(image->width()) * static_cast<double>(image->height());
+        if (totalPixels > cInterpolationCutoff)
+            return true;
+    }
+
+    // If there is no data yet, we will paint the first scale at high quality and record the paint time in case a second scale happens
+    // very soon.
+    if (!data) {
+        data = new RenderBoxModelScaleData(object, size, currentTime(), false);
+        if (!gBoxModelObjects)
+            gBoxModelObjects = new HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>;
+        gBoxModelObjects->set(object, data);
+        return false;
+    }
+
+    // We are scaled, but we painted already at this size, so just keep using whatever mode we last painted with.
+    if (!contextIsScaled && data->size() == size)
+        return data->useLowQualityScale();
+
+    // We have data and our size just changed.  If this change happened quickly, go into low quality mode and then set a repaint
+    // timer to paint in high quality mode.  Otherwise it is ok to just paint in high quality mode.
+    double newTime = currentTime();
+    data->setUseLowQualityScale(newTime - data->lastPaintTime() < cLowQualityTimeThreshold);
+    data->setLastPaintTime(newTime);
+    data->setSize(size);
+    return data->useLowQualityScale();
+}
+
+HashMap<RenderBoxModelObject*, RenderBoxModelScaleData*>* RenderBoxModelScaleObserver::gBoxModelObjects = 0;
+
+void RenderBoxModelObject::highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*)
+{
+    RenderBoxModelScaleObserver::highQualityRepaintTimerFired(this);
+}
+
 RenderBoxModelObject::RenderBoxModelObject(Node* node)
     : RenderObject(node)
     , m_layer(0)
@@ -55,6 +183,7 @@ RenderBoxModelObject::~RenderBoxModelObject()
     // Our layer should have been destroyed and cleared by now
     ASSERT(!hasLayer());
     ASSERT(!m_layer);
+    RenderBoxModelScaleObserver::boxModelObjectDestroyed(this);
 }
 
 void RenderBoxModelObject::destroyLayer()
@@ -307,6 +436,9 @@ int RenderBoxModelObject::paddingRight(bool) const
 void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& c, const FillLayer* bgLayer, int tx, int ty, int w, int h, InlineFlowBox* box, CompositeOperator op, RenderObject* backgroundObject)
 {
     GraphicsContext* context = paintInfo.context;
+    if (context->paintingDisabled())
+        return;
+
     bool includeLeftEdge = box ? box->includeLeftEdge() : true;
     bool includeRightEdge = box ? box->includeRightEdge() : true;
     int bLeft = includeLeftEdge ? borderLeft() : 0;
@@ -464,7 +596,9 @@ void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
             phase += destRect.location() - destOrigin;
             CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
             RenderObject* clientForBackgroundImage = backgroundObject ? backgroundObject : this;
-            context->drawTiledImage(bg->image(clientForBackgroundImage, tileSize), style()->colorSpace(), destRect, phase, tileSize, compositeOp);
+            Image* image = bg->image(clientForBackgroundImage, tileSize);
+            bool useLowQualityScaling = RenderBoxModelScaleObserver::shouldPaintBackgroundAtLowQuality(context, this, image, destRect.size());
+            context->drawTiledImage(image, style()->colorSpace(), destRect, phase, tileSize, compositeOp, useLowQualityScaling);
         }
     }
 
diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h
index fae866c..db7538d 100644
--- a/WebCore/rendering/RenderBoxModelObject.h
+++ b/WebCore/rendering/RenderBoxModelObject.h
@@ -98,6 +98,8 @@ public:
     // Called by RenderObject::destroy() (and RenderWidget::destroy()) and is the only way layers should ever be destroyed
     void destroyLayer();
 
+    void highQualityRepaintTimerFired(Timer<RenderBoxModelObject>*);
+
 protected:
     void calculateBackgroundImageGeometry(const FillLayer*, int tx, int ty, int w, int h, IntRect& destRect, IntPoint& phase, IntSize& tileSize);
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list