Changeset 149886 in webkit


Ignore:
Timestamp:
May 10, 2013 10:34:36 AM (11 years ago)
Author:
akling@apple.com
Message:

Caching of generated images in CSS should be smarter.
<http://webkit.org/b/115902>
<rdar://problem/13542727>

Reviewed by Antti Koivisto.

Add an IntSize => GeneratorGeneratedImage cache at the CSSImageGeneratorValue level.

CSSGradientValue is currently the only CSSImageGeneratorValue subclass that makes use of the cache.
Generated images are kept for 3 seconds after last use.

The main problem with the previous approach was that background renderers (e.g <body>, <tr>, etc)
would be passed to multiple CSSImageGeneratorValue::getImage() calls with different sizes requested
for each of the descendent renderers that inherit their background from the same parent.
The cache wasn't smart enough for this, it just thought the background renderer was changing size
a lot, and would regenerate the image over and over.

We already had caching of intermediate image buffers for GeneratorGeneratedImage::drawPattern().
This removes the eviction timer from that cache so that the intermediate images can live a bit longer.

(WebCore::CSSImageGeneratorValue::cachedImageForSize):
(WebCore::CSSImageGeneratorValue::saveCachedImageForSize):

Renamed from getImage() and putImage().

(WebCore::CSSImageGeneratorValue::evictCachedGeneratedImage):
(WebCore::CSSImageGeneratorValue::CachedGeneratedImage::CachedGeneratedImage):
(WebCore::CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired):

Let the CachedGeneratedImage throw itself out from cache when the timer fires.

  • css/CSSImageGeneratorValue.h:

(CachedGeneratedImage):

Exactly what it sounds like. These go into CSSImageGeneratorValue::m_images with the size
as the hash key.

  • platform/graphics/GeneratorGeneratedImage.cpp:

(WebCore::GeneratorGeneratedImage::drawPattern):

  • platform/graphics/GeneratorGeneratedImage.h:

(WebCore::GeneratorGeneratedImage::~GeneratorGeneratedImage):
(WebCore::GeneratorGeneratedImage::GeneratorGeneratedImage):

Keep the intermediate image for drawPattern() until destruction instead of dropping it on
a timer. These objects are now evicted by the CSSImageGeneratorValue's image cache
after 3 seconds of disuse rather than kept for the lifetime of the renderer.

  • css/CSSCanvasValue.cpp:

(WebCore::CSSCanvasValue::canvasChanged):
(WebCore::CSSCanvasValue::canvasResized):

  • css/CSSCrossfadeValue.cpp:

(WebCore::CSSCrossfadeValue::crossfadeChanged):

  • rendering/style/StyleGeneratedImage.cpp:

(WebCore::StyleGeneratedImage::addClient):

  • css/CSSImageGeneratorValue.cpp:

(WebCore::CSSImageGeneratorValue::addClient):
(WebCore::CSSImageGeneratorValue::removeClient):

