Changeset 143541 in webkit


Ignore:
Timestamp:
Feb 20, 2013 5:19:25 PM (11 years ago)
Author:
pdr@google.com
Message:

Account for transform in SVG background images
https://bugs.webkit.org/show_bug.cgi?id=110295

Reviewed by Dirk Schulze.

Source/WebCore:

Tiled SVG background images are rendererd by drawing the SVG content into a temporary
image buffer, then stamping out a tiled pattern using this buffer. Previously the
image buffer did not account for CSS transforms which could result in pixelated backgrounds.

This patch takes advantage of the context's transform when sizing the temporary tiling
image buffer. Because the context's transform also includes scale, this patch simplifies
the SVG image code to no longer track scale.

Test: svg/as-background-image/svg-transformed-background.html

  • loader/cache/CachedImage.cpp:

(WebCore):
(WebCore::CachedImage::imageForRenderer):

CachedImage::lookupOrCreateImageForRenderer no longer creates images so it has been
refactored into just "imageForRenderer". Previously there were two versions of
lookupOrCreateImageForRenderer; these have been folded into imageForRenderer.

  • loader/cache/CachedImage.h:
  • svg/graphics/SVGImage.cpp:

(WebCore::SVGImage::drawPatternForContainer):

To create the temporary tiling image buffer, the final size in screen coordinates is
needed. This is now computed using the current context's CTM. Because the CTM
already includes the page scale, all page scale tracking can be removed.

The adjustments to srcRect and the pattern transform are the same as before, just
refactored to use imageBufferScale which has x and y components.

  • svg/graphics/SVGImage.h:
  • svg/graphics/SVGImageCache.cpp:

(WebCore::SVGImageCache::setContainerSizeForRenderer):

Because the page scale needed to be cached between calls to
setContainerSizeForRenderer, this function was written to modify an existing cache
entry. Because the page scale no longer needs to be tracked, this code has been
simplified to re-write any existing cache entry.

(WebCore::SVGImageCache::imageSizeForRenderer):

This function has been simplified by calling SVGImageForContainer::size() instead
of computing this value manually. The value returned remains the same, containing
the container size multiplied by zoom.

(WebCore::SVGImageCache::imageForRenderer):

Previously we set the page scale on every call to imageForRenderer. Because page scale
no longer needs to be tracked, this function has been simplified to simply return
the cached SVGImageForContainer.

  • svg/graphics/SVGImageForContainer.cpp:

(WebCore::SVGImageForContainer::drawPattern):

  • svg/graphics/SVGImageForContainer.h:

(WebCore::SVGImageForContainer::create):
(WebCore::SVGImageForContainer::SVGImageForContainer):
(SVGImageForContainer):

LayoutTests:

  • svg/as-background-image/svg-transformed-background-expected.html: Added.
  • svg/as-background-image/svg-transformed-background.html: Added.
