Title: [117858] trunk/Source/WebCore
Revision
117858
Author
[email protected]
Date
2012-05-21 17:28:58 -0700 (Mon, 21 May 2012)

Log Message

GeneratorGeneratedImage should cache intermediate images
https://bugs.webkit.org/show_bug.cgi?id=86906
<rdar://problem/11484852>

Reviewed by Dean Jackson.

Cache generated images in GeneratorGeneratedImage. The cache is invalidated:
    a) if the Generator's hash changes.
    b) if the rendered size changes.
    c) if the cached image is incompatible with the destination context (acceleration state or CTM scale).
    d) after one second of disuse.

Add a hash() function to Generator, which should be implemented in subclasses
to provide a straightforward way to determine if Generators have been mutated
in a way that will affect the resultant rendering.

No new tests, performance optimization. Correctness is covered by the multitude of existing gradient tests.

* platform/graphics/Generator.h:
(Generator):
* platform/graphics/GeneratorGeneratedImage.cpp:
(WebCore::GeneratorGeneratedImage::drawPattern):
* platform/graphics/GeneratorGeneratedImage.h:
(WebCore):
(GeneratorGeneratedImage):
(WebCore::GeneratorGeneratedImage::~GeneratorGeneratedImage):
(WebCore::GeneratorGeneratedImage::GeneratorGeneratedImage):
(GeneratedImageCacheTimer):
(WebCore::GeneratorGeneratedImage::GeneratedImageCacheTimer::GeneratedImageCacheTimer):
(WebCore::GeneratorGeneratedImage::GeneratedImageCacheTimer::restart):
* platform/graphics/Gradient.cpp:
(WebCore::Gradient::Gradient):
(WebCore::Gradient::addColorStop):
(WebCore::Gradient::sortStopsIfNecessary):
(WebCore::Gradient::setSpreadMethod):
(WebCore::Gradient::setGradientSpaceTransform):
(WebCore::Gradient::hash):
* platform/graphics/Gradient.h:
(WebCore::Gradient::setP0):
(WebCore::Gradient::setP1):
(WebCore::Gradient::setStartRadius):
(WebCore::Gradient::setEndRadius):
(Gradient):
(WebCore::Gradient::clearHashCache):
* platform/graphics/GraphicsContext.cpp:
(WebCore::GraphicsContext::isCompatibleWithBuffer):
(WebCore):
* platform/graphics/GraphicsContext.h:
(GraphicsContext):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (117857 => 117858)


