Changeset 142765 in webkit


Ignore:
Timestamp:
Feb 13, 2013 11:44:19 AM (11 years ago)
Author:
pdr@google.com
Message:

Replace SVG bitmap cache with directly-rendered SVG
https://bugs.webkit.org/show_bug.cgi?id=106159

Reviewed by Tim Horton.

Source/WebCore:

This patch removes the caching of SVG bitmaps so SVG images are rendered directly. This
enables WebKit to pass the IE Chalkboard demo in 10s on a Z620:
http://ie.microsoft.com/testdrive/Performance/Chalkboard/

On a simple scaled SVG benchmark similar to the IE10 Chalkboard demo
(http://philbit.com/SvgImagePerformance/viewport.html):

without patch: ~20FPS
with patch: ~55FPS

The bitmap SVG image cache had several shortcomings:

  • The bitmap cache prevented viewport rendering. (WK104693)
  • Bitmap memory usage was high. (WK106484)
  • Caching animating images was expensive.

This change removes almost all of the SVGImageCache implementation, replacing it with
directly-rendered SVG. Instead of caching bitmaps, an SVGImageForContainer is cached which
is a thin wrapper around an SVG image with the associated container size and scale.
When rendering patterns (e.g., tiled backgrounds), a temporary bitmap is used for
performance. This change also removes the redraw timer of the old cache, instead relying
on the SVG image to notify clients if the image changes (e.g., during animations).

This patch fixes two existing bugs (WK99481 and WK104189) that were due to caching bitmaps
at a fixed size. A test has been added for each of these bugs.

Tests: svg/as-image/svg-image-scaled.html

svg/as-image/svg-image-viewbox.html

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • Target.pri:
  • WebCore.gypi:
  • WebCore.vcproj/WebCore.vcproj:
  • WebCore.xcodeproj/project.pbxproj:
  • loader/cache/CachedImage.cpp:

(WebCore::CachedImage::lookupOrCreateImageForRenderer):
(WebCore::CachedImage::setContainerSizeForRenderer):
(WebCore::CachedImage::clear):
(WebCore::CachedImage::changedInRect):

SVG images are no longer special-cased here. When the SVG image changes, users are
notified through this function, and users can then request their content to be redrawn.

  • svg/graphics/SVGImage.cpp:

(WebCore::SVGImage::setContainerSize):
(WebCore::SVGImage::drawForContainer):

drawForContainer lays out the SVG content for a specific container size and renders it.
The logic is fairly straightforward but a note about the scales and zooms here:

the destination rect parameter is zoomed but not scaled
the source rect parameter is zoomed but not scaled
the context is scaled but not zoomed

SVGImage::draw(...) only accepts a source and destination rect but does not consider
scale or zoom. Therefore, drawForContainer removes the zoom component from the source
so SVGImage::draw(...) will draw from the pre-zoom source to the post-zoom destination.

(WebCore::SVGImage::drawPatternForContainer):

For performance, drawPatternForContainer renders the SVG content onto a bitmap, then
has the bitmap image draw the pattern. This is necessary because drawPattern is used
for tiling.

(WebCore):
(WebCore::SVGImage::startAnimation):
(WebCore::SVGImage::stopAnimation):
(WebCore::SVGImage::resetAnimation):
(WebCore::SVGImage::reportMemoryUsage):

  • svg/graphics/SVGImage.h:

(WebCore):
(SVGImage):

  • svg/graphics/SVGImageCache.cpp:

Instead of storing a SizeAndScales values for each renderer, a SVGImageForContainer
is stored which is just a thin wrapper around an SVG image that contains container
sizing information. By combining the image and size information, the two maps of
SVGImageCache have been merged into one.

To make this patch easier to review, SVGImageCache still exists and works similar to
how it did before the patch. Now, SVGImageCache simply stores the SVGImageForContainers.
In a followup patch it will be removed.

Note: the redraw timer of SVGImageCache has been removed because animation
invalidation is now properly propagated back to the image clients.

(WebCore):
(WebCore::SVGImageCache::SVGImageCache):
(WebCore::SVGImageCache::~SVGImageCache):
(WebCore::SVGImageCache::removeClientFromCache):
(WebCore::SVGImageCache::setContainerSizeForRenderer):
(WebCore::SVGImageCache::imageSizeForRenderer):

Previously, this function returned the scaled image size which was incorrect. The image
size is used by clients such as GraphicsContext2D to determine the source size
for drawing the image. draw() accepts zoomed but not scaled values, so this has been
changed.

(WebCore::SVGImageCache::imageForRenderer):

A FIXME has been added here to not set the scale on every lookup. This can be improved
by setting the page scale factor in setContainerSizeForRenderer() in a future patch.

  • svg/graphics/SVGImageCache.h:

(WebCore):
(SVGImageCache):

  • svg/graphics/SVGImageForContainer.cpp: Added.

(WebCore):

SVGImageForContainer is a thin wrapper around an SVG image. The lifetime of the
SVGImage will be longer than the image cache.

(WebCore::SVGImageForContainer::size):

This is the only logic in SVGImageForContainer. The size returned needs to be zoomed
but not scaled because it is used (e.g., by RenderImage) to pass back into draw() which
takes zoomed but not scaled values.

(WebCore::SVGImageForContainer::draw):
(WebCore::SVGImageForContainer::drawPattern):

  • svg/graphics/SVGImageForContainer.h: Added.

(WebCore):
(SVGImageForContainer):

In a future patch SVGImageForContainer can be made immutable but without a refactoring
for not setting the page scale factor in SVGImageCache::lookupOrCreateImageForRenderer,
setters are needed.

(WebCore::SVGImageForContainer::create):
(WebCore::SVGImageForContainer::containerSize):
(WebCore::SVGImageForContainer::pageScale):
(WebCore::SVGImageForContainer::zoom):
(WebCore::SVGImageForContainer::setSize):
(WebCore::SVGImageForContainer::setZoom):
(WebCore::SVGImageForContainer::setPageScale):
(WebCore::SVGImageForContainer::SVGImageForContainer):
(WebCore::SVGImageForContainer::destroyDecodedData):
(WebCore::SVGImageForContainer::decodedSize):

LayoutTests:

This patch fixes two existing bugs (WK99481 and WK104189) that were due to caching bitmaps
at a fixed size. A test has been added for each of these bugs.

  • platform/chromium/TestExpectations:
  • svg/as-image/svg-image-scaled-expected.html: Added.
  • svg/as-image/svg-image-scaled.html: Added.
  • svg/as-image/svg-image-viewbox-expected.html: Added.
  • svg/as-image/svg-image-viewbox.html: Added.
Location:
trunk
Files:
6 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r142759 r142765  
     12013-02-13  Philip Rogers  <pdr@google.com>
     2
     3        Replace SVG bitmap cache with directly-rendered SVG
     4        https://bugs.webkit.org/show_bug.cgi?id=106159
     5
     6        Reviewed by Tim Horton.
     7
     8        This patch fixes two existing bugs (WK99481 and WK104189) that were due to caching bitmaps
     9        at a fixed size. A test has been added for each of these bugs.
     10
     11        * platform/chromium/TestExpectations:
     12        * svg/as-image/svg-image-scaled-expected.html: Added.
     13        * svg/as-image/svg-image-scaled.html: Added.
     14        * svg/as-image/svg-image-viewbox-expected.html: Added.
     15        * svg/as-image/svg-image-viewbox.html: Added.
     16
    1172013-02-13  Florin Malita  <fmalita@chromium.org>
    218
  • trunk/LayoutTests/platform/chromium/TestExpectations

    r142739 r142765  
    41374137webkit.org/b/103308 [ SnowLeopard Lion ] css3/filters/custom/custom-filter-transforms-animation.html [ Pass Timeout ]
    41384138
     4139# Rebaseline after https://bugs.webkit.org/show_bug.cgi?id=106159
     4140webkit.org/b/106159 svg/as-background-image/animated-svg-as-background.html [ ImageOnlyFailure Pass ]
     4141webkit.org/b/106159 svg/as-background-image/svg-as-background-1.html [ ImageOnlyFailure Pass ]
     4142webkit.org/b/106159 svg/as-background-image/svg-as-background-2.html [ ImageOnlyFailure Pass ]
     4143webkit.org/b/106159 svg/as-background-image/svg-as-background-3.html [ ImageOnlyFailure Pass ]
     4144webkit.org/b/106159 svg/as-background-image/svg-as-background-4.html [ ImageOnlyFailure Pass ]
     4145webkit.org/b/106159 svg/as-background-image/svg-as-background-5.html [ ImageOnlyFailure Pass ]
     4146webkit.org/b/106159 svg/as-background-image/svg-as-background-6.html [ ImageOnlyFailure Pass ]
     4147webkit.org/b/106159 svg/as-background-image/svg-as-background-with-relative-size.html [ ImageOnlyFailure Pass ]
     4148webkit.org/b/106159 svg/as-background-image/svg-background-partial-redraw.html [ ImageOnlyFailure Pass ]
     4149webkit.org/b/106159 svg/as-border-image/svg-as-border-image.html [ ImageOnlyFailure Pass ]
     4150webkit.org/b/106159 svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size.html [ ImageOnlyFailure Pass ]
     4151webkit.org/b/106159 svg/as-image/img-preserveAspectRatio-support-2.html [ ImageOnlyFailure Pass ]
     4152webkit.org/b/106159 svg/as-image/svg-image-change-content-size.xhtml [ ImageOnlyFailure Pass ]
     4153webkit.org/b/106159 svg/as-image/svg-non-integer-scaled-image.html [ ImageOnlyFailure Pass ]
     4154webkit.org/b/106159 svg/carto.net/combobox.svg [ ImageOnlyFailure Pass ]
     4155webkit.org/b/106159 svg/wicd/test-scalable-background-image1.xhtml [ ImageOnlyFailure Pass ]
     4156webkit.org/b/106159 svg/wicd/test-scalable-background-image2.xhtml [ ImageOnlyFailure Pass ]
     4157webkit.org/b/106159 svg/zoom/page/zoom-background-images.html [ ImageOnlyFailure Pass ]
     4158webkit.org/b/106159 svg/zoom/page/zoom-svg-as-background-with-relative-size-and-viewBox.html [ ImageOnlyFailure Pass ]
     4159webkit.org/b/106159 svg/zoom/page/zoom-svg-as-background-with-relative-size.html [ ImageOnlyFailure Pass ]
     4160webkit.org/b/106159 css2.1/20110323/background-intrinsic-005.htm [ ImageOnlyFailure Pass ]
     4161webkit.org/b/106159 svg/as-image/same-image-two-instances.html [ ImageOnlyFailure Pass ]
     4162webkit.org/b/106159 css2.1/20110323/background-intrinsic-004.htm [ ImageOnlyFailure Pass ]
     4163webkit.org/b/106159 fast/backgrounds/size/contain-and-cover.html [ ImageOnlyFailure Pass ]
     4164webkit.org/b/106159 fast/writing-mode/block-level-images.html [ ImageOnlyFailure Pass ]
     4165
    41394166webkit.org/b/103363 [ Mac ] touchadjustment/touch-links-longpress.html [ Failure ]
    41404167webkit.org/b/103446 [ Mac ] http/tests/canvas/canvas-slow-font-loading.html [ ImageOnlyFailure ]
  • trunk/Source/WebCore/CMakeLists.txt

    r142739 r142765  
    24952495    svg/graphics/SVGImage.cpp
    24962496    svg/graphics/SVGImageCache.cpp
     2497    svg/graphics/SVGImageForContainer.cpp
    24972498
    24982499    svg/graphics/filters/SVGFEImage.cpp
  • trunk/Source/WebCore/ChangeLog

    r142764 r142765  
     12013-02-13  Philip Rogers  <pdr@google.com>
     2
     3        Replace SVG bitmap cache with directly-rendered SVG
     4        https://bugs.webkit.org/show_bug.cgi?id=106159
     5
     6        Reviewed by Tim Horton.
     7
     8        This patch removes the caching of SVG bitmaps so SVG images are rendered directly. This
     9        enables WebKit to pass the IE Chalkboard demo in 10s on a Z620:
     10        http://ie.microsoft.com/testdrive/Performance/Chalkboard/
     11
     12        On a simple scaled SVG benchmark similar to the IE10 Chalkboard demo
     13        (http://philbit.com/SvgImagePerformance/viewport.html):
     14            without patch: ~20FPS
     15            with patch: ~55FPS
     16
     17        The bitmap SVG image cache had several shortcomings:
     18            - The bitmap cache prevented viewport rendering. (WK104693)
     19            - Bitmap memory usage was high. (WK106484)
     20            - Caching animating images was expensive.
     21
     22        This change removes almost all of the SVGImageCache implementation, replacing it with
     23        directly-rendered SVG. Instead of caching bitmaps, an SVGImageForContainer is cached which
     24        is a thin wrapper around an SVG image with the associated container size and scale.
     25        When rendering patterns (e.g., tiled backgrounds), a temporary bitmap is used for
     26        performance. This change also removes the redraw timer of the old cache, instead relying
     27        on the SVG image to notify clients if the image changes (e.g., during animations).
     28
     29        This patch fixes two existing bugs (WK99481 and WK104189) that were due to caching bitmaps
     30        at a fixed size. A test has been added for each of these bugs.
     31
     32        Tests: svg/as-image/svg-image-scaled.html
     33               svg/as-image/svg-image-viewbox.html
     34
     35        * CMakeLists.txt:
     36        * GNUmakefile.list.am:
     37        * Target.pri:
     38        * WebCore.gypi:
     39        * WebCore.vcproj/WebCore.vcproj:
     40        * WebCore.xcodeproj/project.pbxproj:
     41        * loader/cache/CachedImage.cpp:
     42        (WebCore::CachedImage::lookupOrCreateImageForRenderer):
     43        (WebCore::CachedImage::setContainerSizeForRenderer):
     44        (WebCore::CachedImage::clear):
     45        (WebCore::CachedImage::changedInRect):
     46
     47            SVG images are no longer special-cased here. When the SVG image changes, users are
     48            notified through this function, and users can then request their content to be redrawn.
     49
     50        * svg/graphics/SVGImage.cpp:
     51        (WebCore::SVGImage::setContainerSize):
     52        (WebCore::SVGImage::drawForContainer):
     53
     54            drawForContainer lays out the SVG content for a specific container size and renders it.
     55            The logic is fairly straightforward but a note about the scales and zooms here:
     56                the destination rect parameter is zoomed but not scaled
     57                the source rect parameter is zoomed but not scaled
     58                the context is scaled but not zoomed
     59            SVGImage::draw(...) only accepts a source and destination rect but does not consider
     60            scale or zoom. Therefore, drawForContainer removes the zoom component from the source
     61            so SVGImage::draw(...) will draw from the pre-zoom source to the post-zoom destination.
     62
     63        (WebCore::SVGImage::drawPatternForContainer):
     64
     65            For performance, drawPatternForContainer renders the SVG content onto a bitmap, then
     66            has the bitmap image draw the pattern. This is necessary because drawPattern is used
     67            for tiling.
     68
     69        (WebCore):
     70        (WebCore::SVGImage::startAnimation):
     71        (WebCore::SVGImage::stopAnimation):
     72        (WebCore::SVGImage::resetAnimation):
     73        (WebCore::SVGImage::reportMemoryUsage):
     74        * svg/graphics/SVGImage.h:
     75        (WebCore):
     76        (SVGImage):
     77        * svg/graphics/SVGImageCache.cpp:
     78
     79            Instead of storing a SizeAndScales values for each renderer, a SVGImageForContainer
     80            is stored which is just a thin wrapper around an SVG image that contains container
     81            sizing information. By combining the image and size information, the two maps of
     82            SVGImageCache have been merged into one.
     83
     84            To make this patch easier to review, SVGImageCache still exists and works similar to
     85            how it did before the patch. Now, SVGImageCache simply stores the SVGImageForContainers.
     86            In a followup patch it will be removed.
     87
     88            Note: the redraw timer of SVGImageCache has been removed because animation
     89            invalidation is now properly propagated back to the image clients.
     90
     91        (WebCore):
     92        (WebCore::SVGImageCache::SVGImageCache):
     93        (WebCore::SVGImageCache::~SVGImageCache):
     94        (WebCore::SVGImageCache::removeClientFromCache):
     95        (WebCore::SVGImageCache::setContainerSizeForRenderer):
     96        (WebCore::SVGImageCache::imageSizeForRenderer):
     97
     98            Previously, this function returned the scaled image size which was incorrect. The image
     99            size is used by clients such as GraphicsContext2D to determine the source size
     100            for drawing the image. draw() accepts zoomed but not scaled values, so this has been
     101            changed.
     102
     103        (WebCore::SVGImageCache::imageForRenderer):
     104
     105            A FIXME has been added here to not set the scale on every lookup. This can be improved
     106            by setting the page scale factor in setContainerSizeForRenderer() in a future patch.
     107
     108        * svg/graphics/SVGImageCache.h:
     109        (WebCore):
     110        (SVGImageCache):
     111        * svg/graphics/SVGImageForContainer.cpp: Added.
     112        (WebCore):
     113
     114            SVGImageForContainer is a thin wrapper around an SVG image. The lifetime of the
     115            SVGImage will be longer than the image cache.
     116
     117        (WebCore::SVGImageForContainer::size):
     118
     119            This is the only logic in SVGImageForContainer. The size returned needs to be zoomed
     120            but not scaled because it is used (e.g., by RenderImage) to pass back into draw() which
     121            takes zoomed but not scaled values.
     122
     123        (WebCore::SVGImageForContainer::draw):
     124        (WebCore::SVGImageForContainer::drawPattern):
     125        * svg/graphics/SVGImageForContainer.h: Added.
     126        (WebCore):
     127        (SVGImageForContainer):
     128
     129            In a future patch SVGImageForContainer can be made immutable but without a refactoring
     130            for not setting the page scale factor in SVGImageCache::lookupOrCreateImageForRenderer,
     131            setters are needed.
     132
     133        (WebCore::SVGImageForContainer::create):
     134        (WebCore::SVGImageForContainer::containerSize):
     135        (WebCore::SVGImageForContainer::pageScale):
     136        (WebCore::SVGImageForContainer::zoom):
     137        (WebCore::SVGImageForContainer::setSize):
     138        (WebCore::SVGImageForContainer::setZoom):
     139        (WebCore::SVGImageForContainer::setPageScale):
     140        (WebCore::SVGImageForContainer::SVGImageForContainer):
     141        (WebCore::SVGImageForContainer::destroyDecodedData):
     142        (WebCore::SVGImageForContainer::decodedSize):
     143
    11442013-02-12  Antti Koivisto  <antti@apple.com>
    2145
  • trunk/Source/WebCore/GNUmakefile.list.am

    r142739 r142765  
    49264926        Source/WebCore/svg/graphics/SVGImageCache.h \
    49274927        Source/WebCore/svg/graphics/SVGImageChromeClient.h \
     4928        Source/WebCore/svg/graphics/SVGImageForContainer.cpp \
     4929        Source/WebCore/svg/graphics/SVGImageForContainer.h \
    49284930        Source/WebCore/svg/graphics/SVGImage.cpp \
    49294931        Source/WebCore/svg/graphics/SVGImage.h \
  • trunk/Source/WebCore/Target.pri

    r142739 r142765  
    26542654    svg/graphics/SVGImage.h \
    26552655    svg/graphics/SVGImageCache.h \
     2656    svg/graphics/SVGImageForContainer.h \
    26562657    svg/properties/SVGAttributeToPropertyMap.h \
    26572658    svg/properties/SVGAnimatedEnumerationPropertyTearOff.h \
     
    37753776        svg/graphics/SVGImage.cpp \
    37763777        svg/graphics/SVGImageCache.cpp \
     3778        svg/graphics/SVGImageForContainer.cpp \
    37773779        svg/properties/SVGAttributeToPropertyMap.cpp \
    37783780        svg/properties/SVGPathSegListPropertyTearOff.cpp \
  • trunk/Source/WebCore/WebCore.gypi

    r142739 r142765  
    51165116            'svg/graphics/SVGImage.cpp',
    51175117            'svg/graphics/SVGImage.h',
     5118            'svg/graphics/SVGImageForContainer.h',
     5119            'svg/graphics/SVGImageForContainer.cpp',
    51185120            'svg/graphics/filters/SVGFEImage.cpp',
    51195121            'svg/graphics/filters/SVGFEImage.h',
  • trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj

    r142739 r142765  
    7462674626                                        >
    7462774627                                </File>
     74628                                <File
     74629                                        RelativePath="..\svg\graphics\SVGImageForContainer.cpp"
     74630                                        >
     74631                                </File>
     74632                                <File
     74633                                        RelativePath="..\svg\graphics\SVGImageForContainer.h"
     74634                                        >
     74635                                </File>
    7462874636                                <Filter
    7462974637                                        Name="filters"
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r142739 r142765  
    220220                08F859D41463F9CD0067D933 /* SVGImageCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08F859D21463F9CD0067D933 /* SVGImageCache.cpp */; };
    221221                08F859D51463F9CD0067D933 /* SVGImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 08F859D31463F9CD0067D933 /* SVGImageCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
     222                08F859D41463F9CD0067D934 /* SVGImageForContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08F859D21463F9CD0067D934 /* SVGImageForContainer.cpp */; };
     223                08F859D51463F9CD0067D934 /* SVGImageForContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 08F859D31463F9CD0067D934 /* SVGImageForContainer.h */; settings = {ATTRIBUTES = (Private, ); }; };
    222224                08FB17C113BC7E9100040086 /* SVGAttributeToPropertyMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08FB17C013BC7E9100040086 /* SVGAttributeToPropertyMap.cpp */; };
    223225                08FB3F8413BC754C0099FC18 /* SVGAttributeToPropertyMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 08FB3F8313BC754C0099FC18 /* SVGAttributeToPropertyMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    74947496                08F859D21463F9CD0067D933 /* SVGImageCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGImageCache.cpp; sourceTree = "<group>"; };
    74957497                08F859D31463F9CD0067D933 /* SVGImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGImageCache.h; sourceTree = "<group>"; };
     7498                08F859D21463F9CD0067D934 /* SVGImageForContainer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGImageForContainer.cpp; sourceTree = "<group>"; };
     7499                08F859D31463F9CD0067D934 /* SVGImageForContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGImageForContainer.h; sourceTree = "<group>"; };
    74967500                08FB17C013BC7E9100040086 /* SVGAttributeToPropertyMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAttributeToPropertyMap.cpp; sourceTree = "<group>"; };
    74977501                08FB3F8313BC754C0099FC18 /* SVGAttributeToPropertyMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAttributeToPropertyMap.h; sourceTree = "<group>"; };
     
    2042920433                                08F859D21463F9CD0067D933 /* SVGImageCache.cpp */,
    2043020434                                08F859D31463F9CD0067D933 /* SVGImageCache.h */,
     20435                                08F859D21463F9CD0067D934 /* SVGImageForContainer.cpp */,
     20436                                08F859D31463F9CD0067D934 /* SVGImageForContainer.h */,
    2043120437                                AAC08CED15F933D600F1E188 /* SVGImageChromeClient.h */,
    2043220438                        );
     
    2610026106                                B25599A40D00D8BA00BB825C /* SVGImage.h in Headers */,
    2610126107                                08F859D51463F9CD0067D933 /* SVGImageCache.h in Headers */,
     26108                                08F859D51463F9CD0067D934 /* SVGImageForContainer.h in Headers */,
    2610226109                                AAC08CEF15F933D600F1E188 /* SVGImageChromeClient.h in Headers */,
    2610326110                                B2227A2D0D00BF220071B782 /* SVGImageElement.h in Headers */,
     
    2937629383                                B25599A30D00D8BA00BB825C /* SVGImage.cpp in Sources */,
    2937729384                                08F859D41463F9CD0067D933 /* SVGImageCache.cpp in Sources */,
     29385                                08F859D41463F9CD0067D934 /* SVGImageForContainer.cpp in Sources */,
    2937829386                                B2227A2C0D00BF220071B782 /* SVGImageElement.cpp in Sources */,
    2937929387                                B28C6A290D00C44800334AA4 /* SVGImageLoader.cpp in Sources */,
  • trunk/Source/WebCore/loader/cache/CachedImage.cpp

    r141637 r142765  
    165165    if (!m_image->isSVGImage())
    166166        return m_image.get();
    167     Image* useImage = m_svgImageCache->lookupOrCreateBitmapImageForRenderer(renderer);
     167    Image* useImage = m_svgImageCache->imageForRenderer(renderer);
    168168    if (useImage == Image::nullImage())
    169169        return m_image.get();
     
    216216        return;
    217217    ASSERT(renderer);
     218    ASSERT(containerZoom);
    218219    if (!m_image) {
    219220        m_pendingContainerSizeRequests.set(renderer, SizeAndZoom(containerSize, containerZoom));
     
    313314{
    314315    destroyDecodedData();
    315 #if ENABLE(SVG)
    316     m_svgImageCache.clear();
    317 #endif
    318316    clearImage();
    319317    m_pendingContainerSizeRequests.clear();
     
    485483    if (!image || image != m_image)
    486484        return;
    487 #if ENABLE(SVG)
    488     // We have to update the cached ImageBuffers if the underlying content changed.
    489     if (image->isSVGImage()) {
    490         m_svgImageCache->imageContentChanged();
    491         return;
    492     }
    493 #endif
    494485    notifyObservers(&rect);
    495486}
  • trunk/Source/WebCore/svg/graphics/SVGImage.cpp

    r141570 r142765  
    3535#include "ImageBuffer.h"
    3636#include "ImageObserver.h"
     37#include "IntRect.h"
    3738#include "RenderSVGRoot.h"
    3839#include "SVGDocument.h"
     
    6061}
    6162
    62 void SVGImage::setContainerSize(const IntSize&)
    63 {
    64     // SVGImageCache already intercepted this call, as it stores & caches the desired container sizes & zoom levels.
    65     ASSERT_NOT_REACHED();
     63void SVGImage::setContainerSize(const IntSize& size)
     64{
     65    if (!m_page || !usesContainerSize())
     66        return;
     67
     68    Frame* frame = m_page->mainFrame();
     69    SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement();
     70    if (!rootElement)
     71        return;
     72    RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer());
     73    if (!renderer)
     74        return;
     75
     76    FrameView* view = frameView();
     77    view->resize(this->size());
     78
     79    renderer->setContainerSize(size);
    6680}
    6781
     
    100114}
    101115
    102 void SVGImage::drawSVGToImageBuffer(ImageBuffer* buffer, const FloatSize& size, float zoomAndScale, ShouldClearBuffer shouldClear)
    103 {
    104     // FIXME: This doesn't work correctly with animations. If an image contains animations, that say run for 2 seconds,
    105     // and we currently have one <img> that displays us. If we open another document referencing the same SVGImage it
    106     // will display the document at a time where animations already ran - even though it has its own ImageBuffer.
    107     // We currently don't implement SVGSVGElement::setCurrentTime, and can NOT go back in time, once animations started.
    108     // There's no way to fix this besides avoiding style/attribute mutations from SVGAnimationElement.
    109     ASSERT(buffer);
    110     ASSERT(!size.isEmpty());
    111 
    112     if (!m_page)
    113         return;
    114 
    115     Frame* frame = m_page->mainFrame();
    116     SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement();
    117     if (!rootElement)
    118         return;
    119     RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer());
    120     if (!renderer)
    121         return;
    122 
    123     // Draw image at requested size.
     116void SVGImage::drawForContainer(GraphicsContext* context, const FloatSize containerSize, float zoom, const FloatRect& dstRect,
     117    const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp, BlendMode blendMode)
     118{
     119    if (!m_page)
     120        return;
     121
    124122    ImageObserver* observer = imageObserver();
    125123    ASSERT(observer);
     
    128126    setImageObserver(0);
    129127
    130     // Disable repainting; we don't want deferred repaints to schedule any timers due to this relayout.
    131     frame->view()->beginDisableRepaints();
    132 
    133     IntSize containerSize = roundedIntSize(size);
    134     renderer->setContainerSize(containerSize);
    135     frame->view()->resize(this->size());
    136 
    137     FloatSize scaledContainerSize(size);
    138     scaledContainerSize.scale(zoomAndScale);
    139     IntRect destRect = IntRect(IntPoint(), expandedIntSize(scaledContainerSize));
    140     if (shouldClear == ClearImageBuffer)
    141         buffer->context()->clearRect(destRect);
    142 
    143     // Draw SVG on top of ImageBuffer.
    144     draw(buffer->context(), destRect, IntRect(IntPoint(), containerSize), ColorSpaceDeviceRGB, CompositeSourceOver, BlendModeNormal);
    145 
    146     if (frame->view()->needsLayout())
    147         frame->view()->layout();
     128    IntSize roundedContainerSize = roundedIntSize(containerSize);
     129    setContainerSize(roundedContainerSize);
     130
     131    FloatRect scaledSrc = srcRect;
     132    scaledSrc.scale(1 / zoom);
     133
     134    // Compensate for the container size rounding by adjusting the source rect.
     135    FloatSize adjustedSrcSize = scaledSrc.size();
     136    adjustedSrcSize.scale(roundedContainerSize.width() / containerSize.width(), roundedContainerSize.height() / containerSize.height());
     137    scaledSrc.setSize(adjustedSrcSize);
     138
     139    draw(context, dstRect, scaledSrc, colorSpace, compositeOp, blendMode);
    148140
    149141    setImageObserver(observer);
    150 
    151     frame->view()->endDisableRepaints();
     142}
     143
     144void SVGImage::drawPatternForContainer(GraphicsContext* context, const FloatSize containerSize, float pageScale, float zoom, const FloatRect& srcRect,
     145    const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace colorSpace, CompositeOperator compositeOp, const FloatRect& dstRect)
     146{
     147    FloatSize zoomedContainerSize(containerSize);
     148    zoomedContainerSize.scale(zoom);
     149    FloatRect zoomedContainerRect = FloatRect(FloatPoint(), zoomedContainerSize);
     150
     151    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(expandedIntSize(zoomedContainerSize), pageScale);
     152    drawForContainer(buffer->context(), containerSize, zoom, zoomedContainerRect, zoomedContainerRect, ColorSpaceDeviceRGB, CompositeSourceOver, BlendModeNormal);
     153
     154    RefPtr<Image> image = buffer->copyImage(CopyBackingStore);
     155    image->drawPattern(context, srcRect, patternTransform, phase, colorSpace, compositeOp, dstRect);
    152156}
    153157
     
    251255}
    252256
    253 NativeImagePtr SVGImage::nativeImageForCurrentFrame()
    254 {
    255     // FIXME: In order to support dynamic SVGs we need to have a way to invalidate this
    256     // frame cache, or better yet, not use a cache for tiled drawing at all, instead
    257     // having a tiled drawing callback (hopefully non-virtual).
    258     if (!m_frameCache) {
    259         if (!m_page)
    260             return 0;
    261         OwnPtr<ImageBuffer> buffer = ImageBuffer::create(size(), 1);
    262         if (!buffer) // failed to allocate image
    263             return 0;
    264         draw(buffer->context(), rect(), rect(), ColorSpaceDeviceRGB, CompositeSourceOver, BlendModeNormal);
    265         m_frameCache = buffer->copyImage(CopyBackingStore);
    266     }
    267     return m_frameCache->nativeImageForCurrentFrame();
     257// FIXME: support catchUpIfNecessary.
     258void SVGImage::startAnimation(bool /* catchUpIfNecessary */)
     259{
     260    if (!m_page)
     261        return;
     262    Frame* frame = m_page->mainFrame();
     263    SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement();
     264    if (!rootElement)
     265        return;
     266    rootElement->unpauseAnimations();
     267    rootElement->setCurrentTime(0);
     268}
     269
     270void SVGImage::stopAnimation()
     271{
     272    if (!m_page)
     273        return;
     274    Frame* frame = m_page->mainFrame();
     275    SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement();
     276    if (!rootElement)
     277        return;
     278    rootElement->pauseAnimations();
     279}
     280
     281void SVGImage::resetAnimation()
     282{
     283    stopAnimation();
     284    startAnimation();
    268285}
    269286
     
    323340    info.addMember(m_chromeClient, "chromeClient");
    324341    info.addMember(m_page, "page");
    325     info.addMember(m_frameCache, "frameCache");
    326342}
    327343
  • trunk/Source/WebCore/svg/graphics/SVGImage.h

    r141637 r142765  
    3939class RenderBox;
    4040class SVGImageChromeClient;
     41class SVGImageForContainer;
    4142
    4243class SVGImage : public Image {
     
    4748    }
    4849
    49     enum ShouldClearBuffer {
    50         ClearImageBuffer,
    51         DontClearImageBuffer
    52     };
    53 
    54     void drawSVGToImageBuffer(ImageBuffer*, const FloatSize&, float, ShouldClearBuffer);
    5550    RenderBox* embeddedContentBox() const;
    5651    FrameView* frameView() const;
     
    6257    virtual bool hasRelativeHeight() const;
    6358
     59    virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) OVERRIDE;
     60    virtual void stopAnimation() OVERRIDE;
     61    virtual void resetAnimation() OVERRIDE;
     62
    6463    virtual void reportMemoryUsage(MemoryObjectInfo*) const OVERRIDE;
    6564
    6665private:
    6766    friend class SVGImageChromeClient;
     67    friend class SVGImageForContainer;
     68
    6869    virtual ~SVGImage();
    6970
     
    8889    SVGImage(ImageObserver*);
    8990    virtual void draw(GraphicsContext*, const FloatRect& fromRect, const FloatRect& toRect, ColorSpace styleColorSpace, CompositeOperator, BlendMode);
    90 
    91     virtual NativeImagePtr nativeImageForCurrentFrame();
     91    void drawForContainer(GraphicsContext*, const FloatSize, float, const FloatRect&, const FloatRect&, ColorSpace, CompositeOperator, BlendMode);
     92    void drawPatternForContainer(GraphicsContext*, const FloatSize, float, float, const FloatRect&, const AffineTransform&,
     93        const FloatPoint&, ColorSpace, CompositeOperator, const FloatRect&);
    9294
    9395    OwnPtr<SVGImageChromeClient> m_chromeClient;
    9496    OwnPtr<Page> m_page;
    95     RefPtr<Image> m_frameCache;
    9697};
    9798}
  • trunk/Source/WebCore/svg/graphics/SVGImageCache.cpp

    r141303 r142765  
    3030#include "RenderSVGRoot.h"
    3131#include "SVGImage.h"
     32#include "SVGImageForContainer.h"
    3233
    3334namespace WebCore {
    3435
    35 static const int timeToKeepCachedBitmapsAfterLastUseInSeconds = 30;
    36 
    3736SVGImageCache::SVGImageCache(SVGImage* svgImage)
    3837    : m_svgImage(svgImage)
    39     , m_redrawTimer(this, &SVGImageCache::redrawTimerFired)
    40     , m_cacheClearTimer(this, &SVGImageCache::cacheClearTimerFired, timeToKeepCachedBitmapsAfterLastUseInSeconds)
    4138{
    4239    ASSERT(m_svgImage);
     
    4542SVGImageCache::~SVGImageCache()
    4643{
    47     m_sizeAndScalesMap.clear();
    48     clearBitmapCache();
    49 }
    50 
    51 void SVGImageCache::clearBitmapCache()
    52 {
    53     ImageDataMap::iterator end = m_imageDataMap.end();
    54     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it) {
    55         // Checks if the client (it->key) is still valid. The client should remove itself from this
    56         // cache before its end of life, otherwise the following ASSERT will crash on pure virtual
    57         // function call or a general crash.
    58         ASSERT(it->key->resourceClientType() == CachedImageClient::expectedType());
    59         delete it->value.buffer;
    60     }
    61 
    62     m_imageDataMap.clear();
     44    m_imageForContainerMap.clear();
    6345}
    6446
     
    6648{
    6749    ASSERT(client);
    68     m_sizeAndScalesMap.remove(client);
    6950
    70     ImageDataMap::iterator it = m_imageDataMap.find(client);
    71     if (it == m_imageDataMap.end())
    72         return;
    73 
    74     delete it->value.buffer;
    75     m_imageDataMap.remove(it);
     51    if (m_imageForContainerMap.contains(client))
     52        m_imageForContainerMap.remove(client);
    7653}
    7754
     
    8360    FloatSize containerSizeWithoutZoom(containerSize);
    8461    containerSizeWithoutZoom.scale(1 / containerZoom);
    85     m_sizeAndScalesMap.set(client, SizeAndScales(containerSizeWithoutZoom, containerZoom));
     62
     63    ImageForContainerMap::iterator imageIt = m_imageForContainerMap.find(client);
     64    if (imageIt == m_imageForContainerMap.end()) {
     65        RefPtr<SVGImageForContainer> image = SVGImageForContainer::create(m_svgImage, containerSizeWithoutZoom, 1, containerZoom);
     66        m_imageForContainerMap.set(client, image);
     67    } else {
     68        imageIt->value->setSize(containerSizeWithoutZoom);
     69        imageIt->value->setZoom(containerZoom);
     70    }
    8671}
    8772
     
    8974{
    9075    IntSize imageSize = m_svgImage->size();
    91 
    9276    if (!renderer)
    9377        return imageSize;
    94     SizeAndScalesMap::const_iterator it = m_sizeAndScalesMap.find(renderer);
    95     if (it == m_sizeAndScalesMap.end())
     78
     79    ImageForContainerMap::const_iterator it = m_imageForContainerMap.find(renderer);
     80    if (it == m_imageForContainerMap.end())
    9681        return imageSize;
    9782
    98     SizeAndScales sizeAndScales = it->value;
    99     if (!sizeAndScales.size.isEmpty()) {
    100         float scale = sizeAndScales.scale;
    101         if (!scale) {
    102             Page* page = renderer->document()->page();
    103             scale = page->deviceScaleFactor() * page->pageScaleFactor();
    104         }
     83    RefPtr<SVGImageForContainer> image = it->value;
     84    FloatSize size = image->containerSize();
     85    if (!size.isEmpty()) {
     86        size.scale(image->zoom());
     87        imageSize.setWidth(size.width());
     88        imageSize.setHeight(size.height());
     89    }
    10590
    106         imageSize.setWidth(scale * sizeAndScales.size.width());
    107         imageSize.setHeight(scale * sizeAndScales.size.height());
    108     }
    10991    return imageSize;
    11092}
    11193
    112 void SVGImageCache::imageContentChanged()
    113 {
    114     ImageDataMap::iterator end = m_imageDataMap.end();
    115     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it)
    116         it->value.imageNeedsUpdate = true;
    117 
    118     // Always redraw on a timer because this method may be invoked from destructors of things we are intending to draw.
    119     if (!m_redrawTimer.isActive())
    120         m_redrawTimer.startOneShot(0);
    121 }
    122 
    123 void SVGImageCache::redraw()
    124 {
    125     ImageDataMap::iterator end = m_imageDataMap.end();
    126     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it) {
    127         ImageData& data = it->value;
    128         if (!data.imageNeedsUpdate)
    129             continue;
    130         // If the content changed we redraw using our existing ImageBuffer.
    131         ASSERT(data.buffer);
    132         ASSERT(data.image);
    133         m_svgImage->drawSVGToImageBuffer(data.buffer, data.sizeAndScales.size, data.sizeAndScales.zoom * data.sizeAndScales.scale, SVGImage::ClearImageBuffer);
    134         data.image = data.buffer->copyImage(CopyBackingStore);
    135         data.imageNeedsUpdate = false;
    136     }
    137     ASSERT(m_svgImage->imageObserver());
    138     m_svgImage->imageObserver()->animationAdvanced(m_svgImage);
    139 }
    140 
    141 void SVGImageCache::redrawTimerFired(Timer<SVGImageCache>*)
    142 {
    143     // We have no guarantee that the frame does not require layout when the timer fired.
    144     // So be sure to check again in case it is still not safe to run redraw.
    145     FrameView* frameView = m_svgImage->frameView();
    146     if (frameView && (frameView->needsLayout() || frameView->isInLayout())) {
    147         if (!m_redrawTimer.isActive())
    148             m_redrawTimer.startOneShot(0);
    149     } else
    150        redraw();
    151 }
    152 
    153 void SVGImageCache::cacheClearTimerFired(DeferrableOneShotTimer<SVGImageCache>*)
    154 {
    155     clearBitmapCache();
    156 }
    157 
    158 Image* SVGImageCache::lookupOrCreateBitmapImageForRenderer(const RenderObject* renderer)
     94// FIXME: This doesn't take into account the animation timeline so animations will not
     95// restart on page load, nor will two animations in different pages have different timelines.
     96Image* SVGImageCache::imageForRenderer(const RenderObject* renderer)
    15997{
    16098    if (!renderer)
    16199        return Image::nullImage();
    162100
    163     const CachedImageClient* client = renderer;
    164 
    165101    // The cache needs to know the size of the renderer before querying an image for it.
    166     SizeAndScalesMap::iterator sizeIt = m_sizeAndScalesMap.find(renderer);
    167     if (sizeIt == m_sizeAndScalesMap.end())
     102    ImageForContainerMap::iterator it = m_imageForContainerMap.find(renderer);
     103    if (it == m_imageForContainerMap.end())
    168104        return Image::nullImage();
    169105
    170     FloatSize size = sizeIt->value.size;
    171     float zoom = sizeIt->value.zoom;
    172     float scale = sizeIt->value.scale;
     106    RefPtr<SVGImageForContainer> image = it->value;
     107    ASSERT(!image->containerSize().isEmpty());
    173108
    174     // FIXME (85335): This needs to take CSS transform scale into account as well.
     109    // FIXME: Set the page scale in setContainerSizeForRenderer instead of looking it up here.
    175110    Page* page = renderer->document()->page();
    176     if (!scale)
    177         scale = page->deviceScaleFactor() * page->pageScaleFactor();
     111    image->setPageScale(page->deviceScaleFactor() * page->pageScaleFactor());
    178112
    179     ASSERT(!size.isEmpty());
    180 
    181     // (Re)schedule the oneshot timer to throw out all the cached ImageBuffers if they remain unused for too long.
    182     m_cacheClearTimer.restart();
    183 
    184     // Lookup image for client in cache and eventually update it.
    185     ImageDataMap::iterator it = m_imageDataMap.find(client);
    186     if (it != m_imageDataMap.end()) {
    187         ImageData& data = it->value;
    188 
    189         // Common case: image size & zoom remained the same.
    190         if (data.sizeAndScales.size == size && data.sizeAndScales.zoom == zoom && data.sizeAndScales.scale == scale)
    191             return data.image.get();
    192 
    193         // If the image size for the client changed, we have to delete the buffer, remove the item from the cache and recreate it.
    194         delete data.buffer;
    195         m_imageDataMap.remove(it);
    196     }
    197 
    198     FloatSize scaledSize(size);
    199     scaledSize.scale(scale * zoom);
    200 
    201     // Create and cache new image and image buffer at requested size.
    202     OwnPtr<ImageBuffer> newBuffer = ImageBuffer::create(expandedIntSize(scaledSize), 1);
    203     if (!newBuffer)
    204         return Image::nullImage();
    205 
    206     m_svgImage->drawSVGToImageBuffer(newBuffer.get(), size, scale * zoom, SVGImage::DontClearImageBuffer);
    207 
    208     RefPtr<Image> newImage = newBuffer->copyImage(CopyBackingStore);
    209     Image* newImagePtr = newImage.get();
    210     ASSERT(newImagePtr);
    211 
    212     m_imageDataMap.add(client, ImageData(newBuffer.leakPtr(), newImage.release(), SizeAndScales(size, zoom, scale)));
    213     return newImagePtr;
     113    return image.get();
    214114}
    215115
  • trunk/Source/WebCore/svg/graphics/SVGImageCache.h

    r141303 r142765  
    2525#include "Image.h"
    2626#include "IntSize.h"
    27 #include "Timer.h"
    2827#include <wtf/HashMap.h>
    2928#include <wtf/PassOwnPtr.h>
     
    3635class ImageBuffer;
    3736class SVGImage;
     37class SVGImageForContainer;
    3838class RenderObject;
    3939
     
    4848    }
    4949
    50     struct SizeAndScales {
    51         SizeAndScales()
    52             : zoom(1)
    53             , scale(0)
    54         {
    55         }
    56 
    57         SizeAndScales(const FloatSize& newSize, float newZoom, float newScale)
    58             : size(newSize)
    59             , zoom(newZoom)
    60             , scale(newScale)
    61         {
    62         }
    63 
    64         SizeAndScales(const FloatSize& newSize, float newZoom)
    65             : size(newSize)
    66             , zoom(newZoom)
    67             , scale(0)
    68         {
    69         }
    70 
    71         FloatSize size; // This is the container size without zoom.
    72         float zoom;
    73         float scale; // A scale of 0 indicates that the default scale should be used.
    74     };
    75 
    7650    void removeClientFromCache(const CachedImageClient*);
    7751
     
    7953    IntSize imageSizeForRenderer(const RenderObject*) const;
    8054
    81     Image* lookupOrCreateBitmapImageForRenderer(const RenderObject*);
    82     void imageContentChanged();
     55    Image* imageForRenderer(const RenderObject*);
    8356
    8457private:
    8558    SVGImageCache(SVGImage*);
    86     void redraw();
    87     void redrawTimerFired(Timer<SVGImageCache>*);
    88     void cacheClearTimerFired(DeferrableOneShotTimer<SVGImageCache>*);
    89     void clearBitmapCache();
    9059
    91     struct ImageData {
    92         ImageData()
    93             : imageNeedsUpdate(false)
    94             , buffer(0)
    95         {
    96         }
    97 
    98         ImageData(ImageBuffer* newBuffer, PassRefPtr<Image> newImage, const SizeAndScales& newSizeAndScales)
    99             : imageNeedsUpdate(false)
    100             , sizeAndScales(newSizeAndScales)
    101             , buffer(newBuffer)
    102             , image(newImage)
    103         {
    104         }
    105 
    106         bool imageNeedsUpdate;
    107         SizeAndScales sizeAndScales;
    108 
    109         ImageBuffer* buffer;
    110         RefPtr<Image> image;
    111     };
    112 
    113     typedef HashMap<const CachedImageClient*, SizeAndScales> SizeAndScalesMap;
    114     typedef HashMap<const CachedImageClient*, ImageData> ImageDataMap;
     60    typedef HashMap<const CachedImageClient*, RefPtr<SVGImageForContainer> > ImageForContainerMap;
    11561
    11662    SVGImage* m_svgImage;
    117     SizeAndScalesMap m_sizeAndScalesMap;
    118     ImageDataMap m_imageDataMap;
    119     Timer<SVGImageCache> m_redrawTimer;
    120     DeferrableOneShotTimer<SVGImageCache> m_cacheClearTimer;
     63    ImageForContainerMap m_imageForContainerMap;
    12164};
    12265
Note: See TracChangeset for help on using the changeset viewer.