Location:
trunk
Files:
2 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r143539 r143541  
     12013-02-20  Philip Rogers  <pdr@google.com>
     2
     3        Account for transform in SVG background images
     4        https://bugs.webkit.org/show_bug.cgi?id=110295
     5
     6        Reviewed by Dirk Schulze.
     7
     8        * svg/as-background-image/svg-transformed-background-expected.html: Added.
     9        * svg/as-background-image/svg-transformed-background.html: Added.
     10
    1112013-02-20  Ojan Vafai  <ojan@chromium.org>
    212
  • trunk/Source/WebCore/ChangeLog

    r143540 r143541  
     12013-02-20  Philip Rogers  <pdr@google.com>
     2
     3        Account for transform in SVG background images
     4        https://bugs.webkit.org/show_bug.cgi?id=110295
     5
     6        Reviewed by Dirk Schulze.
     7
     8        Tiled SVG background images are rendererd by drawing the SVG content into a temporary
     9        image buffer, then stamping out a tiled pattern using this buffer. Previously the
     10        image buffer did not account for CSS transforms which could result in pixelated backgrounds.
     11
     12        This patch takes advantage of the context's transform when sizing the temporary tiling
     13        image buffer. Because the context's transform also includes scale, this patch simplifies
     14        the SVG image code to no longer track scale.
     15
     16        Test: svg/as-background-image/svg-transformed-background.html
     17
     18        * loader/cache/CachedImage.cpp:
     19        (WebCore):
     20        (WebCore::CachedImage::imageForRenderer):
     21
     22            CachedImage::lookupOrCreateImageForRenderer no longer creates images so it has been
     23            refactored into just "imageForRenderer". Previously there were two versions of
     24            lookupOrCreateImageForRenderer; these have been folded into imageForRenderer.
     25
     26        * loader/cache/CachedImage.h:
     27        * svg/graphics/SVGImage.cpp:
     28        (WebCore::SVGImage::drawPatternForContainer):
     29
     30            To create the temporary tiling image buffer, the final size in screen coordinates is
     31            needed. This is now computed using the current context's CTM. Because the CTM
     32            already includes the page scale, all page scale tracking can be removed.
     33
     34            The adjustments to srcRect and the pattern transform are the same as before, just
     35            refactored to use imageBufferScale which has x and y components.
     36
     37        * svg/graphics/SVGImage.h:
     38        * svg/graphics/SVGImageCache.cpp:
     39        (WebCore::SVGImageCache::setContainerSizeForRenderer):
     40
     41            Because the page scale needed to be cached between calls to
     42            setContainerSizeForRenderer, this function was written to modify an existing cache
     43            entry. Because the page scale no longer needs to be tracked, this code has been
     44            simplified to re-write any existing cache entry.
     45
     46        (WebCore::SVGImageCache::imageSizeForRenderer):
     47
     48            This function has been simplified by calling SVGImageForContainer::size() instead
     49            of computing this value manually. The value returned remains the same, containing
     50            the container size multiplied by zoom.
     51
     52        (WebCore::SVGImageCache::imageForRenderer):
     53
     54            Previously we set the page scale on every call to imageForRenderer. Because page scale
     55            no longer needs to be tracked, this function has been simplified to simply return
     56            the cached SVGImageForContainer.
     57
     58        * svg/graphics/SVGImageForContainer.cpp:
     59        (WebCore::SVGImageForContainer::drawPattern):
     60        * svg/graphics/SVGImageForContainer.h:
     61        (WebCore::SVGImageForContainer::create):
     62        (WebCore::SVGImageForContainer::SVGImageForContainer):
     63        (SVGImageForContainer):
     64
    1652013-02-20  Jer Noble  <jer.noble@apple.com>
    266
  • trunk/Source/WebCore/loader/cache/CachedImage.cpp

    r142765 r143541  
    158158}
    159159
    160 #if ENABLE(SVG)
    161 inline Image* CachedImage::lookupOrCreateImageForRenderer(const RenderObject* renderer)
    162 {
    163     if (!m_image)
    164         return 0;
    165     if (!m_image->isSVGImage())
    166         return m_image.get();
    167     Image* useImage = m_svgImageCache->imageForRenderer(renderer);
    168     if (useImage == Image::nullImage())
    169         return m_image.get();
    170     return useImage;
    171 }
    172 #else
    173 inline Image* CachedImage::lookupOrCreateImageForRenderer(const RenderObject*)
    174 {
    175     return m_image.get();
    176 }
    177 #endif
    178 
    179160Image* CachedImage::image()
    180161{
     
    205186    }
    206187
    207     if (m_image)
    208         return lookupOrCreateImageForRenderer(renderer);
    209 
    210     return Image::nullImage();
     188    if (!m_image)
     189        return Image::nullImage();
     190
     191#if ENABLE(SVG)
     192    if (m_image->isSVGImage()) {
     193        Image* image = m_svgImageCache->imageForRenderer(renderer);
     194        if (image != Image::nullImage())
     195            return image;
     196    }
     197#else
     198    UNUSED_PARAM(renderer);
     199#endif
     200    return m_image.get();
    211201}
    212202
  • trunk/Source/WebCore/loader/cache/CachedImage.h

    r141637 r143541  
    9898
    9999private:
    100     Image* lookupOrCreateImageForRenderer(const RenderObject*);
    101 
    102100    void clear();
    103101
  • trunk/Source/WebCore/svg/graphics/SVGImage.cpp

    r143257 r143541  
    142142}
    143143
    144 void SVGImage::drawPatternForContainer(GraphicsContext* context, const FloatSize containerSize, float pageScale, float zoom, const FloatRect& srcRect,
     144void SVGImage::drawPatternForContainer(GraphicsContext* context, const FloatSize containerSize, float zoom, const FloatRect& srcRect,
    145145    const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace colorSpace, CompositeOperator compositeOp, const FloatRect& dstRect)
    146146{
    147     ASSERT(pageScale);
    148 
    149147    FloatRect zoomedContainerRect = FloatRect(FloatPoint(), containerSize);
    150148    zoomedContainerRect.scale(zoom);
    151     FloatRect zoomedAndScaledContainerRect = zoomedContainerRect;
    152     zoomedAndScaledContainerRect.scale(pageScale);
    153 
    154     // FIXME(WK110065): This should take advantage of the ImageBuffer resolution instead of scaling the buffer manually.
    155     OwnPtr<ImageBuffer> buffer = ImageBuffer::create(expandedIntSize(zoomedAndScaledContainerRect.size()), 1);
    156     drawForContainer(buffer->context(), containerSize, zoom, zoomedAndScaledContainerRect, zoomedContainerRect, ColorSpaceDeviceRGB, CompositeSourceOver, BlendModeNormal);
     149
     150    // The ImageBuffer size needs to be scaled to match the final resolution.
     151    AffineTransform transform = context->getCTM();
     152    FloatSize imageBufferScale = FloatSize(transform.xScale(), transform.yScale());
     153    ASSERT(imageBufferScale.width());
     154    ASSERT(imageBufferScale.height());
     155
     156    FloatRect imageBufferSize = zoomedContainerRect;
     157    imageBufferSize.scale(imageBufferScale.width(), imageBufferScale.height());
     158
     159    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(expandedIntSize(imageBufferSize.size()), 1);
     160    drawForContainer(buffer->context(), containerSize, zoom, imageBufferSize, zoomedContainerRect, ColorSpaceDeviceRGB, CompositeSourceOver, BlendModeNormal);
    157161    RefPtr<Image> image = buffer->copyImage(CopyBackingStore, Unscaled);
    158162
    159     // Adjust the source rect and transform for image buffer scale due to pageScale.
     163    // Adjust the source rect and transform due to the image buffer's scaling.
    160164    FloatRect scaledSrcRect = srcRect;
    161     scaledSrcRect.scale(pageScale);
     165    scaledSrcRect.scale(imageBufferScale.width(), imageBufferScale.height());
    162166    AffineTransform unscaledPatternTransform(patternTransform);
    163     unscaledPatternTransform.scale(1 / pageScale);
     167    unscaledPatternTransform.scale(1 / imageBufferScale.width(), 1 / imageBufferScale.height());
    164168
    165169    image->drawPattern(context, scaledSrcRect, unscaledPatternTransform, phase, colorSpace, compositeOp, dstRect);
  • trunk/Source/WebCore/svg/graphics/SVGImage.h

    r142765 r143541  
    9090    virtual void draw(GraphicsContext*, const FloatRect& fromRect, const FloatRect& toRect, ColorSpace styleColorSpace, CompositeOperator, BlendMode);
    9191    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&);
     92    void drawPatternForContainer(GraphicsContext*, const FloatSize, float, const FloatRect&, const AffineTransform&, const FloatPoint&, ColorSpace,
     93        CompositeOperator, const FloatRect&);
    9494
    9595    OwnPtr<SVGImageChromeClient> m_chromeClient;
  • trunk/Source/WebCore/svg/graphics/SVGImageCache.cpp

    r142765 r143541  
    5757    ASSERT(client);
    5858    ASSERT(!containerSize.isEmpty());
     59    ASSERT(containerZoom);
    5960
    6061    FloatSize containerSizeWithoutZoom(containerSize);
    6162    containerSizeWithoutZoom.scale(1 / containerZoom);
    6263
    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     }
     64    m_imageForContainerMap.set(client, SVGImageForContainer::create(m_svgImage, containerSizeWithoutZoom, containerZoom));
    7165}
    7266
     
    8276
    8377    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     }
    90 
    91     return imageSize;
     78    ASSERT(!image->size().isEmpty());
     79    return image->size();
    9280}
    9381
     
    9987        return Image::nullImage();
    10088
    101     // The cache needs to know the size of the renderer before querying an image for it.
    10289    ImageForContainerMap::iterator it = m_imageForContainerMap.find(renderer);
    10390    if (it == m_imageForContainerMap.end())
     
    10592
    10693    RefPtr<SVGImageForContainer> image = it->value;
    107     ASSERT(!image->containerSize().isEmpty());
    108 
    109     // FIXME: Set the page scale in setContainerSizeForRenderer instead of looking it up here.
    110     Page* page = renderer->document()->page();
    111     image->setPageScale(page->deviceScaleFactor() * page->pageScaleFactor());
    112 
     94    ASSERT(!image->size().isEmpty());
    11395    return image.get();
    11496}
  • trunk/Source/WebCore/svg/graphics/SVGImageForContainer.cpp

    r143046 r143541  
    4646    const FloatPoint& phase, ColorSpace colorSpace, CompositeOperator compositeOp, const FloatRect& dstRect, BlendMode)
    4747{
    48     m_image->drawPatternForContainer(context, m_containerSize, m_pageScale, m_zoom, srcRect, patternTransform, phase, colorSpace, compositeOp, dstRect);
     48    m_image->drawPatternForContainer(context, m_containerSize, m_zoom, srcRect, patternTransform, phase, colorSpace, compositeOp, dstRect);
    4949}
    5050
  • trunk/Source/WebCore/svg/graphics/SVGImageForContainer.h

    r143046 r143541  
    3939class SVGImageForContainer : public Image {
    4040public:
    41     static PassRefPtr<SVGImageForContainer> create(SVGImage* image, const FloatSize& containerSize, float pageScale, float zoom)
     41    static PassRefPtr<SVGImageForContainer> create(SVGImage* image, const FloatSize& containerSize, float zoom)
    4242    {
    43         return adoptRef(new SVGImageForContainer(image, containerSize, pageScale, zoom));
     43        return adoptRef(new SVGImageForContainer(image, containerSize, zoom));
    4444    }
    4545
     
    6363    virtual bool currentFrameKnownToBeOpaque() OVERRIDE { return false; }
    6464
    65     FloatSize containerSize() { return m_containerSize; }
    66     float pageScale() { return m_pageScale; }
    67     float zoom() { return m_zoom; }
    68 
    69     void setSize(FloatSize& size) { m_containerSize = size; }
    70     void setZoom(float zoom) { m_zoom = zoom; }
    71     void setPageScale(float pageScale) { m_pageScale = pageScale; }
    72 
    7365private:
    74     SVGImageForContainer(SVGImage* image, const FloatSize& containerSize, float pageScale, float zoom)
    75         : m_image(image), m_containerSize(containerSize), m_pageScale(pageScale), m_zoom(zoom) { }
     66    SVGImageForContainer(SVGImage* image, const FloatSize& containerSize, float zoom)
     67        : m_image(image)
     68        , m_containerSize(containerSize)
     69        , m_zoom(zoom)
     70    {
     71    }
    7672
    7773    virtual void destroyDecodedData(bool /*destroyAll*/ = true) { }
     
    7975
    8076    SVGImage* m_image;
    81     FloatSize m_containerSize;
    82     float m_pageScale;
    83     float m_zoom;
     77    const FloatSize m_containerSize;
     78    const float m_zoom;
    8479};
    8580}
Note: See TracChangeset for help on using the changeset viewer.