--- trunk/Source/WebCore/ChangeLog	2012-05-22 00:27:09 UTC (rev 117857)
+++ trunk/Source/WebCore/ChangeLog	2012-05-22 00:28:58 UTC (rev 117858)
@@ -1,3 +1,55 @@
+2012-05-21  Tim Horton  <[email protected]>
+
+        GeneratorGeneratedImage should cache intermediate images
+        https://bugs.webkit.org/show_bug.cgi?id=86906
+        <rdar://problem/11484852>
+
+        Reviewed by Dean Jackson.
+
+        Cache generated images in GeneratorGeneratedImage. The cache is invalidated:
+            a) if the Generator's hash changes.
+            b) if the rendered size changes.
+            c) if the cached image is incompatible with the destination context (acceleration state or CTM scale).
+            d) after one second of disuse.
+
+        Add a hash() function to Generator, which should be implemented in subclasses
+        to provide a straightforward way to determine if Generators have been mutated
+        in a way that will affect the resultant rendering.
+
+        No new tests, performance optimization. Correctness is covered by the multitude of existing gradient tests.
+
+        * platform/graphics/Generator.h:
+        (Generator):
+        * platform/graphics/GeneratorGeneratedImage.cpp:
+        (WebCore::GeneratorGeneratedImage::drawPattern):
+        * platform/graphics/GeneratorGeneratedImage.h:
+        (WebCore):
+        (GeneratorGeneratedImage):
+        (WebCore::GeneratorGeneratedImage::~GeneratorGeneratedImage):
+        (WebCore::GeneratorGeneratedImage::GeneratorGeneratedImage):
+        (GeneratedImageCacheTimer):
+        (WebCore::GeneratorGeneratedImage::GeneratedImageCacheTimer::GeneratedImageCacheTimer):
+        (WebCore::GeneratorGeneratedImage::GeneratedImageCacheTimer::restart):
+        * platform/graphics/Gradient.cpp:
+        (WebCore::Gradient::Gradient):
+        (WebCore::Gradient::addColorStop):
+        (WebCore::Gradient::sortStopsIfNecessary):
+        (WebCore::Gradient::setSpreadMethod):
+        (WebCore::Gradient::setGradientSpaceTransform):
+        (WebCore::Gradient::hash):
+        * platform/graphics/Gradient.h:
+        (WebCore::Gradient::setP0):
+        (WebCore::Gradient::setP1):
+        (WebCore::Gradient::setStartRadius):
+        (WebCore::Gradient::setEndRadius):
+        (Gradient):
+        (WebCore::Gradient::clearHashCache):
+        * platform/graphics/GraphicsContext.cpp:
+        (WebCore::GraphicsContext::isCompatibleWithBuffer):
+        (WebCore):
+        * platform/graphics/GraphicsContext.h:
+        (GraphicsContext):
+
 2012-05-21  Emil A Eklund  <[email protected]>
 
         Fix bug in paintNinePieceImage exposed by subpixel change

Modified: trunk/Source/WebCore/platform/graphics/Generator.h (117857 => 117858)


--- trunk/Source/WebCore/platform/graphics/Generator.h	2012-05-22 00:27:09 UTC (rev 117857)
+++ trunk/Source/WebCore/platform/graphics/Generator.h	2012-05-22 00:28:58 UTC (rev 117858)
@@ -39,6 +39,7 @@
     
     virtual void fill(GraphicsContext*, const FloatRect&) = 0;
     virtual void adjustParametersForTiledDrawing(IntSize& /* size */, FloatRect& /* srcRect */) { }
+    virtual unsigned hash() = 0;
 };
 
 } //namespace

Modified: trunk/Source/WebCore/platform/graphics/GeneratorGeneratedImage.cpp (117857 => 117858)


--- trunk/Source/WebCore/platform/graphics/GeneratorGeneratedImage.cpp	2012-05-22 00:27:09 UTC (rev 117857)
+++ trunk/Source/WebCore/platform/graphics/GeneratorGeneratedImage.cpp	2012-05-22 00:28:58 UTC (rev 117858)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,7 +28,6 @@
 
 #include "FloatRect.h"
 #include "GraphicsContext.h"
-#include "ImageBuffer.h"
 #include "Length.h"
 
 namespace WebCore {
@@ -61,17 +60,28 @@
     adjustedPatternCTM.scale(1.0 / xScale, 1.0 / yScale);
     adjustedSrcRect.scale(xScale, yScale);
 
-    // Create a BitmapImage and call drawPattern on it.
-    OwnPtr<ImageBuffer> imageBuffer = destContext->createCompatibleBuffer(adjustedSize);
-    if (!imageBuffer)
-        return;
+    unsigned generatorHash = m_generator->hash();
 
-    // Fill with the generated image.
-    GraphicsContext* graphicsContext = imageBuffer->context();
-    graphicsContext->fillRect(FloatRect(FloatPoint(), adjustedSize), *m_generator.get());
+    if (!m_cachedImageBuffer
+        || m_cachedGeneratorHash != generatorHash
+        || m_cachedAdjustedSize != adjustedSize
+        || !destContext->isCompatibleWithBuffer(m_cachedImageBuffer.get())) {
+        // Create a BitmapImage and call drawPattern on it.
+        m_cachedImageBuffer = destContext->createCompatibleBuffer(adjustedSize);
+        if (!m_cachedImageBuffer)
+            return;
 
+        // Fill with the generated image.
+        GraphicsContext* graphicsContext = m_cachedImageBuffer->context();
+        graphicsContext->fillRect(FloatRect(FloatPoint(), adjustedSize), *m_generator.get());
+
+        m_cachedGeneratorHash = generatorHash;
+        m_cachedAdjustedSize = adjustedSize;
+    }
+
     // Tile the image buffer into the context.
-    imageBuffer->drawPattern(destContext, adjustedSrcRect, adjustedPatternCTM, phase, styleColorSpace, compositeOp, destRect);
+    m_cachedImageBuffer->drawPattern(destContext, adjustedSrcRect, adjustedPatternCTM, phase, styleColorSpace, compositeOp, destRect);
+    m_cacheTimer.restart();
 }
 
 void GeneratedImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio)

