| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006 Eric Seidel <eric@webkit.org> | 2 * Copyright (C) 2006 Eric Seidel <eric@webkit.org> |
| 3 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. | 3 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. |
| 4 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 4 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
| 5 * | 5 * |
| 6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
| 8 * are met: | 8 * are met: |
| 9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 #include "config.h" | 28 #include "config.h" |
| 29 | 29 |
| 30 #if ENABLE(SVG) | 30 #if ENABLE(SVG) |
| 31 #include "SVGImage.h" | 31 #include "SVGImage.h" |
| 32 | 32 |
| 33 #include "DocumentLoader.h" | 33 #include "DocumentLoader.h" |
| 34 #include "FrameView.h" | 34 #include "FrameView.h" |
| 35 #include "ImageBuffer.h" | 35 #include "ImageBuffer.h" |
| 36 #include "ImageObserver.h" | 36 #include "ImageObserver.h" |
| 37 #include "IntRect.h" |
| 37 #include "RenderSVGRoot.h" | 38 #include "RenderSVGRoot.h" |
| 38 #include "SVGDocument.h" | 39 #include "SVGDocument.h" |
| 39 #include "SVGImageChromeClient.h" | 40 #include "SVGImageChromeClient.h" |
| 40 #include "SVGSVGElement.h" | 41 #include "SVGSVGElement.h" |
| 41 #include "Settings.h" | 42 #include "Settings.h" |
| 42 | 43 |
| 43 namespace WebCore { | 44 namespace WebCore { |
| 44 | 45 |
| 45 SVGImage::SVGImage(ImageObserver* observer) | 46 SVGImage::SVGImage(ImageObserver* observer) |
| 46 : Image(observer) | 47 : Image(observer) |
| 47 { | 48 { |
| 48 } | 49 } |
| 49 | 50 |
| 50 SVGImage::~SVGImage() | 51 SVGImage::~SVGImage() |
| 51 { | 52 { |
| 52 if (m_page) { | 53 if (m_page) { |
| 53 // Store m_page in a local variable, clearing m_page, so that SVGImageCh
romeClient knows we're destructed. | 54 // Store m_page in a local variable, clearing m_page, so that SVGImageCh
romeClient knows we're destructed. |
| 54 OwnPtr<Page> currentPage = m_page.release(); | 55 OwnPtr<Page> currentPage = m_page.release(); |
| 55 currentPage->mainFrame()->loader()->frameDetached(); // Break both the l
oader and view references to the frame | 56 currentPage->mainFrame()->loader()->frameDetached(); // Break both the l
oader and view references to the frame |
| 56 } | 57 } |
| 57 | 58 |
| 58 // Verify that page teardown destroyed the Chrome | 59 // Verify that page teardown destroyed the Chrome |
| 59 ASSERT(!m_chromeClient || !m_chromeClient->image()); | 60 ASSERT(!m_chromeClient || !m_chromeClient->image()); |
| 60 } | 61 } |
| 61 | 62 |
| 62 void SVGImage::setContainerSize(const IntSize&) | 63 void SVGImage::setContainerSize(const IntSize& size) |
| 63 { | 64 { |
| 64 // SVGImageCache already intercepted this call, as it stores & caches the de
sired container sizes & zoom levels. | 65 if (!m_page || !usesContainerSize()) |
| 65 ASSERT_NOT_REACHED(); | 66 return; |
| 67 |
| 68 Frame* frame = m_page->mainFrame(); |
| 69 SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->r
ootElement(); |
| 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); |
| 66 } | 80 } |
| 67 | 81 |
| 68 IntSize SVGImage::size() const | 82 IntSize SVGImage::size() const |
| 69 { | 83 { |
| 70 if (!m_page) | 84 if (!m_page) |
| 71 return IntSize(); | 85 return IntSize(); |
| 72 Frame* frame = m_page->mainFrame(); | 86 Frame* frame = m_page->mainFrame(); |
| 73 SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->r
ootElement(); | 87 SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->r
ootElement(); |
| 74 if (!rootElement) | 88 if (!rootElement) |
| 75 return IntSize(); | 89 return IntSize(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 92 else | 106 else |
| 93 currentSize = rootElement->currentViewBoxRect().size(); | 107 currentSize = rootElement->currentViewBoxRect().size(); |
| 94 | 108 |
| 95 if (!currentSize.isEmpty()) | 109 if (!currentSize.isEmpty()) |
| 96 return IntSize(static_cast<int>(ceilf(currentSize.width())), static_cast
<int>(ceilf(currentSize.height()))); | 110 return IntSize(static_cast<int>(ceilf(currentSize.width())), static_cast
<int>(ceilf(currentSize.height()))); |
| 97 | 111 |
| 98 // As last resort, use CSS default intrinsic size. | 112 // As last resort, use CSS default intrinsic size. |
| 99 return IntSize(300, 150); | 113 return IntSize(300, 150); |
| 100 } | 114 } |
| 101 | 115 |
| 102 void SVGImage::drawSVGToImageBuffer(ImageBuffer* buffer, const FloatSize& size,
float zoomAndScale, ShouldClearBuffer shouldClear) | 116 void SVGImage::drawForContainer(GraphicsContext* context, const FloatSize contai
nerSize, float zoom, const FloatRect& dstRect, |
| 117 const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator composite
Op, BlendMode blendMode) |
| 103 { | 118 { |
| 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 docu
ment referencing the same SVGImage it | |
| 106 // will display the document at a time where animations already ran - even t
hough it has its own ImageBuffer. | |
| 107 // We currently don't implement SVGSVGElement::setCurrentTime, and can NOT g
o back in time, once animations started. | |
| 108 // There's no way to fix this besides avoiding style/attribute mutations fro
m SVGAnimationElement. | |
| 109 ASSERT(buffer); | |
| 110 ASSERT(!size.isEmpty()); | |
| 111 | |
| 112 if (!m_page) | 119 if (!m_page) |
| 113 return; | 120 return; |
| 114 | 121 |
| 115 Frame* frame = m_page->mainFrame(); | |
| 116 SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->r
ootElement(); | |
| 117 if (!rootElement) | |
| 118 return; | |
| 119 RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer()); | |
| 120 if (!renderer) | |
| 121 return; | |
| 122 | |
| 123 // Draw image at requested size. | |
| 124 ImageObserver* observer = imageObserver(); | 122 ImageObserver* observer = imageObserver(); |
| 125 ASSERT(observer); | 123 ASSERT(observer); |
| 126 | 124 |
| 127 // Temporarily reset image observer, we don't want to receive any changeInRe
ct() calls due to this relayout. | 125 // Temporarily reset image observer, we don't want to receive any changeInRe
ct() calls due to this relayout. |
| 128 setImageObserver(0); | 126 setImageObserver(0); |
| 129 | 127 |
| 130 // Disable repainting; we don't want deferred repaints to schedule any timer
s due to this relayout. | 128 IntSize roundedContainerSize = roundedIntSize(containerSize); |
| 131 frame->view()->beginDisableRepaints(); | 129 setContainerSize(roundedContainerSize); |
| 132 | 130 |
| 133 IntSize containerSize = roundedIntSize(size); | 131 FloatRect scaledSrc = srcRect; |
| 134 renderer->setContainerSize(containerSize); | 132 scaledSrc.scale(1 / zoom); |
| 135 frame->view()->resize(this->size()); | |
| 136 | 133 |
| 137 FloatSize scaledContainerSize(size); | 134 // Compensate for the container size rounding by adjusting the source rect. |
| 138 scaledContainerSize.scale(zoomAndScale); | 135 FloatSize adjustedSrcSize = scaledSrc.size(); |
| 139 IntRect destRect = IntRect(IntPoint(), expandedIntSize(scaledContainerSize))
; | 136 adjustedSrcSize.scale(roundedContainerSize.width() / containerSize.width(),
roundedContainerSize.height() / containerSize.height()); |
| 140 if (shouldClear == ClearImageBuffer) | 137 scaledSrc.setSize(adjustedSrcSize); |
| 141 buffer->context()->clearRect(destRect); | |
| 142 | 138 |
| 143 // Draw SVG on top of ImageBuffer. | 139 draw(context, dstRect, scaledSrc, colorSpace, compositeOp, blendMode); |
| 144 draw(buffer->context(), destRect, IntRect(IntPoint(), containerSize), ColorS
paceDeviceRGB, CompositeSourceOver, BlendModeNormal); | |
| 145 | |
| 146 if (frame->view()->needsLayout()) | |
| 147 frame->view()->layout(); | |
| 148 | 140 |
| 149 setImageObserver(observer); | 141 setImageObserver(observer); |
| 142 } |
| 150 | 143 |
| 151 frame->view()->endDisableRepaints(); | 144 void 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(zoomedConta
inerSize), 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, co
mpositeOp, dstRect); |
| 152 } | 156 } |
| 153 | 157 |
| 154 void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const Fl
oatRect& srcRect, ColorSpace, CompositeOperator compositeOp, BlendMode) | 158 void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const Fl
oatRect& srcRect, ColorSpace, CompositeOperator compositeOp, BlendMode) |
| 155 { | 159 { |
| 156 if (!m_page) | 160 if (!m_page) |
| 157 return; | 161 return; |
| 158 | 162 |
| 159 FrameView* view = frameView(); | 163 FrameView* view = frameView(); |
| 160 | 164 |
| 161 GraphicsContextStateSaver stateSaver(*context); | 165 GraphicsContextStateSaver stateSaver(*context); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 intrinsicWidth = rootElement->intrinsicWidth(); | 247 intrinsicWidth = rootElement->intrinsicWidth(); |
| 244 intrinsicHeight = rootElement->intrinsicHeight(); | 248 intrinsicHeight = rootElement->intrinsicHeight(); |
| 245 if (rootElement->preserveAspectRatio().align() == SVGPreserveAspectRatio::SV
G_PRESERVEASPECTRATIO_NONE) | 249 if (rootElement->preserveAspectRatio().align() == SVGPreserveAspectRatio::SV
G_PRESERVEASPECTRATIO_NONE) |
| 246 return; | 250 return; |
| 247 | 251 |
| 248 intrinsicRatio = rootElement->viewBox().size(); | 252 intrinsicRatio = rootElement->viewBox().size(); |
| 249 if (intrinsicRatio.isEmpty() && intrinsicWidth.isFixed() && intrinsicHeight.
isFixed()) | 253 if (intrinsicRatio.isEmpty() && intrinsicWidth.isFixed() && intrinsicHeight.
isFixed()) |
| 250 intrinsicRatio = FloatSize(floatValueForLength(intrinsicWidth, 0), float
ValueForLength(intrinsicHeight, 0)); | 254 intrinsicRatio = FloatSize(floatValueForLength(intrinsicWidth, 0), float
ValueForLength(intrinsicHeight, 0)); |
| 251 } | 255 } |
| 252 | 256 |
| 253 NativeImagePtr SVGImage::nativeImageForCurrentFrame() | 257 // FIXME: support catchUpIfNecessary. |
| 258 void SVGImage::startAnimation(bool /* catchUpIfNecessary */) |
| 254 { | 259 { |
| 255 // FIXME: In order to support dynamic SVGs we need to have a way to invalida
te this | 260 if (!m_page) |
| 256 // frame cache, or better yet, not use a cache for tiled drawing at all, ins
tead | 261 return; |
| 257 // having a tiled drawing callback (hopefully non-virtual). | 262 Frame* frame = m_page->mainFrame(); |
| 258 if (!m_frameCache) { | 263 SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->r
ootElement(); |
| 259 if (!m_page) | 264 if (!rootElement) |
| 260 return 0; | 265 return; |
| 261 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(size(), 1); | 266 rootElement->unpauseAnimations(); |
| 262 if (!buffer) // failed to allocate image | 267 rootElement->setCurrentTime(0); |
| 263 return 0; | 268 } |
| 264 draw(buffer->context(), rect(), rect(), ColorSpaceDeviceRGB, CompositeSo
urceOver, BlendModeNormal); | 269 |
| 265 m_frameCache = buffer->copyImage(CopyBackingStore); | 270 void SVGImage::stopAnimation() |
| 266 } | 271 { |
| 267 return m_frameCache->nativeImageForCurrentFrame(); | 272 if (!m_page) |
| 273 return; |
| 274 Frame* frame = m_page->mainFrame(); |
| 275 SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->r
ootElement(); |
| 276 if (!rootElement) |
| 277 return; |
| 278 rootElement->pauseAnimations(); |
| 279 } |
| 280 |
| 281 void SVGImage::resetAnimation() |
| 282 { |
| 283 stopAnimation(); |
| 284 startAnimation(); |
| 268 } | 285 } |
| 269 | 286 |
| 270 bool SVGImage::dataChanged(bool allDataReceived) | 287 bool SVGImage::dataChanged(bool allDataReceived) |
| 271 { | 288 { |
| 272 // Don't do anything if is an empty image. | 289 // Don't do anything if is an empty image. |
| 273 if (!data()->size()) | 290 if (!data()->size()) |
| 274 return true; | 291 return true; |
| 275 | 292 |
| 276 if (allDataReceived) { | 293 if (allDataReceived) { |
| 277 static FrameLoaderClient* dummyFrameLoaderClient = new EmptyFrameLoader
Client; | 294 static FrameLoaderClient* dummyFrameLoaderClient = new EmptyFrameLoader
Client; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 { | 332 { |
| 316 return "svg"; | 333 return "svg"; |
| 317 } | 334 } |
| 318 | 335 |
| 319 void SVGImage::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const | 336 void SVGImage::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const |
| 320 { | 337 { |
| 321 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CachedResou
rceImage); | 338 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CachedResou
rceImage); |
| 322 Image::reportMemoryUsage(memoryObjectInfo); | 339 Image::reportMemoryUsage(memoryObjectInfo); |
| 323 info.addMember(m_chromeClient, "chromeClient"); | 340 info.addMember(m_chromeClient, "chromeClient"); |
| 324 info.addMember(m_page, "page"); | 341 info.addMember(m_page, "page"); |
| 325 info.addMember(m_frameCache, "frameCache"); | |
| 326 } | 342 } |
| 327 | 343 |
| 328 } | 344 } |
| 329 | 345 |
| 330 #endif // ENABLE(SVG) | 346 #endif // ENABLE(SVG) |
| OLD | NEW |