CSSImageGeneratorValue::m_clients is now a HashCountedSet<RenderObject*>, tweak accordingly.

Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r149882 r149886  
     12013-05-10  Andreas Kling  <akling@apple.com>
     2
     3        Caching of generated images in CSS should be smarter.
     4        <http://webkit.org/b/115902>
     5        <rdar://problem/13542727>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Add an IntSize => GeneratorGeneratedImage cache at the CSSImageGeneratorValue level.
     10
     11        CSSGradientValue is currently the only CSSImageGeneratorValue subclass that makes use of the cache.
     12        Generated images are kept for 3 seconds after last use.
     13
     14        The main problem with the previous approach was that background renderers (e.g <body>, <tr>, etc)
     15        would be passed to multiple CSSImageGeneratorValue::getImage() calls with different sizes requested
     16        for each of the descendent renderers that inherit their background from the same parent.
     17        The cache wasn't smart enough for this, it just thought the background renderer was changing size
     18        a lot, and would regenerate the image over and over.
     19
     20        We already had caching of intermediate image buffers for GeneratorGeneratedImage::drawPattern().
     21        This removes the eviction timer from that cache so that the intermediate images can live a bit longer.
     22
     23        (WebCore::CSSImageGeneratorValue::cachedImageForSize):
     24        (WebCore::CSSImageGeneratorValue::saveCachedImageForSize):
     25
     26            Renamed from getImage() and putImage().
     27
     28        (WebCore::CSSImageGeneratorValue::evictCachedGeneratedImage):
     29        (WebCore::CSSImageGeneratorValue::CachedGeneratedImage::CachedGeneratedImage):
     30        (WebCore::CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired):
     31
     32            Let the CachedGeneratedImage throw itself out from cache when the timer fires.
     33
     34        * css/CSSImageGeneratorValue.h:
     35        (CachedGeneratedImage):
     36
     37            Exactly what it sounds like. These go into CSSImageGeneratorValue::m_images with the size
     38            as the hash key.
     39
     40        * platform/graphics/GeneratorGeneratedImage.cpp:
     41        (WebCore::GeneratorGeneratedImage::drawPattern):
     42        * platform/graphics/GeneratorGeneratedImage.h:
     43        (WebCore::GeneratorGeneratedImage::~GeneratorGeneratedImage):
     44        (WebCore::GeneratorGeneratedImage::GeneratorGeneratedImage):
     45
     46            Keep the intermediate image for drawPattern() until destruction instead of dropping it on
     47            a timer. These objects are now evicted by the CSSImageGeneratorValue's image cache
     48            after 3 seconds of disuse rather than kept for the lifetime of the renderer.
     49
     50        * css/CSSCanvasValue.cpp:
     51        (WebCore::CSSCanvasValue::canvasChanged):
     52        (WebCore::CSSCanvasValue::canvasResized):
     53        * css/CSSCrossfadeValue.cpp:
     54        (WebCore::CSSCrossfadeValue::crossfadeChanged):
     55        * rendering/style/StyleGeneratedImage.cpp:
     56        (WebCore::StyleGeneratedImage::addClient):
     57        * css/CSSImageGeneratorValue.cpp:
     58        (WebCore::CSSImageGeneratorValue::addClient):
     59        (WebCore::CSSImageGeneratorValue::removeClient):
     60
     61            CSSImageGeneratorValue::m_clients is now a HashCountedSet<RenderObject*>, tweak accordingly.
     62
    1632013-05-10  Anders Carlsson  <andersca@apple.com>
    264
  • trunk/Source/WebCore/css/CSSCanvasValue.cpp

    r148921 r149886  
    5151{
    5252    IntRect imageChangeRect = enclosingIntRect(changedRect);
    53     RenderObjectSizeCountMap::const_iterator end = clients().end();
    54     for (RenderObjectSizeCountMap::const_iterator curr = clients().begin(); curr != end; ++curr)
     53    HashCountedSet<RenderObject*>::const_iterator end = clients().end();
     54    for (HashCountedSet<RenderObject*>::const_iterator curr = clients().begin(); curr != end; ++curr)
    5555        const_cast<RenderObject*>(curr->key)->imageChanged(static_cast<WrappedImagePtr>(this), &imageChangeRect);
    5656}
     
    5858void CSSCanvasValue::canvasResized(HTMLCanvasElement*)
    5959{
    60     RenderObjectSizeCountMap::const_iterator end = clients().end();
    61     for (RenderObjectSizeCountMap::const_iterator curr = clients().begin(); curr != end; ++curr)
     60    HashCountedSet<RenderObject*>::const_iterator end = clients().end();
     61    for (HashCountedSet<RenderObject*>::const_iterator curr = clients().begin(); curr != end; ++curr)
    6262        const_cast<RenderObject*>(curr->key)->imageChanged(static_cast<WrappedImagePtr>(this));
    6363}
  • trunk/Source/WebCore/css/CSSCrossfadeValue.cpp

    r148921 r149886  
    194194void CSSCrossfadeValue::crossfadeChanged(const IntRect&)
    195195{
    196     RenderObjectSizeCountMap::const_iterator end = clients().end();
    197     for (RenderObjectSizeCountMap::const_iterator curr = clients().begin(); curr != end; ++curr) {
     196    HashCountedSet<RenderObject*>::const_iterator end = clients().end();
     197    for (HashCountedSet<RenderObject*>::const_iterator curr = clients().begin(); curr != end; ++curr) {
    198198        RenderObject* client = const_cast<RenderObject*>(curr->key);
    199199        client->imageChanged(static_cast<WrappedImagePtr>(this));
  • trunk/Source/WebCore/css/CSSGradientValue.cpp

    r149583 r149886  
    5454            return 0;
    5555
    56         // Need to look up our size.  Create a string of width*height to use as a hash key.
    57         Image* result = getImage(renderer, size);
     56        Image* result = cachedImageForSize(size);
    5857        if (result)
    5958            return result;
    6059    }
    6160
    62     // We need to create an image.
    6361    RefPtr<Gradient> gradient;
    6462
     
    7068    }
    7169
    72     RefPtr<Image> newImage = GeneratorGeneratedImage::create(gradient, size);
     70    RefPtr<GeneratorGeneratedImage> newImage = GeneratorGeneratedImage::create(gradient, size);
    7371    if (cacheable)
    74         putImage(size, newImage);
     72        saveCachedImageForSize(size, newImage);
    7573
    7674    return newImage.release();
  • trunk/Source/WebCore/css/CSSImageGeneratorValue.cpp

    r149665 r149886  
    11/*
    2  * Copyright (C) 2008 Apple Inc.  All rights reserved.
     2 * Copyright (C) 2008, 2011, 2012, 2013 Apple Inc.  All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3636namespace WebCore {
    3737
     38static const double timeToKeepCachedGeneratedImagesInSeconds = 3;
     39
    3840CSSImageGeneratorValue::CSSImageGeneratorValue(ClassType classType)
    3941    : CSSValue(classType)
     
    4547}
    4648
    47 void CSSImageGeneratorValue::addClient(RenderObject* renderer, const IntSize& size)
    48 {
     49void CSSImageGeneratorValue::addClient(RenderObject* renderer)
     50{
     51    ASSERT(renderer);
    4952    ref();
    50 
     53    m_clients.add(renderer);
     54}
     55
     56void CSSImageGeneratorValue::removeClient(RenderObject* renderer)
     57{
    5158    ASSERT(renderer);
    52     if (!size.isEmpty())
    53         m_sizes.add(size);
    54 
    55     RenderObjectSizeCountMap::iterator it = m_clients.find(renderer);
    56     if (it == m_clients.end())
    57         m_clients.add(renderer, SizeAndCount(size, 1));
    58     else {
    59         SizeAndCount& sizeCount = it->value;
    60         ++sizeCount.count;
    61     }
    62 }
    63 
    64 void CSSImageGeneratorValue::removeClient(RenderObject* renderer)
    65 {
    66     ASSERT(renderer);
    67     RenderObjectSizeCountMap::iterator it = m_clients.find(renderer);
    68     ASSERT(it != m_clients.end());
    69 
    70     IntSize removedImageSize;
    71     SizeAndCount& sizeCount = it->value;
    72     IntSize size = sizeCount.size;
    73     if (!size.isEmpty()) {
    74         m_sizes.remove(size);
    75         if (!m_sizes.contains(size))
    76             m_images.remove(size);
    77     }
    78 
    79     if (!--sizeCount.count)
    80         m_clients.remove(renderer);
    81 
     59    m_clients.remove(renderer);
    8260    deref();
    8361}
    8462
    85 Image* CSSImageGeneratorValue::getImage(RenderObject* renderer, const IntSize& size)
    86 {
    87     RenderObjectSizeCountMap::iterator it = m_clients.find(renderer);
    88     if (it != m_clients.end()) {
    89         SizeAndCount& sizeCount = it->value;
    90         IntSize oldSize = sizeCount.size;
    91         if (oldSize != size) {
    92             RefPtr<CSSImageGeneratorValue> protect(this);
    93             removeClient(renderer);
    94             addClient(renderer, size);
    95         }
    96     }
    97 
    98     // Don't generate an image for empty sizes.
     63GeneratorGeneratedImage* CSSImageGeneratorValue::cachedImageForSize(IntSize size)
     64{
    9965    if (size.isEmpty())
    10066        return 0;
    10167
    102     // Look up the image in our cache.
    103     return m_images.get(size);
    104 }
    105 
    106 void CSSImageGeneratorValue::putImage(const IntSize& size, PassRefPtr<Image> image)
    107 {
    108     m_images.add(size, image);
     68    CachedGeneratedImage* cachedGeneratedImage = m_images.get(size);
     69    if (!cachedGeneratedImage)
     70        return 0;
     71
     72    cachedGeneratedImage->puntEvictionTimer();
     73    return cachedGeneratedImage->image();
     74}
     75
     76void CSSImageGeneratorValue::saveCachedImageForSize(IntSize size, PassRefPtr<GeneratorGeneratedImage> image)
     77{
     78    ASSERT(!m_images.contains(size));
     79    m_images.add(size, adoptPtr(new CachedGeneratedImage(*this, size, image)));
     80}
     81
     82void CSSImageGeneratorValue::evictCachedGeneratedImage(IntSize size)
     83{
     84    ASSERT(m_images.contains(size));
     85    m_images.remove(size);
     86}
     87
     88CSSImageGeneratorValue::CachedGeneratedImage::CachedGeneratedImage(CSSImageGeneratorValue& owner, IntSize size, PassRefPtr<GeneratorGeneratedImage> image)
     89    : m_owner(owner)
     90    , m_size(size)
     91    , m_image(image)
     92    , m_evictionTimer(this, &CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired, timeToKeepCachedGeneratedImagesInSeconds)
     93{
     94    m_evictionTimer.restart();
     95}
     96
     97void CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired(DeferrableOneShotTimer<CachedGeneratedImage>*)
     98{
     99    // NOTE: This is essentially a "delete this", the object is no longer valid after this line.
     100    m_owner.evictCachedGeneratedImage(m_size);
    109101}
    110102
  • trunk/Source/WebCore/css/CSSImageGeneratorValue.h

    r148921 r149886  
    11/*
    2  * Copyright (C) 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008, 2011, 2012, 2013 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2828
    2929#include "CSSValue.h"
     30#include "GeneratorGeneratedImage.h"
    3031#include "IntSizeHash.h"
     32#include "Timer.h"
    3133#include <wtf/HashCountedSet.h>
    3234#include <wtf/RefPtr.h>
     
    3537
    3638class CachedResourceLoader;
    37 class Image;
     39class GeneratorGeneratedImage;
    3840class RenderObject;
    3941class StyleResolver;
    40 
    41 struct SizeAndCount {
    42     SizeAndCount(IntSize newSize = IntSize(), int newCount = 0)
    43         : size(newSize)
    44         , count(newCount)
    45     {
    46     }
    47 
    48     IntSize size;
    49     int count;
    50 };
    51 
    52 typedef HashMap<const RenderObject*, SizeAndCount> RenderObjectSizeCountMap;
    5342
    5443class CSSImageGeneratorValue : public CSSValue {
     
    5645    ~CSSImageGeneratorValue();
    5746
    58     void addClient(RenderObject*, const IntSize&);
     47    void addClient(RenderObject*);
    5948    void removeClient(RenderObject*);
     49
    6050    PassRefPtr<Image> image(RenderObject*, const IntSize&);
    6151
     
    7161    CSSImageGeneratorValue(ClassType);
    7262
    73     Image* getImage(RenderObject*, const IntSize&);
    74     void putImage(const IntSize&, PassRefPtr<Image>);
    75     const RenderObjectSizeCountMap& clients() const { return m_clients; }
     63    GeneratorGeneratedImage* cachedImageForSize(IntSize);
     64    void saveCachedImageForSize(IntSize, PassRefPtr<GeneratorGeneratedImage>);
     65    const HashCountedSet<RenderObject*>& clients() const { return m_clients; }
    7666
    77     HashCountedSet<IntSize> m_sizes; // A count of how many times a given image size is in use.
    78     RenderObjectSizeCountMap m_clients; // A map from RenderObjects (with entry count) to image sizes.
    79     HashMap<IntSize, RefPtr<Image> > m_images; // A cache of Image objects by image size.
     67private:
     68    class CachedGeneratedImage {
     69    public:
     70        CachedGeneratedImage(CSSImageGeneratorValue&, IntSize, PassRefPtr<GeneratorGeneratedImage>);
     71        GeneratorGeneratedImage* image() { return m_image.get(); }
     72        void puntEvictionTimer() { m_evictionTimer.restart(); }
     73
     74    private:
     75        void evictionTimerFired(DeferrableOneShotTimer<CachedGeneratedImage>*);
     76
     77        CSSImageGeneratorValue& m_owner;
     78        IntSize m_size;
     79        RefPtr<GeneratorGeneratedImage> m_image;
     80        DeferrableOneShotTimer<CachedGeneratedImage> m_evictionTimer;
     81    };
     82
     83    friend class CachedGeneratedImage;
     84    void evictCachedGeneratedImage(IntSize);
     85
     86    HashCountedSet<RenderObject*> m_clients;
     87    HashMap<IntSize, OwnPtr<CachedGeneratedImage> > m_images;
    8088};
    8189
  • trunk/Source/WebCore/platform/graphics/GeneratorGeneratedImage.cpp

    r148921 r149886  
    7777    // Tile the image buffer into the context.
    7878    m_cachedImageBuffer->drawPattern(destContext, adjustedSrcRect, adjustedPatternCTM, phase, styleColorSpace, compositeOp, destRect);
    79     m_cacheTimer.restart();
    80 }
    81 
    82 void GeneratorGeneratedImage::invalidateCacheTimerFired(DeferrableOneShotTimer<GeneratorGeneratedImage>*)
    83 {
    84     m_cachedImageBuffer.clear();
    85     m_cachedAdjustedSize = IntSize();
    8679}
    8780
  • trunk/Source/WebCore/platform/graphics/GeneratorGeneratedImage.h

    r148921 r149886  
    3232#include "ImageBuffer.h"
    3333#include "IntSize.h"
    34 #include "Timer.h"
    3534#include <wtf/RefPtr.h>
    3635
    3736namespace WebCore {
    38 
    39 static const int generatedImageCacheClearDelay = 1;
    4037
    4138class GeneratorGeneratedImage : public GeneratedImage {
     
    4643    }
    4744
    48     virtual ~GeneratorGeneratedImage()
    49     {
    50         m_cacheTimer.stop();
    51     }
     45    virtual ~GeneratorGeneratedImage() { }
    5246
    5347protected:
     
    5650        const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect, BlendMode);
    5751
    58     void invalidateCacheTimerFired(DeferrableOneShotTimer<GeneratorGeneratedImage>*);
    59 
    6052    GeneratorGeneratedImage(PassRefPtr<Generator> generator, const IntSize& size)
    6153        : m_generator(generator)
    62         , m_cacheTimer(this, &GeneratorGeneratedImage::invalidateCacheTimerFired, generatedImageCacheClearDelay)
    6354    {
    6455        m_size = size;
     
    6657
    6758    RefPtr<Generator> m_generator;
    68 
    6959    OwnPtr<ImageBuffer> m_cachedImageBuffer;
    70     DeferrableOneShotTimer<GeneratorGeneratedImage> m_cacheTimer;
    7160    IntSize m_cachedAdjustedSize;
    7261    unsigned m_cachedGeneratorHash;
  • trunk/Source/WebCore/rendering/style/StyleGeneratedImage.cpp

    r141637 r149886  
    7777void StyleGeneratedImage::addClient(RenderObject* renderer)
    7878{
    79     m_imageGeneratorValue->addClient(renderer, IntSize());
     79    m_imageGeneratorValue->addClient(renderer);
    8080}
    8181
  • trunk/Tools/Scripts/webkitpy/port/mac.py

    r148502 r149886  
    137137
    138138    def _build_java_test_support(self):
     139        return True
    139140        java_tests_path = self._filesystem.join(self.layout_tests_dir(), "java")
    140141        build_java = [self.make_command(), "-C", java_tests_path]
Note: See TracChangeset for help on using the changeset viewer.