don't discard iframe children.
[kdelibs.git] / khtml / svg / graphics / SVGImage.cpp
blob2a8c0db9c7a1c1af0260f14cfb02e61949106d5b
1 /*
2 * Copyright (C) 2006 Eric Seidel (eric@webkit.org)
3 * Copyright (C) 2008 Apple, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "config.h"
28 #if ENABLE(SVG)
29 #include "SVGImage.h"
31 #include "CachedPage.h"
32 #include "DocumentLoader.h"
33 #include "EditCommand.h"
34 #include "FloatRect.h"
35 #include "Frame.h"
36 #include "FrameLoader.h"
37 #include "FrameView.h"
38 #include "GraphicsContext.h"
39 #include "ImageObserver.h"
40 #include "NotImplemented.h"
41 #include "Page.h"
42 #include "RenderView.h"
43 #include "ResourceError.h"
44 #include "SVGDocument.h"
45 #include "SVGLength.h"
46 #include "SVGRenderSupport.h"
47 #include "SVGSVGElement.h"
48 #include "Settings.h"
50 #include "SVGImageEmptyClients.h"
52 namespace WebCore {
54 SVGImage::SVGImage(ImageObserver* observer)
55 : Image(observer)
56 , m_document(0)
57 , m_page(0)
58 , m_frame(0)
59 , m_frameView(0)
63 SVGImage::~SVGImage()
65 if (m_frame)
66 m_frame->loader()->frameDetached(); // Break both the loader and view references to the frame
69 void SVGImage::setContainerSize(const IntSize& containerSize)
71 if (containerSize.width() <= 0 || containerSize.height() <= 0)
72 return;
74 if (!m_frame || !m_frame->document())
75 return;
76 SVGSVGElement* rootElement = static_cast<SVGDocument*>(m_frame->document())->rootElement();
77 if (!rootElement)
78 return;
80 rootElement->setContainerSize(containerSize);
83 bool SVGImage::usesContainerSize() const
85 if (!m_frame || !m_frame->document())
86 return false;
87 SVGSVGElement* rootElement = static_cast<SVGDocument*>(m_frame->document())->rootElement();
88 if (!rootElement)
89 return false;
91 return rootElement->hasSetContainerSize();
94 IntSize SVGImage::size() const
96 if (!m_frame || !m_frame->document())
97 return IntSize();
99 SVGSVGElement* rootElement = static_cast<SVGDocument*>(m_frame->document())->rootElement();
100 if (!rootElement)
101 return IntSize();
103 SVGLength width = rootElement->width();
104 SVGLength height = rootElement->height();
106 IntSize svgSize;
107 if (width.unitType() == LengthTypePercentage)
108 svgSize.setWidth(rootElement->relativeWidthValue());
109 else
110 svgSize.setWidth(static_cast<int>(width.value()));
112 if (height.unitType() == LengthTypePercentage)
113 svgSize.setHeight(rootElement->relativeHeightValue());
114 else
115 svgSize.setHeight(static_cast<int>(height.value()));
117 return svgSize;
120 bool SVGImage::hasRelativeWidth() const
122 if (!m_frame || !m_frame->document())
123 return false;
124 SVGSVGElement* rootElement = static_cast<SVGDocument*>(m_frame->document())->rootElement();
125 if (!rootElement)
126 return false;
128 return rootElement->width().unitType() == LengthTypePercentage;
131 bool SVGImage::hasRelativeHeight() const
133 if (!m_frame || !m_frame->document())
134 return false;
135 SVGSVGElement* rootElement = static_cast<SVGDocument*>(m_frame->document())->rootElement();
136 if (!rootElement)
137 return false;
139 return rootElement->height().unitType() == LengthTypePercentage;
142 void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp)
144 if (!m_frame)
145 return;
147 context->save();
148 context->setCompositeOperation(compositeOp);
149 context->clip(enclosingIntRect(dstRect));
150 if (compositeOp != CompositeSourceOver)
151 context->beginTransparencyLayer(1.0f);
152 context->translate(dstRect.location().x(), dstRect.location().y());
153 context->scale(FloatSize(dstRect.width()/srcRect.width(), dstRect.height()/srcRect.height()));
155 if (m_frame->view()->needsLayout())
156 m_frame->view()->layout();
157 m_frame->paint(context, enclosingIntRect(srcRect));
159 if (compositeOp != CompositeSourceOver)
160 context->endTransparencyLayer();
162 context->restore();
164 if (imageObserver())
165 imageObserver()->didDraw(this);
168 NativeImagePtr SVGImage::nativeImageForCurrentFrame()
170 // FIXME: In order to support dynamic SVGs we need to have a way to invalidate this
171 // frame cache, or better yet, not use a cache for tiled drawing at all, instead
172 // having a tiled drawing callback (hopefully non-virtual).
173 if (!m_frameCache) {
174 m_frameCache.set(ImageBuffer::create(size(), false).release());
175 if (!m_frameCache) // failed to allocate image
176 return 0;
177 renderSubtreeToImage(m_frameCache.get(), m_frame->contentRenderer());
179 #if PLATFORM(CG)
180 return m_frameCache->cgImage();
181 #elif PLATFORM(QT)
182 return m_frameCache->pixmap();
183 #elif PLATFORM(CAIRO)
184 return m_frameCache->surface();
185 #else
186 notImplemented();
187 return 0;
188 #endif
191 bool SVGImage::dataChanged(bool allDataReceived)
193 int length = m_data->size();
194 if (!length) // if this was an empty image
195 return true;
197 if (allDataReceived) {
198 static ChromeClient* dummyChromeClient = new SVGEmptyChromeClient;
199 static FrameLoaderClient* dummyFrameLoaderClient = new SVGEmptyFrameLoaderClient;
200 static EditorClient* dummyEditorClient = new SVGEmptyEditorClient;
201 static ContextMenuClient* dummyContextMenuClient = new SVGEmptyContextMenuClient;
202 static DragClient* dummyDragClient = new SVGEmptyDragClient;
203 static InspectorClient* dummyInspectorClient = new SVGEmptyInspectorClient;
205 // FIXME: If this SVG ends up loading itself, we'll leak this Frame (and associated DOM & render trees).
206 // The Cache code does not know about CachedImages holding Frames and won't know to break the cycle.
207 m_page.set(new Page(dummyChromeClient, dummyContextMenuClient, dummyEditorClient, dummyDragClient, dummyInspectorClient));
208 m_page->settings()->setJavaScriptEnabled(false);
210 m_frame = new Frame(m_page.get(), 0, dummyFrameLoaderClient);
211 m_frameView = new FrameView(m_frame.get());
212 m_frameView->deref(); // FIXME: FrameView starts with a refcount of 1
213 m_frame->setView(m_frameView.get());
214 m_frame->init();
215 ResourceRequest fakeRequest(KURL(""));
216 m_frame->loader()->load(fakeRequest); // Make sure the DocumentLoader is created
217 m_frame->loader()->cancelContentPolicyCheck(); // cancel any policy checks
218 m_frame->loader()->commitProvisionalLoad(0);
219 m_frame->loader()->setResponseMIMEType("image/svg+xml");
220 m_frame->loader()->begin(KURL()); // create the empty document
221 m_frame->loader()->write(m_data->data(), m_data->size());
222 m_frame->loader()->end();
223 m_frameView->setTransparent(true); // SVG Images are transparent.
225 return m_frameView;
230 #endif // ENABLE(SVG)