Modified: trunk/Source/WebCore/platform/graphics/GeneratorGeneratedImage.h (117857 => 117858)


--- trunk/Source/WebCore/platform/graphics/GeneratorGeneratedImage.h	2012-05-22 00:27:09 UTC (rev 117857)
+++ trunk/Source/WebCore/platform/graphics/GeneratorGeneratedImage.h	2012-05-22 00:28:58 UTC (rev 117858)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2008, 2012 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,19 +29,30 @@
 #include "GeneratedImage.h"
 #include "Generator.h"
 #include "Image.h"
+#include "ImageBuffer.h"
 #include "IntSize.h"
+#include "Timer.h"
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
 
+static const int generatedImageCacheClearDelay = 1;
+
+class GeneratedImageCacheTimer;
+
 class GeneratorGeneratedImage : public GeneratedImage {
+    friend class GeneratedImageCacheTimer;
 public:
     static PassRefPtr<GeneratorGeneratedImage> create(PassRefPtr<Generator> generator, const IntSize& size)
     {
         return adoptRef(new GeneratorGeneratedImage(generator, size));
     }
-    virtual ~GeneratorGeneratedImage() { }
 
+    virtual ~GeneratorGeneratedImage()
+    {
+        m_cacheTimer.stop();
+    }
+
 protected:
     virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
     virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
@@ -49,11 +60,49 @@
 
     GeneratorGeneratedImage(PassRefPtr<Generator> generator, const IntSize& size)
         : m_generator(generator)
+        , m_cacheTimer(this)
     {
         m_size = size;
     }
+    
+    class GeneratedImageCacheTimer : public TimerBase {
+    public:
+        GeneratedImageCacheTimer(GeneratorGeneratedImage * parent)
+        : m_shouldRestartWhenTimerFires(false)
+        , m_parent(parent) { }
+        
+        void restart()
+        {
+            if (isActive()) {
+                m_shouldRestartWhenTimerFires = true;
+                return;
+            }
+            startOneShot(generatedImageCacheClearDelay);
+        };
+    private:
+        virtual void fired() OVERRIDE
+        {
+            if (m_shouldRestartWhenTimerFires) {
+                m_shouldRestartWhenTimerFires = false;
+                startOneShot(generatedImageCacheClearDelay);
+                return;
+            }
+            
+            if (m_parent) {
+                m_parent->m_cachedImageBuffer.clear();
+                m_parent->m_cachedAdjustedSize = IntSize();
+            }
+        };
+        bool m_shouldRestartWhenTimerFires;
+        GeneratorGeneratedImage* m_parent;
+    };
 
     RefPtr<Generator> m_generator;
+
+    OwnPtr<ImageBuffer> m_cachedImageBuffer;
+    GeneratedImageCacheTimer m_cacheTimer;
+    IntSize m_cachedAdjustedSize;
+    unsigned m_cachedGeneratorHash;
 };
 
 }

Modified: trunk/Source/WebCore/platform/graphics/Gradient.cpp (117857 => 117858)


