2 Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 2007 Apple Inc. All rights reserved.
6 This file is part of the KDE project
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
25 #include <wtf/Platform.h>
28 #include "SVGSVGElement.h"
30 #include "AffineTransform.h"
31 /*#include "CSSHelper.h"*/
32 #include "css/csshelper.h"
33 /*#include "CSSPropertyNames.h"*/
35 //#include "EventListener.h"
36 #include "dom/dom2_events.h"
37 /*#include "EventNames.h"*/
38 #include "FloatConversion.h"
39 #include "FloatRect.h"
41 #include "HTMLNames.h"
42 #include "RenderSVGViewportContainer.h"*/
43 #include "RenderSVGRoot.h"
45 #include "SVGLength.h"
47 #include "SVGPreserveAspectRatio.h"
48 #include "SVGTransform.h"
49 #include "SVGTransformList.h"
50 /*#include "SVGViewElement.h"*/
51 #include "SVGViewSpec.h"
52 /*#include "SVGZoomEvent.h"
53 #include "SelectionController.h"
54 #include "SMILTimeContainer.h"*/
58 /*using namespace HTMLNames;
59 using namespace EventNames;*/
60 using namespace SVGNames
;
62 SVGSVGElement::SVGSVGElement(const QualifiedName
& tagName
, Document
* doc
)
63 : SVGStyledLocatableElement(tagName
, doc
)
66 , SVGExternalResourcesRequired()
69 , m_x(this, LengthModeWidth
)
70 , m_y(this, LengthModeHeight
)
71 , m_width(this, LengthModeWidth
)
72 , m_height(this, LengthModeHeight
)
73 , m_useCurrentView(false)
74 /*, m_timeContainer(SMILTimeContainer::create(this))
76 , m_containerSize(300, 150)
77 /*, m_hasSetContainerSize(false)*/
79 setWidthBaseValue(SVGLength(this, LengthModeWidth
, "100%"));
80 setHeightBaseValue(SVGLength(this, LengthModeHeight
, "100%"));
81 //doc->registerForCacheCallbacks(this);
84 SVGSVGElement::~SVGSVGElement()
86 /*document()->unregisterForCacheCallbacks(this);
87 // There are cases where removedFromDocument() is not called.
88 // see ContainerNode::removeAllChildren, called by it's destructor.
89 document()->accessSVGExtensions()->removeTimeContainer(this);*/
92 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement
, SVGLength
, Length
, length
, X
, x
, SVGNames::xAttr
, m_x
)
93 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement
, SVGLength
, Length
, length
, Y
, y
, SVGNames::yAttr
, m_y
)
94 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement
, SVGLength
, Length
, length
, Width
, width
, SVGNames::widthAttr
, m_width
)
95 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement
, SVGLength
, Length
, length
, Height
, height
, SVGNames::heightAttr
, m_height
)
97 const AtomicString
& SVGSVGElement::contentScriptType() const
99 /*static const AtomicString defaultValue("text/ecmascript");
100 const AtomicString& n = getAttribute(contentScriptTypeAttr);
101 return n.isNull() ? defaultValue : n;*/
106 void SVGSVGElement::setContentScriptType(const AtomicString
& type
)
108 setAttribute(SVGNames::contentScriptTypeAttr
, type
);
111 const AtomicString
& SVGSVGElement::contentStyleType() const
113 /*static const AtomicString defaultValue("text/css");
114 const AtomicString& n = getAttribute(contentStyleTypeAttr);
115 return n.isNull() ? defaultValue : n;*/
120 void SVGSVGElement::setContentStyleType(const AtomicString
& type
)
122 setAttribute(SVGNames::contentStyleTypeAttr
, type
);
125 FloatRect
SVGSVGElement::viewport() const
129 if (!isOutermostSVG()) {
133 float w
= width().value();
134 float h
= height().value();
135 AffineTransform viewBox
= viewBoxToViewTransform(w
, h
);
138 viewBox
.map(_x
, _y
, &_x
, &_y
);
139 viewBox
.map(w
, h
, &wDouble
, &hDouble
);
140 return FloatRect::narrowPrecision(_x
, _y
, wDouble
, hDouble
);
143 int SVGSVGElement::relativeWidthValue() const
145 SVGLength w
= width();
146 if (w
.unitType() != LengthTypePercentage
)
149 return static_cast<int>(w
.valueAsPercentage() * m_containerSize
.width());
152 int SVGSVGElement::relativeHeightValue() const
154 SVGLength h
= height();
155 if (h
.unitType() != LengthTypePercentage
)
158 return static_cast<int>(h
.valueAsPercentage() * m_containerSize
.height());
161 float SVGSVGElement::pixelUnitToMillimeterX() const
163 // 2.54 / cssPixelsPerInch gives CM.
164 return (2.54f
/ cssPixelsPerInch
) * 10.0f
;
167 float SVGSVGElement::pixelUnitToMillimeterY() const
169 // 2.54 / cssPixelsPerInch gives CM.
170 return (2.54f
/ cssPixelsPerInch
) * 10.0f
;
173 float SVGSVGElement::screenPixelToMillimeterX() const
175 return pixelUnitToMillimeterX();
178 float SVGSVGElement::screenPixelToMillimeterY() const
180 return pixelUnitToMillimeterY();
183 bool SVGSVGElement::useCurrentView() const
185 return m_useCurrentView
;
188 void SVGSVGElement::setUseCurrentView(bool currentView
)
190 m_useCurrentView
= currentView
;
193 SVGViewSpec
* SVGSVGElement::currentView() const
196 m_viewSpec
.set(new SVGViewSpec(this));
198 return m_viewSpec
.get();
201 float SVGSVGElement::currentScale() const
203 /*if (document() && document()->frame())
204 return document()->frame()->zoomFactor();*/
208 void SVGSVGElement::setCurrentScale(float scale
)
210 /*if (document() && document()->frame())
211 document()->frame()->setZoomFactor(scale, true);*/
214 FloatPoint
SVGSVGElement::currentTranslate() const
216 return m_translation
;
219 void SVGSVGElement::setCurrentTranslate(const FloatPoint
&translation
)
221 m_translation
= translation
;
222 if (parentNode() == document() && document()->renderer())
223 document()->renderer()->repaint();
226 void SVGSVGElement::addSVGWindowEventListener(const AtomicString
& eventType
, const Attribute
* attr
)
228 // FIXME: None of these should be window events long term.
229 // Once we propertly support SVGLoad, etc.
230 RefPtr
<EventListener
> listener
= document()->accessSVGExtensions()->
231 createSVGEventListener(attr
->localName().string(), attr
->value(), this);
232 //document()->setHTMLWindowEventListener(eventType, listener.release());
235 void SVGSVGElement::parseMappedAttribute(MappedAttribute
* attr
)
237 kDebug() << "parse attribute: " << attr
->localName() << attr
->value() << endl
;
238 if (!nearestViewportElement()) {
239 // Only handle events if we're the outermost <svg> element
240 /*if (attr->name() == onunloadAttr)
241 addSVGWindowEventListener(unloadEvent, attr);
242 else if (attr->name() == onabortAttr)
243 addSVGWindowEventListener(abortEvent, attr);
244 else if (attr->name() == onerrorAttr)
245 addSVGWindowEventListener(errorEvent, attr);
246 else if (attr->name() == onresizeAttr)
247 addSVGWindowEventListener(resizeEvent, attr);
248 else if (attr->name() == onscrollAttr)
249 addSVGWindowEventListener(scrollEvent, attr);
250 else if (attr->name() == SVGNames::onzoomAttr)
251 addSVGWindowEventListener(zoomEvent, attr);*/
253 if (attr
->name() == SVGNames::xAttr
)
254 setXBaseValue(SVGLength(this, LengthModeWidth
, attr
->value()));
255 else if (attr
->name() == SVGNames::yAttr
)
256 setYBaseValue(SVGLength(this, LengthModeHeight
, attr
->value()));
257 else if (attr
->name() == SVGNames::widthAttr
) {
258 kDebug() << "set width" << attr
->value() << endl
;
259 setWidthBaseValue(SVGLength(this, LengthModeWidth
, attr
->value()));
260 addCSSProperty(attr
, CSSPropertyWidth
, attr
->value());
261 /*if (width().value() < 0.0)
262 document()->accessSVGExtensions()->reportError("A negative value for svg attribute <width> is not allowed");*/
263 } else if (attr
->name() == SVGNames::heightAttr
) {
264 kDebug() << "set height" << attr
->value() << endl
;
265 setHeightBaseValue(SVGLength(this, LengthModeHeight
, attr
->value()));
266 addCSSProperty(attr
, CSSPropertyHeight
, attr
->value());
267 /*if (height().value() < 0.0)
268 document()->accessSVGExtensions()->reportError("A negative value for svg attribute <height> is not allowed");*/
270 /*if (SVGTests::parseMappedAttribute(attr))
272 if (SVGLangSpace::parseMappedAttribute(attr))
274 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
276 if (SVGFitToViewBox::parseMappedAttribute(attr))
278 if (SVGZoomAndPan::parseMappedAttribute(attr))
281 SVGStyledLocatableElement::parseMappedAttribute(attr
);
285 void SVGSVGElement::svgAttributeChanged(const QualifiedName
& attrName
)
287 SVGStyledElement::svgAttributeChanged(attrName
);
292 /*if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
293 attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
294 SVGTests::isKnownAttribute(attrName) ||
295 SVGLangSpace::isKnownAttribute(attrName) ||
296 SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
297 SVGFitToViewBox::isKnownAttribute(attrName) ||
298 SVGZoomAndPan::isKnownAttribute(attrName) ||
299 SVGStyledLocatableElement::isKnownAttribute(attrName))
300 renderer()->setNeedsLayout(true);*/
303 unsigned long SVGSVGElement::suspendRedraw(unsigned long /* max_wait_milliseconds */)
305 // FIXME: Implement me (see bug 11275)
309 void SVGSVGElement::unsuspendRedraw(unsigned long /* suspend_handle_id */, ExceptionCode
& ec
)
311 // if suspend_handle_id is not found, throw exception
312 // FIXME: Implement me (see bug 11275)
315 void SVGSVGElement::unsuspendRedrawAll()
317 // FIXME: Implement me (see bug 11275)
320 void SVGSVGElement::forceRedraw()
322 // FIXME: Implement me (see bug 11275)
325 NodeList
* SVGSVGElement::getIntersectionList(const FloatRect
& rect
, SVGElement
*)
327 // FIXME: Implement me (see bug 11274)
331 NodeList
* SVGSVGElement::getEnclosureList(const FloatRect
& rect
, SVGElement
*)
333 // FIXME: Implement me (see bug 11274)
337 bool SVGSVGElement::checkIntersection(SVGElement
* element
, const FloatRect
& rect
)
339 // TODO : take into account pointer-events?
340 // FIXME: Why is element ignored??
341 // FIXME: Implement me (see bug 11274)
342 return rect
.intersects(getBBox());
345 bool SVGSVGElement::checkEnclosure(SVGElement
* element
, const FloatRect
& rect
)
347 // TODO : take into account pointer-events?
348 // FIXME: Why is element ignored??
349 // FIXME: Implement me (see bug 11274)
350 return rect
.contains(getBBox());
353 void SVGSVGElement::deselectAll()
355 //document()->frame()->selectionController()->clear();
358 float SVGSVGElement::createSVGNumber()
363 SVGLength
SVGSVGElement::createSVGLength()
368 SVGAngle
* SVGSVGElement::createSVGAngle()
370 return new SVGAngle();
373 FloatPoint
SVGSVGElement::createSVGPoint()
378 AffineTransform
SVGSVGElement::createSVGMatrix()
380 return AffineTransform();
383 FloatRect
SVGSVGElement::createSVGRect()
388 SVGTransform
SVGSVGElement::createSVGTransform()
390 return SVGTransform();
393 SVGTransform
SVGSVGElement::createSVGTransformFromMatrix(const AffineTransform
& matrix
)
395 return SVGTransform(matrix
);
398 AffineTransform
SVGSVGElement::getCTM() const
401 if (!isOutermostSVG())
402 mat
.translate(x().value(), y().value());
404 if (attributes()->getNamedItem(SVGNames::viewBoxAttr
)) {
405 AffineTransform viewBox
= viewBoxToViewTransform(width().value(), height().value());
412 AffineTransform
SVGSVGElement::getScreenCTM() const
414 /*document()->updateLayoutIgnorePendingStylesheets();
418 if (RenderObject* renderer = this->renderer()) {
419 renderer = renderer->parent();
420 if (isOutermostSVG()) {
424 renderer->absolutePosition(tx, ty, true);
428 rootX += x().value();
429 rootY += y().value();
433 AffineTransform mat = SVGStyledLocatableElement::getScreenCTM();
434 mat.translate(rootX, rootY);
436 if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) {
437 AffineTransform viewBox = viewBoxToViewTransform(width().value(), height().value());
443 return AffineTransform();
446 RenderObject
* SVGSVGElement::createRenderer(RenderArena
* arena
, RenderStyle
*)
448 kDebug() << "create RenderSVGRoot from <svg> element" << endl
;
449 return new (arena
) RenderSVGRoot(this);
450 /*if (isOutermostSVG())
451 return new (arena) RenderSVGRoot(this);
453 return new (arena) RenderSVGViewportContainer(this);*/
456 void SVGSVGElement::insertedIntoDocument()
458 document()->accessSVGExtensions()->addTimeContainer(this);
459 SVGStyledLocatableElement::insertedIntoDocument();
462 void SVGSVGElement::removedFromDocument()
464 document()->accessSVGExtensions()->removeTimeContainer(this);
465 SVGStyledLocatableElement::removedFromDocument();
468 void SVGSVGElement::pauseAnimations()
470 /*if (!m_timeContainer->isPaused())
471 m_timeContainer->pause();*/
474 void SVGSVGElement::unpauseAnimations()
476 /*if (m_timeContainer->isPaused())
477 m_timeContainer->resume();*/
480 bool SVGSVGElement::animationsPaused() const
482 //return m_timeContainer->isPaused();
487 float SVGSVGElement::getCurrentTime() const
489 //return narrowPrecisionToFloat(m_timeContainer->elapsed().value());
494 void SVGSVGElement::setCurrentTime(float /* seconds */)
496 // FIXME: Implement me, bug 12073
499 bool SVGSVGElement::hasRelativeValues() const
501 return (x().isRelative() || width().isRelative() ||
502 y().isRelative() || height().isRelative());
505 bool SVGSVGElement::isOutermostSVG() const
507 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
508 return !parentNode()->isSVGElement();
511 AffineTransform
SVGSVGElement::viewBoxToViewTransform(float viewWidth
, float viewHeight
) const
513 FloatRect viewBoxRect
;
514 if (useCurrentView()) {
515 if (currentView()) // what if we should use it but it is not set?
516 viewBoxRect
= currentView()->viewBox();
518 viewBoxRect
= viewBox();
519 if (!viewBoxRect
.width() || !viewBoxRect
.height())
520 return AffineTransform();
522 AffineTransform ctm
= preserveAspectRatio()->getCTM(viewBoxRect
.x(),
523 viewBoxRect
.y(), viewBoxRect
.width(), viewBoxRect
.height(),
524 0, 0, viewWidth
, viewHeight
);
526 if (useCurrentView() && currentView())
527 return currentView()->transform()->concatenate().matrix() * ctm
;
532 /*void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement)
534 setUseCurrentView(true);
535 if (viewElement->hasAttribute(SVGNames::viewBoxAttr))
536 currentView()->setViewBox(viewElement->viewBox());
538 currentView()->setViewBox(viewBox());
539 if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr)) {
540 currentView()->preserveAspectRatio()->setAlign(viewElement->preserveAspectRatio()->align());
541 currentView()->preserveAspectRatio()->setMeetOrSlice(viewElement->preserveAspectRatio()->meetOrSlice());
543 currentView()->preserveAspectRatio()->setAlign(preserveAspectRatio()->align());
544 currentView()->preserveAspectRatio()->setMeetOrSlice(preserveAspectRatio()->meetOrSlice());
546 if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr))
547 currentView()->setZoomAndPan(viewElement->zoomAndPan());
548 renderer()->setNeedsLayout(true);
551 void SVGSVGElement::willSaveToCache()
556 void SVGSVGElement::willRestoreFromCache()
558 //unpauseAnimations();
562 quint32
SVGSVGElement::id() const { return SVGNames::svgTag
.id(); }
566 #endif // ENABLE(SVG)