Reviewed by Geoff.
[WebKit-https.git] / WebCore / platform / graphics / svg / SVGImage.cpp
1 /*
2  * Copyright (C) 2006 Eric Seidel (eric@webkit.org)
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #if ENABLE(SVG)
28
29 #include "CachedPage.h"
30 #include "DocumentLoader.h"
31 #include "EditCommand.h"
32 #include "FloatRect.h"
33 #include "Frame.h"
34 #include "FrameLoader.h"
35 #include "FrameView.h"
36 #include "GraphicsContext.h"
37 #include "ImageObserver.h"
38 #include "NotImplemented.h"
39 #include "Page.h"
40 #include "ResourceError.h"
41 #include "SVGDocument.h"
42 #include "SVGImage.h"
43 #include "SVGLength.h"
44 #include "SVGRenderSupport.h"
45 #include "SVGSVGElement.h"
46 #include "Settings.h"
47
48 #include "SVGImageEmptyClients.h"
49
50 namespace WebCore {
51
52 SVGImage::SVGImage(ImageObserver* observer)
53     : Image(observer)
54     , m_document(0)
55     , m_page(0)
56     , m_frame(0)
57     , m_frameView(0)
58 {
59 }
60
61 SVGImage::~SVGImage()
62 {
63     if (m_frame)
64         m_frame->loader()->frameDetached(); // Break both the loader and view references to the frame
65 }
66
67 IntSize SVGImage::size() const
68 {
69     IntSize defaultSize(300, 150);
70     // FIXME: Eventually we'll be passed in the dest size and can scale against that
71     IntSize destSize = defaultSize;
72     
73     if (!m_frame || !m_frame->document())
74         return IntSize();
75     
76     SVGSVGElement* rootElement = static_cast<SVGDocument*>(m_frame->document())->rootElement();
77     if (!rootElement)
78         return defaultSize;
79     
80     SVGLength width = rootElement->width();
81     SVGLength height = rootElement->height();
82     
83     IntSize svgSize;
84     if (width.unitType() == LengthTypePercentage)
85         svgSize.setWidth(static_cast<int>(width.valueAsPercentage() * destSize.width()));
86     else
87         svgSize.setWidth(static_cast<int>(width.value()));
88     if (height.unitType() == LengthTypePercentage)
89         svgSize.setHeight(static_cast<int>(height.valueAsPercentage() * destSize.height()));
90     else
91         svgSize.setHeight(static_cast<int>(height.value()));
92     
93     return svgSize;
94 }
95
96 void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp)
97 {
98     if (!m_frame)
99         return;
100     
101     context->save();
102     context->clip(enclosingIntRect(dstRect));
103     context->translate(dstRect.location().x(), dstRect.location().y());
104     context->scale(FloatSize(dstRect.width()/srcRect.width(), dstRect.height()/srcRect.height()));
105     m_frame->paint(context, enclosingIntRect(srcRect));
106     context->restore();
107
108     if (imageObserver())
109         imageObserver()->didDraw(this);
110 }
111
112 NativeImagePtr SVGImage::nativeImageForCurrentFrame()
113 {
114     // FIXME: In order to support dynamic SVGs we need to have a way to invalidate this
115     // frame cache, or better yet, not use a cache for tiled drawing at all, instead
116     // having a tiled drawing callback (hopefully non-virtual).
117     if (!m_frameCache) {
118         m_frameCache.set(ImageBuffer::create(size(), false).release());
119         if (!m_frameCache) // failed to allocate image
120             return 0;
121         renderSubtreeToImage(m_frameCache.get(), m_frame->renderer());
122     }
123 #if PLATFORM(CG)
124     return m_frameCache->cgImage();
125 #elif PLATFORM(QT)
126     return m_frameCache->pixmap();
127 #elif PLATFORM(CAIRO)
128     return m_frameCache->surface();
129 #else
130     notImplemented();
131     return 0;
132 #endif
133 }
134
135 bool SVGImage::dataChanged(bool allDataReceived)
136 {
137     int length = m_data->size();
138     if (!length) // if this was an empty image
139         return true;
140     
141     if (allDataReceived) {
142         static ChromeClient* dummyChromeClient = new SVGEmptyChromeClient;
143         static FrameLoaderClient* dummyFrameLoaderClient =  new SVGEmptyFrameLoaderClient;
144         static EditorClient* dummyEditorClient = new SVGEmptyEditorClient;
145         static ContextMenuClient* dummyContextMenuClient = new SVGEmptyContextMenuClient;
146         static DragClient* dummyDragClient = new SVGEmptyDragClient;
147         static InspectorClient* dummyInspectorClient = new SVGEmptyInspectorClient;
148
149         // FIXME: If this SVG ends up loading itself, we'll leak this Frame (and associated DOM & render trees).
150         // The Cache code does not know about CachedImages holding Frames and won't know to break the cycle.
151         m_page.set(new Page(dummyChromeClient, dummyContextMenuClient, dummyEditorClient, dummyDragClient, dummyInspectorClient));
152         m_page->settings()->setJavaScriptEnabled(false);
153
154         m_frame = new Frame(m_page.get(), 0, dummyFrameLoaderClient);
155         m_frame->init();
156         m_frameView = new FrameView(m_frame.get());
157         m_frameView->deref(); // FIXME: FrameView starts with a refcount of 1
158         m_frame->setView(m_frameView.get());
159         ResourceRequest fakeRequest(KURL(""));
160         m_frame->loader()->load(fakeRequest); // Make sure the DocumentLoader is created
161         m_frame->loader()->cancelContentPolicyCheck(); // cancel any policy checks
162         m_frame->loader()->commitProvisionalLoad(0);
163         m_frame->loader()->setResponseMIMEType("image/svg+xml");
164         m_frame->loader()->begin("placeholder.svg"); // create the empty document
165         m_frame->loader()->write(m_data->data(), m_data->size());
166         m_frame->loader()->end();
167     }
168     return m_frameView;
169 }
170
171 }
172
173 #endif // ENABLE(SVG)