--- trunk/Source/WebCore/platform/graphics/Gradient.cpp	2012-05-22 00:27:09 UTC (rev 117857)
+++ trunk/Source/WebCore/platform/graphics/Gradient.cpp	2012-05-22 00:28:58 UTC (rev 117858)
@@ -29,6 +29,8 @@
 
 #include "Color.h"
 #include "FloatRect.h"
+#include <wtf/HashFunctions.h>
+#include <wtf/StringHasher.h>
 #include <wtf/UnusedParam.h>
 
 namespace WebCore {
@@ -43,6 +45,7 @@
     , m_stopsSorted(false)
     , m_lastStop(0)
     , m_spreadMethod(SpreadMethodPad)
+    , m_hashCache(0)
 {
     platformInit();
 }
@@ -57,6 +60,7 @@
     , m_stopsSorted(false)
     , m_lastStop(0)
     , m_spreadMethod(SpreadMethodPad)
+    , m_hashCache(0)
 {
     platformInit();
 }
@@ -99,6 +103,8 @@
 
     m_stopsSorted = false;
     platformDestroy();
+
+    clearHashCache();
 }
 
 void Gradient::addColorStop(const Gradient::ColorStop& stop)
@@ -107,6 +113,8 @@
 
     m_stopsSorted = false;
     platformDestroy();
+
+    clearHashCache();
 }
 
 static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
@@ -125,6 +133,8 @@
         return;
 
     std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
+
+    clearHashCache();
 }
 
 void Gradient::getColor(float value, float* r, float* g, float* b, float* a) const
@@ -208,13 +218,24 @@
 {
     // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set.
     ASSERT(m_gradient == 0);
+
+    if (m_spreadMethod == spreadMethod)
+        return;
+
     m_spreadMethod = spreadMethod;
+
+    clearHashCache();
 }
 
 void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
-{ 
+{
+    if (m_gradientSpaceTransformation == gradientSpaceTransformation)
+        return;
+
     m_gradientSpaceTransformation = gradientSpaceTransformation;
     setPlatformGradientSpaceTransform(gradientSpaceTransformation);
+
+    clearHashCache();
 }
 
 #if !USE(SKIA) && !USE(CAIRO)
@@ -223,5 +244,45 @@
 }
 #endif
 
+unsigned Gradient::hash()
+{
+    if (m_hashCache)
+        return m_hashCache;
 
+    struct {
+        AffineTransform gradientSpaceTransformation;
+        FloatPoint p0;
+        FloatPoint p1;
+        float r0;
+        float r1;
+        float aspectRatio;
+        int lastStop;
+        GradientSpreadMethod spreadMethod;
+        bool radial;
+    } parameters;
+    
+    memset(&parameters, 0, sizeof(parameters));
+    
+    parameters.gradientSpaceTransformation = m_gradientSpaceTransformation;
+    parameters.p0 = m_p0;
+    parameters.p1 = m_p1;
+    parameters.r0 = m_r0;
+    parameters.r1 = m_r1;
+    parameters.aspectRatio = m_aspectRatio;
+    parameters.lastStop = m_lastStop;
+    parameters.spreadMethod = m_spreadMethod;
+    parameters.radial = m_radial;
+
+    unsigned parametersHash = StringHasher::hashMemory(&parameters, sizeof(parameters));
+    
+    ColorStop * stopData = m_stops.data();
+    unsigned stopHash = StringHasher::hashMemory(stopData, m_stops.size() * sizeof(ColorStop));
+    
+    std::pair<unsigned, unsigned> hashes(parametersHash, stopHash);
+    
+    m_hashCache = DefaultHash<std::pair<unsigned, unsigned> >::Hash::hash(hashes);
+
+    return m_hashCache;
+}
+
 } //namespace

Modified: trunk/Source/WebCore/platform/graphics/Gradient.h (117857 => 117858)


