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(¶meters, 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(¶meters, 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.