39425fc60909e53c74001474ad8ca977437d5801
[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
47 #include "SVGImageEmptyClients.h"
48
49 namespace WebCore {
50
51 SVGImage::SVGImage(ImageObserver* observer)
52     : Image(observer)
53     , m_document(0)
54     , m_page(0)
55     , m_frame(0)
56     , m_frameView(0)
57 {
58 }
59
60 SVGImage::~SVGImage()
61 {
62     if (m_frame)
63         m_frame->loader()->frameDetached(); // Break both the loader and view references to the frame
64 }
65
66 IntSize SVGImage::size() const
67 {
68     IntSize defaultSize(300, 150);
69     // FIXME: Eventually we'll be passed in the dest size and can scale against that
70     IntSize destSize = defaultSize;
71     
72     if (!m_frame || !m_frame->document())
73         return IntSize();
74     
75     SVGSVGElement* rootElement = static_cast<SVGDocument*>(m_frame->document())->rootElement();
76     if (!rootElement)
77         return defaultSize;
78     
79     SVGLength width = rootElement->width();
80     SVGLength height = rootElement->height();
81     
82     IntSize svgSize;
83     if (width.unitType() == LengthTypePercentage)
84         svgSize.setWidth(static_cast<int>(width.valueAsPercentage() * destSize.width()));
85     else
86         svgSize.setWidth(static_cast<int>(width.value()));
87     if (height.unitType() == LengthTypePercentage)
88         svgSize.setHeight(static_cast<int>(height.valueAsPercentage() * destSize.height()));
89     else
90         svgSize.setHeight(static_cast<int>(height.value()));
91     
92     return svgSize;
93 }
94
95 void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp)
96 {
97     if (!m_frame)
98         return;
99     
100     context->save();
101     context->clip(enclosingIntRect(dstRect));
102     context->translate(dstRect.location().x(), dstRect.location().y());
103     context->scale(FloatSize(dstRect.width()/srcRect.width(), dstRect.height()/srcRect.height()));
104     m_frame->paint(context, enclosingIntRect(srcRect));
105     context->restore();
106
107     if (imageObserver())
108         imageObserver()->didDraw(this);
109 }
110
111 NativeImagePtr SVGImage::nativeImageForCurrentFrame()
112 {
113     // FIXME: In order to support dynamic SVGs we need to have a way to invalidate this
114     // frame cache, or better yet, not use a cache for tiled drawing at all, instead
115     // having a tiled drawing callback (hopefully non-virtual).
116     if (!m_frameCache) {
117         m_frameCache.set(ImageBuffer::create(size(), false).release());
118         if (!m_frameCache) // failed to allocate image
119             return 0;
120         renderSubtreeToImage(m_frameCache.get(), m_frame->renderer());
121     }
122 #if PLATFORM(CG)
123     return m_frameCache->cgImage();
124 #elif PLATFORM(QT)
125     return m_frameCache->pixmap();
126 #elif PLATFORM(CAIRO)
127     return m_frameCache->surface();
128 #else
129     notImplemented();
130     return 0;
131 #endif
132 }
133
134 bool SVGImage::dataChanged(bool allDataReceived)
135 {
136     int length = m_data->size();
137     if (!length) // if this was an empty image
138         return true;
139     
140     if (allDataReceived) {
141         static ChromeClient* dummyChromeClient = new SVGEmptyChromeClient;
142         static FrameLoaderClient* dummyFrameLoaderClient =  new SVGEmptyFrameLoaderClient;
143         static EditorClient* dummyEditorClient = new SVGEmptyEditorClient;
144         static ContextMenuClient* dummyContextMenuClient = new SVGEmptyContextMenuClient;
145         static DragClient* dummyDragClient = new SVGEmptyDragClient;
146         static InspectorClient* dummyInspectorClient = new SVGEmptyInspectorClient;
147
148         // FIXME: If this SVG ends up loading itself, we'll leak this Frame (and associated DOM & render trees).
149         // The Cache code does not know about CachedImages holding Frames and won't know to break the cycle.
150         m_page.set(new Page(dummyChromeClient, dummyContextMenuClient, dummyEditorClient, dummyDragClient, dummyInspectorClient));
151         m_frame = new Frame(m_page.get(), 0, dummyFrameLoaderClient);
152         m_frame->init();
153         m_frameView = new FrameView(m_frame.get());
154         m_frameView->deref(); // FIXME: FrameView starts with a refcount of 1
155         m_frame->setView(m_frameView.get());
156         ResourceRequest fakeRequest(KURL(""));
157         m_frame->loader()->load(fakeRequest); // Make sure the DocumentLoader is created
158         m_frame->loader()->cancelContentPolicyCheck(); // cancel any policy checks
159         m_frame->loader()->commitProvisionalLoad(0);
160         m_frame->loader()->setResponseMIMEType("image/svg+xml");
161         m_frame->loader()->begin("placeholder.svg"); // create the empty document
162         m_frame->loader()->write(m_data->data(), m_data->size());
163         m_frame->loader()->end();
164     }
165     return m_frameView;
166 }
167
168 }
169
170 #endif // ENABLE(SVG)