--- trunk/Source/WebCore/platform/graphics/Gradient.h	2012-05-22 00:27:09 UTC (rev 117857)
+++ trunk/Source/WebCore/platform/graphics/Gradient.h	2012-05-22 00:28:58 UTC (rev 117858)
@@ -97,15 +97,49 @@
         const FloatPoint& p0() const { return m_p0; }
         const FloatPoint& p1() const { return m_p1; }
 
-        void setP0(const FloatPoint& p) { m_p0 = p; }
-        void setP1(const FloatPoint& p) { m_p1 = p; }
+        void setP0(const FloatPoint& p)
+        {
+            if (m_p0 == p)
+                return;
+            
+            m_p0 = p;
+            
+            clearHashCache();
+        }
+        
+        void setP1(const FloatPoint& p)
+        {
+            if (m_p1 == p)
+                return;
+            
+            m_p1 = p;
+            
+            clearHashCache();
+        }
 
         float startRadius() const { return m_r0; }
         float endRadius() const { return m_r1; }
 
-        void setStartRadius(float r) { m_r0 = r; }
-        void setEndRadius(float r) { m_r1 = r; }
-        
+        void setStartRadius(float r)
+        {
+            if (m_r0 == r)
+                return;
+
+            m_r0 = r;
+
+            clearHashCache();
+        }
+
+        void setEndRadius(float r)
+        {
+            if (m_r1 == r)
+                return;
+
+            m_r1 = r;
+
+            clearHashCache();
+        }
+
         float aspectRatio() const { return m_aspectRatio; }
 
 #if OS(WINCE) && !PLATFORM(QT)
@@ -138,6 +172,9 @@
 
         void setPlatformGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation);
 
+        virtual unsigned hash() OVERRIDE;
+        void clearHashCache() { m_hashCache = 0; }
+
 #if USE(CG)
         void paint(CGContextRef);
         void paint(GraphicsContext*);
@@ -155,6 +192,7 @@
         int findStop(float value) const;
         void sortStopsIfNecessary();
 
+        // Keep any parameters relevant to rendering in sync with the structure in Gradient::hash().
         bool m_radial;
         FloatPoint m_p0;
         FloatPoint m_p1;
@@ -167,6 +205,8 @@
         GradientSpreadMethod m_spreadMethod;
         AffineTransform m_gradientSpaceTransformation;
 
+        unsigned m_hashCache;
+
         PlatformGradient m_gradient;
 
 #if USE(CAIRO)

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp (117857 => 117858)


--- trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp	2012-05-22 00:27:09 UTC (rev 117857)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp	2012-05-22 00:28:58 UTC (rev 117858)
@@ -780,6 +780,20 @@
     return buffer.release();
 }
 
+bool GraphicsContext::isCompatibleWithBuffer(ImageBuffer* buffer) const
+{
+    AffineTransform localTransform = getCTM();
+    AffineTransform bufferTransform = buffer->context()->getCTM();
+
+    if (localTransform.xScale() != bufferTransform.xScale() || localTransform.yScale() != bufferTransform.yScale())
+        return false;
+
+    if (isAcceleratedContext() != buffer->context()->isAcceleratedContext())
+        return false;
+
+    return true;
+}
+
 #if !USE(CG)
 void GraphicsContext::platformApplyDeviceScaleFactor(float)
 {

Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.h (117857 => 117858)


--- trunk/Source/WebCore/platform/graphics/GraphicsContext.h	2012-05-22 00:27:09 UTC (rev 117857)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.h	2012-05-22 00:28:58 UTC (rev 117858)
@@ -424,6 +424,7 @@
         // Create an image buffer compatible with this context, with suitable resolution
         // for drawing into the buffer and then into this context.
         PassOwnPtr<ImageBuffer> createCompatibleBuffer(const IntSize&) const;
+        bool isCompatibleWithBuffer(ImageBuffer*) const;
 
         // This function applies the device scale factor to the context, making the context capable of
         // acting as a base-level context for a HiDPI environment.
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to