Reviewed by Darin.
[WebKit-https.git] / WebCore / ksvg2 / svg / SVGSVGElement.cpp
1 /*
2     Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
3                   2004, 2005, 2006 Rob Buis <buis@kde.org>
4
5     This file is part of the KDE project
6
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Library General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Library General Public License for more details.
16
17     You should have received a copy of the GNU Library General Public License
18     along with this library; see the file COPYING.LIB.  If not, write to
19     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20     Boston, MA 02111-1307, USA.
21 */
22
23 #include "config.h"
24 #ifdef SVG_SUPPORT
25 #include "SVGSVGElement.h"
26
27 #include "CSSPropertyNames.h"
28 #include "Document.h"
29 #include "EventListener.h"
30 #include "EventNames.h"
31 #include "HTMLNames.h"
32 #include "KSVGTimeScheduler.h"
33 #include "RenderSVGContainer.h"
34 #include "SVGAngle.h"
35 #include "SVGLength.h"
36 #include "SVGMatrix.h"
37 #include "SVGNames.h"
38 #include "SVGPreserveAspectRatio.h"
39 #include "SVGTransform.h"
40 #include "SVGZoomEvent.h"
41 #include "TextStream.h"
42
43 namespace WebCore {
44
45 using namespace HTMLNames;
46 using namespace EventNames;
47 using namespace SVGNames;
48
49 SVGSVGElement::SVGSVGElement(const QualifiedName& tagName, Document* doc)
50     : SVGStyledLocatableElement(tagName, doc)
51     , SVGTests()
52     , SVGLangSpace()
53     , SVGExternalResourcesRequired()
54     , SVGFitToViewBox()
55     , SVGZoomAndPan()
56     , m_useCurrentView(false)
57     , m_timeScheduler(new TimeScheduler(doc))
58 {
59     const SVGElement* viewport = ownerDocument()->documentElement() == this ? this : viewportElement();
60     const SVGStyledElement* context = ownerDocument()->documentElement() == this ? 0 : this;
61
62     m_x = new SVGLength(context, LM_WIDTH, viewport);
63     m_y = new SVGLength(context, LM_HEIGHT, viewport);
64     m_width = new SVGLength(context, LM_WIDTH, viewport);
65     m_height = new SVGLength(context, LM_HEIGHT, viewport);
66
67     m_width->setValueAsString("100%");
68     m_height->setValueAsString("100%");
69 }
70
71 SVGSVGElement::~SVGSVGElement()
72 {
73     delete m_timeScheduler;
74 }
75
76 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength*, Length, length, X, x, SVGNames::xAttr.localName(), m_x.get())
77 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength*, Length, length, Y, y, SVGNames::yAttr.localName(), m_y.get())
78 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength*, Length, length, Width, width, SVGNames::widthAttr.localName(), m_width.get())
79 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength*, Length, length, Height, height, SVGNames::heightAttr.localName(), m_height.get())
80
81 const AtomicString& SVGSVGElement::contentScriptType() const
82 {
83     static const AtomicString defaultValue("text/ecmascript");
84     const AtomicString& n = getAttribute(contentScriptTypeAttr);
85     return n.isNull() ? defaultValue : n;
86 }
87
88 void SVGSVGElement::setContentScriptType(const AtomicString& type)
89 {
90     setAttribute(SVGNames::contentScriptTypeAttr, type);
91 }
92
93 const AtomicString& SVGSVGElement::contentStyleType() const
94 {
95     static const AtomicString defaultValue("text/css");
96     const AtomicString& n = getAttribute(contentStyleTypeAttr);
97     return n.isNull() ? defaultValue : n;
98 }
99
100 void SVGSVGElement::setContentStyleType(const AtomicString& type)
101 {
102     setAttribute(SVGNames::contentStyleTypeAttr, type);
103 }
104
105 FloatRect SVGSVGElement::viewport() const
106 {
107     double _x = x()->value();
108     double _y = y()->value();
109     double w = width()->value();
110     double h = height()->value();
111     RefPtr<SVGMatrix> viewBox = viewBoxToViewTransform(w, h);
112     viewBox->matrix().map(_x, _y, &_x, &_y);
113     viewBox->matrix().map(w, h, &w, &h);
114     return FloatRect(_x, _y, w, h);
115 }
116
117 float SVGSVGElement::pixelUnitToMillimeterX() const
118 {
119     // FIXME: Implement me (see bug 11273)
120     return .28;
121 }
122
123 float SVGSVGElement::pixelUnitToMillimeterY() const
124 {
125     // FIXME: Implement me (see bug 11273)
126     return .28;
127 }
128
129 float SVGSVGElement::screenPixelToMillimeterX() const
130 {
131     return pixelUnitToMillimeterX();
132 }
133
134 float SVGSVGElement::screenPixelToMillimeterY() const
135 {
136     return pixelUnitToMillimeterY();
137 }
138
139 bool SVGSVGElement::useCurrentView() const
140 {
141     return m_useCurrentView;
142 }
143
144 void SVGSVGElement::setUseCurrentView(bool currentView)
145 {
146     m_useCurrentView = currentView;
147 }
148
149 float SVGSVGElement::currentScale() const
150 {
151     // FIXME: Return the current zoom/scale value (see bug 11272)
152     return 1.;
153 }
154
155 void SVGSVGElement::setCurrentScale(float scale)
156 {
157     // FIXME: Set the current zoom/scale value (see bug 11272)
158 }
159
160 FloatPoint SVGSVGElement::currentTranslate() const
161 {
162     // FIXME: Return the current pan/translate value (see bug 11272)
163     return FloatPoint();
164 }
165
166 void SVGSVGElement::addSVGWindowEventListner(const AtomicString& eventType, const Attribute* attr)
167 {
168     // FIXME: None of these should be window events long term.
169     // Once we propertly support SVGLoad, etc.
170     RefPtr<EventListener> listener = document()->accessSVGExtensions()->
171         createSVGEventListener(attr->localName().domString(), attr->value(), this);
172     document()->setHTMLWindowEventListener(eventType, listener.release());
173 }
174
175 void SVGSVGElement::parseMappedAttribute(MappedAttribute* attr)
176 {
177     const AtomicString& value = attr->value();
178     if (!nearestViewportElement()) {
179         // Only handle events if we're the outermost <svg> element
180         if (attr->name() == onunloadAttr)
181             addSVGWindowEventListner(unloadEvent, attr);
182         else if (attr->name() == onabortAttr)
183             addSVGWindowEventListner(abortEvent, attr);
184         else if (attr->name() == onerrorAttr)
185             addSVGWindowEventListner(errorEvent, attr);
186         else if (attr->name() == onresizeAttr)
187             addSVGWindowEventListner(resizeEvent, attr);
188         else if (attr->name() == onscrollAttr)
189             addSVGWindowEventListner(scrollEvent, attr);
190         else if (attr->name() == SVGNames::onzoomAttr)
191             addSVGWindowEventListner(zoomEvent, attr);
192     }
193     if (attr->name() == SVGNames::xAttr) {
194         xBaseValue()->setValueAsString(value);
195     } else if (attr->name() == SVGNames::yAttr) {
196         yBaseValue()->setValueAsString(value);
197     } else if (attr->name() == SVGNames::widthAttr) {
198         widthBaseValue()->setValueAsString(value);
199         addCSSProperty(attr, CSS_PROP_WIDTH, value);
200     } else if (attr->name() == SVGNames::heightAttr) {
201         heightBaseValue()->setValueAsString(value);
202         addCSSProperty(attr, CSS_PROP_HEIGHT, value);
203     } else {
204         if (SVGTests::parseMappedAttribute(attr))
205             return;
206         if (SVGLangSpace::parseMappedAttribute(attr))
207             return;
208         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
209             return;
210         if (SVGFitToViewBox::parseMappedAttribute(attr) && renderer())
211             static_cast<RenderSVGContainer*>(renderer())->setViewBox(viewBox());
212         if (SVGZoomAndPan::parseMappedAttribute(attr))
213             return;
214
215         SVGStyledLocatableElement::parseMappedAttribute(attr);
216     }
217 }
218
219 unsigned long SVGSVGElement::suspendRedraw(unsigned long /* max_wait_milliseconds */)
220 {
221     // FIXME: Implement me (see bug 11275)
222     return 0;
223 }
224
225 void SVGSVGElement::unsuspendRedraw(unsigned long /* suspend_handle_id */, ExceptionCode& ec)
226 {
227     // if suspend_handle_id is not found, throw exception
228     // FIXME: Implement me (see bug 11275)
229 }
230
231 void SVGSVGElement::unsuspendRedrawAll()
232 {
233     // FIXME: Implement me (see bug 11275)
234 }
235
236 void SVGSVGElement::forceRedraw()
237 {
238     // FIXME: Implement me (see bug 11275)
239 }
240
241 NodeList* SVGSVGElement::getIntersectionList(const FloatRect& rect, SVGElement*)
242 {
243     // FIXME: Implement me (see bug 11274)
244     return 0;
245 }
246
247 NodeList* SVGSVGElement::getEnclosureList(const FloatRect& rect, SVGElement*)
248 {
249     // FIXME: Implement me (see bug 11274)
250     return 0;
251 }
252
253 bool SVGSVGElement::checkIntersection(SVGElement* element, const FloatRect& rect)
254 {
255     // TODO : take into account pointer-events?
256     // FIXME: Why is element ignored??
257     // FIXME: Implement me (see bug 11274)
258     return rect.intersects(getBBox());
259 }
260
261 bool SVGSVGElement::checkEnclosure(SVGElement* element, const FloatRect& rect)
262 {
263     // TODO : take into account pointer-events?
264     // FIXME: Why is element ignored??
265     // FIXME: Implement me (see bug 11274)
266     return rect.contains(getBBox());
267 }
268
269 void SVGSVGElement::deselectAll()
270 {
271     // FIXME: Implement me (see bug 11275)
272 }
273
274 float SVGSVGElement::createSVGNumber()
275 {
276     return 0;
277 }
278
279 SVGLength* SVGSVGElement::createSVGLength()
280 {
281     return new SVGLength(0);
282 }
283
284 SVGAngle* SVGSVGElement::createSVGAngle()
285 {
286     return new SVGAngle(0);
287 }
288
289 FloatPoint SVGSVGElement::createSVGPoint()
290 {
291     return FloatPoint();
292 }
293
294 SVGMatrix* SVGSVGElement::createSVGMatrix()
295 {
296     return new SVGMatrix();
297 }
298
299 FloatRect SVGSVGElement::createSVGRect()
300 {
301     return FloatRect();
302 }
303
304 SVGTransform* SVGSVGElement::createSVGTransform()
305 {
306     return new SVGTransform();
307 }
308
309 SVGTransform* SVGSVGElement::createSVGTransformFromMatrix(SVGMatrix* matrix)
310 {    
311     SVGTransform* obj = SVGSVGElement::createSVGTransform();
312     obj->setMatrix(matrix);
313     return obj;
314 }
315
316 SVGMatrix* SVGSVGElement::getCTM() const
317 {
318     SVGMatrix* mat = createSVGMatrix();
319     if (mat) {
320         mat->translate(x()->value(), y()->value());
321
322         if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) {
323             RefPtr<SVGMatrix> viewBox = viewBoxToViewTransform(width()->value(), height()->value());
324             mat->multiply(viewBox.get());
325         }
326     }
327
328     return mat;
329 }
330
331 SVGMatrix* SVGSVGElement::getScreenCTM() const
332 {
333     SVGMatrix* mat = SVGStyledLocatableElement::getScreenCTM();
334     if (mat) {
335         mat->translate(x()->value(), y()->value());
336
337         if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) {
338             RefPtr<SVGMatrix> viewBox = viewBoxToViewTransform(width()->value(), height()->value());
339             mat->multiply(viewBox.get());
340         }
341     }
342
343     return mat;
344 }
345
346 RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*)
347 {
348     RenderSVGContainer* rootContainer = new (arena) RenderSVGContainer(this);
349
350     // FIXME: All this setup should be done after attributesChanged, not here.
351     rootContainer->setViewBox(viewBox());
352     rootContainer->setAlign(KCAlign(preserveAspectRatio()->align() - 1));
353     rootContainer->setSlice(preserveAspectRatio()->meetOrSlice() == SVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE);
354     
355     return rootContainer;
356 }
357
358 void SVGSVGElement::insertedIntoDocument()
359 {
360     document()->accessSVGExtensions()->addTimeContainer(this);
361     SVGStyledLocatableElement::insertedIntoDocument();
362 }
363
364 void SVGSVGElement::removedFromDocument()
365 {
366     document()->accessSVGExtensions()->removeTimeContainer(this);
367     SVGStyledLocatableElement::removedFromDocument();
368 }
369
370 void SVGSVGElement::setZoomAndPan(unsigned short zoomAndPan)
371 {
372     SVGZoomAndPan::setZoomAndPan(zoomAndPan);
373     //canvasView()->enableZoomAndPan(zoomAndPan == SVG_ZOOMANDPAN_MAGNIFY);
374 }
375
376 void SVGSVGElement::pauseAnimations()
377 {
378     if (!m_timeScheduler->animationsPaused())
379         m_timeScheduler->toggleAnimations();
380 }
381
382 void SVGSVGElement::unpauseAnimations()
383 {
384     if (m_timeScheduler->animationsPaused())
385         m_timeScheduler->toggleAnimations();
386 }
387
388 bool SVGSVGElement::animationsPaused() const
389 {
390     return m_timeScheduler->animationsPaused();
391 }
392
393 float SVGSVGElement::getCurrentTime() const
394 {
395     return m_timeScheduler->elapsed();
396 }
397
398 void SVGSVGElement::setCurrentTime(float /* seconds */)
399 {
400     // FIXME: Implement me
401 }
402
403 void SVGSVGElement::attributeChanged(Attribute* attr, bool preserveDecls)
404 {
405     if (attr->name() == SVGNames::xAttr ||
406         attr->name() == SVGNames::yAttr ||
407         attr->name() == SVGNames::widthAttr ||
408         attr->name() == SVGNames::heightAttr)
409         if (renderer())
410             renderer()->setNeedsLayout(true);
411
412     SVGStyledElement::attributeChanged(attr, preserveDecls);
413 }
414
415 }
416
417 // vim:ts=4:noet
418 #endif // SVG_SUPPORT
419