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 |