File indexing completed on 2024-04-28 15:24:41

0001 /*
0002     Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
0003                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
0004                   2007 Apple Inc.  All rights reserved.
0005 
0006     This file is part of the KDE project
0007 
0008     This library is free software; you can redistribute it and/or
0009     modify it under the terms of the GNU Library General Public
0010     License as published by the Free Software Foundation; either
0011     version 2 of the License, or (at your option) any later version.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Library General Public License for more details.
0017 
0018     You should have received a copy of the GNU Library General Public License
0019     along with this library; see the file COPYING.LIB.  If not, write to
0020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0021     Boston, MA 02110-1301, USA.
0022 */
0023 
0024 #include <wtf/Platform.h>
0025 
0026 #if ENABLE(SVG)
0027 #include "SVGSVGElement.h"
0028 
0029 #include "AffineTransform.h"
0030 /*#include "CSSHelper.h"*/
0031 #include "css/csshelper.h"
0032 /*#include "CSSPropertyNames.h"*/
0033 #include "Document.h"
0034 //#include "EventListener.h"
0035 #include "dom/dom2_events.h"
0036 /*#include "EventNames.h"*/
0037 #include "FloatConversion.h"
0038 /*#include "Frame.h"
0039 #include "HTMLNames.h"
0040 #include "RenderSVGViewportContainer.h"*/
0041 #include "RenderSVGRoot.h"
0042 #include "SVGAngle.h"
0043 #include "SVGLength.h"
0044 #include "SVGNames.h"
0045 #include "SVGPreserveAspectRatio.h"
0046 #include "SVGTransform.h"
0047 #include "SVGTransformList.h"
0048 /*#include "SVGViewElement.h"*/
0049 #include "SVGViewSpec.h"
0050 /*#include "SVGZoomEvent.h"
0051 #include "SelectionController.h"
0052 #include "SMILTimeContainer.h"*/
0053 #include "khtml_part.h"
0054 
0055 namespace WebCore
0056 {
0057 
0058 /*using namespace HTMLNames;
0059 using namespace EventNames;*/
0060 using namespace SVGNames;
0061 
0062 SVGSVGElement::SVGSVGElement(const QualifiedName &tagName, Document *doc)
0063     : SVGStyledLocatableElement(tagName, doc)
0064     , SVGTests()
0065     , SVGLangSpace()
0066     , SVGExternalResourcesRequired()
0067     , SVGFitToViewBox()
0068     , SVGZoomAndPan()
0069     , m_x(this, LengthModeWidth)
0070     , m_y(this, LengthModeHeight)
0071     , m_width(this, LengthModeWidth)
0072     , m_height(this, LengthModeHeight)
0073     , m_useCurrentView(false)
0074 /*, m_timeContainer(SMILTimeContainer::create(this))
0075 , m_viewSpec(0)*/
0076 {
0077     setWidthBaseValue(SVGLength(this, LengthModeWidth, "100%"));
0078     setHeightBaseValue(SVGLength(this, LengthModeHeight, "100%"));
0079     //doc->registerForCacheCallbacks(this);
0080 }
0081 
0082 SVGSVGElement::~SVGSVGElement()
0083 {
0084     /*document()->unregisterForCacheCallbacks(this);
0085     // There are cases where removedFromDocument() is not called.
0086     // see ContainerNode::removeAllChildren, called by it's destructor.
0087     document()->accessSVGExtensions()->removeTimeContainer(this);*/
0088 }
0089 
0090 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, X, x, SVGNames::xAttr, m_x)
0091 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y)
0092 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width)
0093 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height)
0094 
0095 DOMString SVGSVGElement::contentScriptType() const
0096 {
0097     static const DOMString defaultValue("text/ecmascript");
0098     DOMString n = getAttribute(contentScriptTypeAttr);
0099     return n.isNull() ? defaultValue : n;
0100 }
0101 
0102 void SVGSVGElement::setContentScriptType(const DOMString &type)
0103 {
0104     setAttribute(SVGNames::contentScriptTypeAttr, type);
0105 }
0106 
0107 DOMString SVGSVGElement::contentStyleType() const
0108 {
0109     static const DOMString defaultValue("text/css");
0110     const DOMString n = getAttribute(contentStyleTypeAttr);
0111     return n.isNull() ? defaultValue : n;
0112 }
0113 
0114 void SVGSVGElement::setContentStyleType(const DOMString &type)
0115 {
0116     setAttribute(SVGNames::contentStyleTypeAttr, type);
0117 }
0118 
0119 bool SVGSVGElement::hasSetContainerSize() const
0120 {
0121     // For now, we interpret % dimensions only if we're a top-level SVG element nested inside
0122     // an another part. ### might even want to check if we're the documentElement; this
0123     // will also need changes with <img> handling
0124     return isOutermostSVG() && document()->part()->parentPart();
0125 }
0126 
0127 IntSize SVGSVGElement::containerSize() const
0128 {
0129     if (KHTMLView *v = document()->view()) {
0130         return IntSize(v->visibleWidth(), v->visibleHeight());
0131     } else {
0132         return IntSize(300, 150);
0133     }
0134 }
0135 
0136 FloatRect SVGSVGElement::viewport() const
0137 {
0138     double _x = 0.0;
0139     double _y = 0.0;
0140     if (!isOutermostSVG()) {
0141         _x = x().value();
0142         _y = y().value();
0143     }
0144     float w = width().value();
0145     float h = height().value();
0146     AffineTransform viewBox = viewBoxToViewTransform(w, h);
0147     double wDouble = w;
0148     double hDouble = h;
0149     viewBox.map(_x, _y, &_x, &_y);
0150     viewBox.map(w, h, &wDouble, &hDouble);
0151     return FloatRect::narrowPrecision(_x, _y, wDouble, hDouble);
0152 }
0153 
0154 int SVGSVGElement::relativeWidthValue() const
0155 {
0156     SVGLength w = width();
0157     if (w.unitType() != LengthTypePercentage) {
0158         return 0;
0159     }
0160 
0161     return static_cast<int>(w.valueAsPercentage() * containerSize().width());
0162 }
0163 
0164 int SVGSVGElement::relativeHeightValue() const
0165 {
0166     SVGLength h = height();
0167     if (h.unitType() != LengthTypePercentage) {
0168         return 0;
0169     }
0170 
0171     return static_cast<int>(h.valueAsPercentage() * containerSize().height());
0172 }
0173 
0174 float SVGSVGElement::pixelUnitToMillimeterX() const
0175 {
0176     // 2.54 / cssPixelsPerInch gives CM.
0177     return (2.54f / cssPixelsPerInch) * 10.0f;
0178 }
0179 
0180 float SVGSVGElement::pixelUnitToMillimeterY() const
0181 {
0182     // 2.54 / cssPixelsPerInch gives CM.
0183     return (2.54f / cssPixelsPerInch) * 10.0f;
0184 }
0185 
0186 float SVGSVGElement::screenPixelToMillimeterX() const
0187 {
0188     return pixelUnitToMillimeterX();
0189 }
0190 
0191 float SVGSVGElement::screenPixelToMillimeterY() const
0192 {
0193     return pixelUnitToMillimeterY();
0194 }
0195 
0196 bool SVGSVGElement::useCurrentView() const
0197 {
0198     return m_useCurrentView;
0199 }
0200 
0201 void SVGSVGElement::setUseCurrentView(bool currentView)
0202 {
0203     m_useCurrentView = currentView;
0204 }
0205 
0206 SVGViewSpec *SVGSVGElement::currentView() const
0207 {
0208     if (!m_viewSpec) {
0209         m_viewSpec.set(new SVGViewSpec(this));
0210     }
0211 
0212     return m_viewSpec.get();
0213 }
0214 
0215 float SVGSVGElement::currentScale() const
0216 {
0217     /*if (document() && document()->frame())
0218         return document()->frame()->zoomFactor();*/
0219     return 1.0f;
0220 }
0221 
0222 void SVGSVGElement::setCurrentScale(float scale)
0223 {
0224     Q_UNUSED(scale);
0225     /*if (document() && document()->frame())
0226         document()->frame()->setZoomFactor(scale, true);*/
0227 }
0228 
0229 FloatPoint SVGSVGElement::currentTranslate() const
0230 {
0231     return m_translation;
0232 }
0233 
0234 void SVGSVGElement::setCurrentTranslate(const FloatPoint &translation)
0235 {
0236     m_translation = translation;
0237     if (parentNode() == document() && document()->renderer()) {
0238         document()->renderer()->repaint();
0239     }
0240 }
0241 
0242 void SVGSVGElement::addSVGWindowEventListener(const AtomicString &eventType, const Attribute *attr)
0243 {
0244     Q_UNUSED(eventType);
0245     // FIXME: None of these should be window events long term.
0246     // Once we propertly support SVGLoad, etc.
0247     RefPtr<EventListener> listener = document()->accessSVGExtensions()->
0248                                      createSVGEventListener(attr->localName().string(), attr->value(), this);
0249     //document()->setHTMLWindowEventListener(eventType, listener.release());
0250 }
0251 
0252 void SVGSVGElement::parseMappedAttribute(MappedAttribute *attr)
0253 {
0254     // qCDebug(KHTML_LOG) << "parse attribute: " << attr->localName() << attr->value();
0255     if (!nearestViewportElement()) {
0256         // Only handle events if we're the outermost <svg> element
0257         /*if (attr->name() == onunloadAttr)
0258             addSVGWindowEventListener(unloadEvent, attr);
0259         else if (attr->name() == onabortAttr)
0260             addSVGWindowEventListener(abortEvent, attr);
0261         else if (attr->name() == onerrorAttr)
0262             addSVGWindowEventListener(errorEvent, attr);
0263         else if (attr->name() == onresizeAttr)
0264             addSVGWindowEventListener(resizeEvent, attr);
0265         else if (attr->name() == onscrollAttr)
0266             addSVGWindowEventListener(scrollEvent, attr);
0267         else if (attr->name() == SVGNames::onzoomAttr)
0268             addSVGWindowEventListener(zoomEvent, attr);*/
0269     }
0270     if (attr->name() == SVGNames::xAttr) {
0271         setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
0272     } else if (attr->name() == SVGNames::yAttr) {
0273         setYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
0274     } else if (attr->name() == SVGNames::widthAttr) {
0275         // qCDebug(KHTML_LOG) << "set width" << attr->value();
0276         setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
0277         addCSSProperty(attr, CSSPropertyWidth, attr->value());
0278         /*if (width().value() < 0.0)
0279             document()->accessSVGExtensions()->reportError("A negative value for svg attribute <width> is not allowed");*/
0280     } else if (attr->name() == SVGNames::heightAttr) {
0281         // qCDebug(KHTML_LOG) << "set height" << attr->value();
0282         setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
0283         addCSSProperty(attr, CSSPropertyHeight, attr->value());
0284         /*if (height().value() < 0.0)
0285             document()->accessSVGExtensions()->reportError("A negative value for svg attribute <height> is not allowed");*/
0286     } else {
0287         /*if (SVGTests::parseMappedAttribute(attr))
0288             return;
0289         if (SVGLangSpace::parseMappedAttribute(attr))
0290             return;
0291         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
0292             return;
0293         if (SVGFitToViewBox::parseMappedAttribute(attr))
0294             return;
0295         if (SVGZoomAndPan::parseMappedAttribute(attr))
0296             return;*/
0297 
0298         SVGStyledLocatableElement::parseMappedAttribute(attr);
0299     }
0300 }
0301 
0302 void SVGSVGElement::svgAttributeChanged(const QualifiedName &attrName)
0303 {
0304     SVGStyledElement::svgAttributeChanged(attrName);
0305 
0306     if (!renderer()) {
0307         return;
0308     }
0309 
0310     /*if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
0311         attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
0312         SVGTests::isKnownAttribute(attrName) ||
0313         SVGLangSpace::isKnownAttribute(attrName) ||
0314         SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
0315         SVGFitToViewBox::isKnownAttribute(attrName) ||
0316         SVGZoomAndPan::isKnownAttribute(attrName) ||
0317         SVGStyledLocatableElement::isKnownAttribute(attrName))
0318         renderer()->setNeedsLayout(true);*/
0319 }
0320 
0321 unsigned long SVGSVGElement::suspendRedraw(unsigned long /* max_wait_milliseconds */)
0322 {
0323     // FIXME: Implement me (see bug 11275)
0324     return 0;
0325 }
0326 
0327 void SVGSVGElement::unsuspendRedraw(unsigned long /* suspend_handle_id */, ExceptionCode & /*ec*/)
0328 {
0329     // if suspend_handle_id is not found, throw exception
0330     // FIXME: Implement me (see bug 11275)
0331 }
0332 
0333 void SVGSVGElement::unsuspendRedrawAll()
0334 {
0335     // FIXME: Implement me (see bug 11275)
0336 }
0337 
0338 void SVGSVGElement::forceRedraw()
0339 {
0340     // FIXME: Implement me (see bug 11275)
0341 }
0342 
0343 DOM::NodeListImpl *SVGSVGElement::getIntersectionList(const FloatRect &rect, SVGElement *)
0344 {
0345     Q_UNUSED(rect);
0346     // FIXME: Implement me (see bug 11274)
0347     return nullptr;
0348 }
0349 
0350 DOM::NodeListImpl *SVGSVGElement::getEnclosureList(const FloatRect &rect, SVGElement *)
0351 {
0352     Q_UNUSED(rect);
0353     // FIXME: Implement me (see bug 11274)
0354     return nullptr;
0355 }
0356 
0357 bool SVGSVGElement::checkIntersection(SVGElement *element, const FloatRect &rect)
0358 {
0359     Q_UNUSED(element);
0360     // TODO : take into account pointer-events?
0361     // FIXME: Why is element ignored??
0362     // FIXME: Implement me (see bug 11274)
0363     return rect.intersects(getBBox());
0364 }
0365 
0366 bool SVGSVGElement::checkEnclosure(SVGElement *element, const FloatRect &rect)
0367 {
0368     Q_UNUSED(element);
0369     // TODO : take into account pointer-events?
0370     // FIXME: Why is element ignored??
0371     // FIXME: Implement me (see bug 11274)
0372     return rect.contains(getBBox());
0373 }
0374 
0375 void SVGSVGElement::deselectAll()
0376 {
0377     //document()->frame()->selectionController()->clear();
0378 }
0379 
0380 float SVGSVGElement::createSVGNumber()
0381 {
0382     return 0.0f;
0383 }
0384 
0385 SVGLength SVGSVGElement::createSVGLength()
0386 {
0387     return SVGLength();
0388 }
0389 
0390 SVGAngle *SVGSVGElement::createSVGAngle()
0391 {
0392     return new SVGAngle();
0393 }
0394 
0395 FloatPoint SVGSVGElement::createSVGPoint()
0396 {
0397     return FloatPoint();
0398 }
0399 
0400 AffineTransform SVGSVGElement::createSVGMatrix()
0401 {
0402     return AffineTransform();
0403 }
0404 
0405 FloatRect SVGSVGElement::createSVGRect()
0406 {
0407     return FloatRect();
0408 }
0409 
0410 SVGTransform SVGSVGElement::createSVGTransform()
0411 {
0412     return SVGTransform();
0413 }
0414 
0415 SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const AffineTransform &matrix)
0416 {
0417     return SVGTransform(matrix);
0418 }
0419 
0420 AffineTransform SVGSVGElement::getCTM() const
0421 {
0422     AffineTransform mat;
0423     if (!isOutermostSVG()) {
0424         mat.translate(x().value(), y().value());
0425     }
0426 
0427     if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) {
0428         AffineTransform viewBox = viewBoxToViewTransform(width().value(), height().value());
0429         mat = viewBox * mat;
0430     }
0431 
0432     return mat;
0433 }
0434 
0435 AffineTransform SVGSVGElement::getScreenCTM() const
0436 {
0437     /*document()->updateLayoutIgnorePendingStylesheets();
0438     float rootX = 0.0f;
0439     float rootY = 0.0f;
0440 
0441     if (RenderObject* renderer = this->renderer()) {
0442         renderer = renderer->parent();
0443         if (isOutermostSVG()) {
0444             int tx = 0;
0445             int ty = 0;
0446             if (renderer)
0447                 renderer->absolutePosition(tx, ty, true);
0448             rootX += tx;
0449             rootY += ty;
0450         } else {
0451             rootX += x().value();
0452             rootY += y().value();
0453         }
0454     }
0455 
0456     AffineTransform mat = SVGStyledLocatableElement::getScreenCTM();
0457     mat.translate(rootX, rootY);
0458 
0459     if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) {
0460         AffineTransform viewBox = viewBoxToViewTransform(width().value(), height().value());
0461         mat = viewBox * mat;
0462     }
0463 
0464     return mat;*/
0465     ASSERT(false);
0466     return AffineTransform();
0467 }
0468 
0469 RenderObject *SVGSVGElement::createRenderer(RenderArena *arena, RenderStyle *)
0470 {
0471     // qCDebug(KHTML_LOG) << "create RenderSVGRoot from <svg> element";
0472     return new(arena) RenderSVGRoot(this);
0473     /*if (isOutermostSVG())
0474         return new (arena) RenderSVGRoot(this);
0475     else
0476         return new (arena) RenderSVGViewportContainer(this);*/
0477 }
0478 
0479 void SVGSVGElement::insertedIntoDocument()
0480 {
0481     document()->accessSVGExtensions()->addTimeContainer(this);
0482     SVGStyledLocatableElement::insertedIntoDocument();
0483 }
0484 
0485 void SVGSVGElement::removedFromDocument()
0486 {
0487     document()->accessSVGExtensions()->removeTimeContainer(this);
0488     SVGStyledLocatableElement::removedFromDocument();
0489 }
0490 
0491 void SVGSVGElement::pauseAnimations()
0492 {
0493     /*if (!m_timeContainer->isPaused())
0494         m_timeContainer->pause();*/
0495 }
0496 
0497 void SVGSVGElement::unpauseAnimations()
0498 {
0499     /*if (m_timeContainer->isPaused())
0500         m_timeContainer->resume();*/
0501 }
0502 
0503 bool SVGSVGElement::animationsPaused() const
0504 {
0505     //return m_timeContainer->isPaused();
0506     ASSERT(false);
0507     return false;
0508 }
0509 
0510 float SVGSVGElement::getCurrentTime() const
0511 {
0512     //return narrowPrecisionToFloat(m_timeContainer->elapsed().value());
0513     ASSERT(false);
0514     return 0.0;
0515 }
0516 
0517 void SVGSVGElement::setCurrentTime(float /* seconds */)
0518 {
0519     // FIXME: Implement me, bug 12073
0520 }
0521 
0522 bool SVGSVGElement::hasRelativeValues() const
0523 {
0524     return (x().isRelative() || width().isRelative() ||
0525             y().isRelative() || height().isRelative());
0526 }
0527 
0528 bool SVGSVGElement::isOutermostSVG() const
0529 {
0530     // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
0531     return !parentNode()->isSVGElement();
0532 }
0533 
0534 AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const
0535 {
0536     FloatRect viewBoxRect;
0537     if (useCurrentView()) {
0538         if (currentView()) { // what if we should use it but it is not set?
0539             viewBoxRect = currentView()->viewBox();
0540         }
0541     } else {
0542         viewBoxRect = viewBox();
0543     }
0544     if (!viewBoxRect.width() || !viewBoxRect.height()) {
0545         return AffineTransform();
0546     }
0547 
0548     AffineTransform ctm = preserveAspectRatio()->getCTM(viewBoxRect.x(),
0549                           viewBoxRect.y(), viewBoxRect.width(), viewBoxRect.height(),
0550                           0, 0, viewWidth, viewHeight);
0551 
0552     if (useCurrentView() && currentView()) {
0553         return currentView()->transform()->concatenate().matrix() * ctm;
0554     }
0555 
0556     return ctm;
0557 }
0558 
0559 /*void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement)
0560 {
0561     setUseCurrentView(true);
0562     if (viewElement->hasAttribute(SVGNames::viewBoxAttr))
0563         currentView()->setViewBox(viewElement->viewBox());
0564     else
0565         currentView()->setViewBox(viewBox());
0566     if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr)) {
0567         currentView()->preserveAspectRatio()->setAlign(viewElement->preserveAspectRatio()->align());
0568         currentView()->preserveAspectRatio()->setMeetOrSlice(viewElement->preserveAspectRatio()->meetOrSlice());
0569     } else {
0570         currentView()->preserveAspectRatio()->setAlign(preserveAspectRatio()->align());
0571         currentView()->preserveAspectRatio()->setMeetOrSlice(preserveAspectRatio()->meetOrSlice());
0572     }
0573     if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr))
0574         currentView()->setZoomAndPan(viewElement->zoomAndPan());
0575     renderer()->setNeedsLayout(true);
0576 }*/
0577 
0578 void SVGSVGElement::willSaveToCache()
0579 {
0580     //pauseAnimations();
0581 }
0582 
0583 void SVGSVGElement::willRestoreFromCache()
0584 {
0585     //unpauseAnimations();
0586 }
0587 
0588 // KHTML stuff
0589 quint32 SVGSVGElement::id() const
0590 {
0591     return SVGNames::svgTag.id();
0592 }
0593 
0594 }
0595 
0596 #endif // ENABLE(SVG)
0597