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