KHTML
SVGSVGElement.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> 00003 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 00004 2007 Apple Inc. All rights reserved. 00005 00006 This file is part of the KDE project 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "config.h" 00025 #include <wtf/Platform.h> 00026 00027 #if ENABLE(SVG) 00028 #include "SVGSVGElement.h" 00029 00030 #include "AffineTransform.h" 00031 /*#include "CSSHelper.h"*/ 00032 #include "css/csshelper.h" 00033 /*#include "CSSPropertyNames.h"*/ 00034 #include "Document.h" 00035 //#include "EventListener.h" 00036 #include "dom/dom2_events.h" 00037 /*#include "EventNames.h"*/ 00038 #include "FloatConversion.h" 00039 #include "FloatRect.h" 00040 /*#include "Frame.h" 00041 #include "HTMLNames.h" 00042 #include "RenderSVGViewportContainer.h"*/ 00043 #include "RenderSVGRoot.h" 00044 #include "SVGAngle.h" 00045 #include "SVGLength.h" 00046 #include "SVGNames.h" 00047 #include "SVGPreserveAspectRatio.h" 00048 #include "SVGTransform.h" 00049 #include "SVGTransformList.h" 00050 /*#include "SVGViewElement.h"*/ 00051 #include "SVGViewSpec.h" 00052 /*#include "SVGZoomEvent.h" 00053 #include "SelectionController.h" 00054 #include "SMILTimeContainer.h"*/ 00055 #include "khtml_part.h" 00056 00057 namespace WebCore { 00058 00059 /*using namespace HTMLNames; 00060 using namespace EventNames;*/ 00061 using namespace SVGNames; 00062 00063 SVGSVGElement::SVGSVGElement(const QualifiedName& tagName, Document* doc) 00064 : SVGStyledLocatableElement(tagName, doc) 00065 , SVGTests() 00066 , SVGLangSpace() 00067 , SVGExternalResourcesRequired() 00068 , SVGFitToViewBox() 00069 , SVGZoomAndPan() 00070 , m_x(this, LengthModeWidth) 00071 , m_y(this, LengthModeHeight) 00072 , m_width(this, LengthModeWidth) 00073 , m_height(this, LengthModeHeight) 00074 , m_useCurrentView(false) 00075 /*, m_timeContainer(SMILTimeContainer::create(this)) 00076 , m_viewSpec(0)*/ 00077 { 00078 setWidthBaseValue(SVGLength(this, LengthModeWidth, "100%")); 00079 setHeightBaseValue(SVGLength(this, LengthModeHeight, "100%")); 00080 //doc->registerForCacheCallbacks(this); 00081 } 00082 00083 SVGSVGElement::~SVGSVGElement() 00084 { 00085 /*document()->unregisterForCacheCallbacks(this); 00086 // There are cases where removedFromDocument() is not called. 00087 // see ContainerNode::removeAllChildren, called by it's destructor. 00088 document()->accessSVGExtensions()->removeTimeContainer(this);*/ 00089 } 00090 00091 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, X, x, SVGNames::xAttr, m_x) 00092 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y) 00093 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width) 00094 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height) 00095 00096 DOMString SVGSVGElement::contentScriptType() const 00097 { 00098 static const DOMString defaultValue("text/ecmascript"); 00099 DOMString n = getAttribute(contentScriptTypeAttr); 00100 return n.isNull() ? defaultValue : n; 00101 } 00102 00103 void SVGSVGElement::setContentScriptType(const DOMString& type) 00104 { 00105 setAttribute(SVGNames::contentScriptTypeAttr, type); 00106 } 00107 00108 DOMString SVGSVGElement::contentStyleType() const 00109 { 00110 static const DOMString defaultValue("text/css"); 00111 const DOMString n = getAttribute(contentStyleTypeAttr); 00112 return n.isNull() ? defaultValue : n; 00113 } 00114 00115 void SVGSVGElement::setContentStyleType(const DOMString& type) 00116 { 00117 setAttribute(SVGNames::contentStyleTypeAttr, type); 00118 } 00119 00120 bool SVGSVGElement::hasSetContainerSize() const 00121 { 00122 // For now, we interpret % dimensions only if we're a top-level SVG element nested inside 00123 // an another part. ### might even want to check if we're the documentElement; this 00124 // will also need changes with <img> handling 00125 return isOutermostSVG() && document()->part()->parentPart(); 00126 } 00127 00128 IntSize SVGSVGElement::containerSize() const 00129 { 00130 if (KHTMLView* v = document()->view()) 00131 return IntSize(v->visibleWidth(), v->visibleHeight()); 00132 else 00133 return IntSize(300, 150); 00134 } 00135 00136 FloatRect SVGSVGElement::viewport() const 00137 { 00138 double _x = 0.0; 00139 double _y = 0.0; 00140 if (!isOutermostSVG()) { 00141 _x = x().value(); 00142 _y = y().value(); 00143 } 00144 float w = width().value(); 00145 float h = height().value(); 00146 AffineTransform viewBox = viewBoxToViewTransform(w, h); 00147 double wDouble = w; 00148 double hDouble = h; 00149 viewBox.map(_x, _y, &_x, &_y); 00150 viewBox.map(w, h, &wDouble, &hDouble); 00151 return FloatRect::narrowPrecision(_x, _y, wDouble, hDouble); 00152 } 00153 00154 int SVGSVGElement::relativeWidthValue() const 00155 { 00156 SVGLength w = width(); 00157 if (w.unitType() != LengthTypePercentage) 00158 return 0; 00159 00160 return static_cast<int>(w.valueAsPercentage() * containerSize().width()); 00161 } 00162 00163 int SVGSVGElement::relativeHeightValue() const 00164 { 00165 SVGLength h = height(); 00166 if (h.unitType() != LengthTypePercentage) 00167 return 0; 00168 00169 return static_cast<int>(h.valueAsPercentage() * containerSize().height()); 00170 } 00171 00172 float SVGSVGElement::pixelUnitToMillimeterX() const 00173 { 00174 // 2.54 / cssPixelsPerInch gives CM. 00175 return (2.54f / cssPixelsPerInch) * 10.0f; 00176 } 00177 00178 float SVGSVGElement::pixelUnitToMillimeterY() const 00179 { 00180 // 2.54 / cssPixelsPerInch gives CM. 00181 return (2.54f / cssPixelsPerInch) * 10.0f; 00182 } 00183 00184 float SVGSVGElement::screenPixelToMillimeterX() const 00185 { 00186 return pixelUnitToMillimeterX(); 00187 } 00188 00189 float SVGSVGElement::screenPixelToMillimeterY() const 00190 { 00191 return pixelUnitToMillimeterY(); 00192 } 00193 00194 bool SVGSVGElement::useCurrentView() const 00195 { 00196 return m_useCurrentView; 00197 } 00198 00199 void SVGSVGElement::setUseCurrentView(bool currentView) 00200 { 00201 m_useCurrentView = currentView; 00202 } 00203 00204 SVGViewSpec* SVGSVGElement::currentView() const 00205 { 00206 if (!m_viewSpec) 00207 m_viewSpec.set(new SVGViewSpec(this)); 00208 00209 return m_viewSpec.get(); 00210 } 00211 00212 float SVGSVGElement::currentScale() const 00213 { 00214 /*if (document() && document()->frame()) 00215 return document()->frame()->zoomFactor();*/ 00216 return 1.0f; 00217 } 00218 00219 void SVGSVGElement::setCurrentScale(float scale) 00220 { 00221 Q_UNUSED(scale); 00222 /*if (document() && document()->frame()) 00223 document()->frame()->setZoomFactor(scale, true);*/ 00224 } 00225 00226 FloatPoint SVGSVGElement::currentTranslate() const 00227 { 00228 return m_translation; 00229 } 00230 00231 void SVGSVGElement::setCurrentTranslate(const FloatPoint &translation) 00232 { 00233 m_translation = translation; 00234 if (parentNode() == document() && document()->renderer()) 00235 document()->renderer()->repaint(); 00236 } 00237 00238 void SVGSVGElement::addSVGWindowEventListener(const AtomicString& eventType, const Attribute* attr) 00239 { 00240 Q_UNUSED(eventType); 00241 // FIXME: None of these should be window events long term. 00242 // Once we propertly support SVGLoad, etc. 00243 RefPtr<EventListener> listener = document()->accessSVGExtensions()-> 00244 createSVGEventListener(attr->localName().string(), attr->value(), this); 00245 //document()->setHTMLWindowEventListener(eventType, listener.release()); 00246 } 00247 00248 void SVGSVGElement::parseMappedAttribute(MappedAttribute* attr) 00249 { 00250 kDebug() << "parse attribute: " << attr->localName() << attr->value() << endl; 00251 if (!nearestViewportElement()) { 00252 // Only handle events if we're the outermost <svg> element 00253 /*if (attr->name() == onunloadAttr) 00254 addSVGWindowEventListener(unloadEvent, attr); 00255 else if (attr->name() == onabortAttr) 00256 addSVGWindowEventListener(abortEvent, attr); 00257 else if (attr->name() == onerrorAttr) 00258 addSVGWindowEventListener(errorEvent, attr); 00259 else if (attr->name() == onresizeAttr) 00260 addSVGWindowEventListener(resizeEvent, attr); 00261 else if (attr->name() == onscrollAttr) 00262 addSVGWindowEventListener(scrollEvent, attr); 00263 else if (attr->name() == SVGNames::onzoomAttr) 00264 addSVGWindowEventListener(zoomEvent, attr);*/ 00265 } 00266 if (attr->name() == SVGNames::xAttr) 00267 setXBaseValue(SVGLength(this, LengthModeWidth, attr->value())); 00268 else if (attr->name() == SVGNames::yAttr) 00269 setYBaseValue(SVGLength(this, LengthModeHeight, attr->value())); 00270 else if (attr->name() == SVGNames::widthAttr) { 00271 kDebug() << "set width" << attr->value() << endl; 00272 setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value())); 00273 addCSSProperty(attr, CSSPropertyWidth, attr->value()); 00274 /*if (width().value() < 0.0) 00275 document()->accessSVGExtensions()->reportError("A negative value for svg attribute <width> is not allowed");*/ 00276 } else if (attr->name() == SVGNames::heightAttr) { 00277 kDebug() << "set height" << attr->value() << endl; 00278 setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value())); 00279 addCSSProperty(attr, CSSPropertyHeight, attr->value()); 00280 /*if (height().value() < 0.0) 00281 document()->accessSVGExtensions()->reportError("A negative value for svg attribute <height> is not allowed");*/ 00282 } else { 00283 /*if (SVGTests::parseMappedAttribute(attr)) 00284 return; 00285 if (SVGLangSpace::parseMappedAttribute(attr)) 00286 return; 00287 if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) 00288 return; 00289 if (SVGFitToViewBox::parseMappedAttribute(attr)) 00290 return; 00291 if (SVGZoomAndPan::parseMappedAttribute(attr)) 00292 return;*/ 00293 00294 SVGStyledLocatableElement::parseMappedAttribute(attr); 00295 } 00296 } 00297 00298 void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName) 00299 { 00300 SVGStyledElement::svgAttributeChanged(attrName); 00301 00302 if (!renderer()) 00303 return; 00304 00305 /*if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || 00306 attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr || 00307 SVGTests::isKnownAttribute(attrName) || 00308 SVGLangSpace::isKnownAttribute(attrName) || 00309 SVGExternalResourcesRequired::isKnownAttribute(attrName) || 00310 SVGFitToViewBox::isKnownAttribute(attrName) || 00311 SVGZoomAndPan::isKnownAttribute(attrName) || 00312 SVGStyledLocatableElement::isKnownAttribute(attrName)) 00313 renderer()->setNeedsLayout(true);*/ 00314 } 00315 00316 unsigned long SVGSVGElement::suspendRedraw(unsigned long /* max_wait_milliseconds */) 00317 { 00318 // FIXME: Implement me (see bug 11275) 00319 return 0; 00320 } 00321 00322 void SVGSVGElement::unsuspendRedraw(unsigned long /* suspend_handle_id */, ExceptionCode& /*ec*/) 00323 { 00324 // if suspend_handle_id is not found, throw exception 00325 // FIXME: Implement me (see bug 11275) 00326 } 00327 00328 void SVGSVGElement::unsuspendRedrawAll() 00329 { 00330 // FIXME: Implement me (see bug 11275) 00331 } 00332 00333 void SVGSVGElement::forceRedraw() 00334 { 00335 // FIXME: Implement me (see bug 11275) 00336 } 00337 00338 DOM::NodeListImpl* SVGSVGElement::getIntersectionList(const FloatRect& rect, SVGElement*) 00339 { 00340 Q_UNUSED(rect); 00341 // FIXME: Implement me (see bug 11274) 00342 return 0; 00343 } 00344 00345 DOM::NodeListImpl* SVGSVGElement::getEnclosureList(const FloatRect& rect, SVGElement*) 00346 { 00347 Q_UNUSED(rect); 00348 // FIXME: Implement me (see bug 11274) 00349 return 0; 00350 } 00351 00352 bool SVGSVGElement::checkIntersection(SVGElement* element, const FloatRect& rect) 00353 { 00354 Q_UNUSED(element); 00355 // TODO : take into account pointer-events? 00356 // FIXME: Why is element ignored?? 00357 // FIXME: Implement me (see bug 11274) 00358 return rect.intersects(getBBox()); 00359 } 00360 00361 bool SVGSVGElement::checkEnclosure(SVGElement* element, const FloatRect& rect) 00362 { 00363 Q_UNUSED(element); 00364 // TODO : take into account pointer-events? 00365 // FIXME: Why is element ignored?? 00366 // FIXME: Implement me (see bug 11274) 00367 return rect.contains(getBBox()); 00368 } 00369 00370 void SVGSVGElement::deselectAll() 00371 { 00372 //document()->frame()->selectionController()->clear(); 00373 } 00374 00375 float SVGSVGElement::createSVGNumber() 00376 { 00377 return 0.0f; 00378 } 00379 00380 SVGLength SVGSVGElement::createSVGLength() 00381 { 00382 return SVGLength(); 00383 } 00384 00385 SVGAngle* SVGSVGElement::createSVGAngle() 00386 { 00387 return new SVGAngle(); 00388 } 00389 00390 FloatPoint SVGSVGElement::createSVGPoint() 00391 { 00392 return FloatPoint(); 00393 } 00394 00395 AffineTransform SVGSVGElement::createSVGMatrix() 00396 { 00397 return AffineTransform(); 00398 } 00399 00400 FloatRect SVGSVGElement::createSVGRect() 00401 { 00402 return FloatRect(); 00403 } 00404 00405 SVGTransform SVGSVGElement::createSVGTransform() 00406 { 00407 return SVGTransform(); 00408 } 00409 00410 SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const AffineTransform& matrix) 00411 { 00412 return SVGTransform(matrix); 00413 } 00414 00415 AffineTransform SVGSVGElement::getCTM() const 00416 { 00417 AffineTransform mat; 00418 if (!isOutermostSVG()) 00419 mat.translate(x().value(), y().value()); 00420 00421 if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) { 00422 AffineTransform viewBox = viewBoxToViewTransform(width().value(), height().value()); 00423 mat = viewBox * mat; 00424 } 00425 00426 return mat; 00427 } 00428 00429 AffineTransform SVGSVGElement::getScreenCTM() const 00430 { 00431 /*document()->updateLayoutIgnorePendingStylesheets(); 00432 float rootX = 0.0f; 00433 float rootY = 0.0f; 00434 00435 if (RenderObject* renderer = this->renderer()) { 00436 renderer = renderer->parent(); 00437 if (isOutermostSVG()) { 00438 int tx = 0; 00439 int ty = 0; 00440 if (renderer) 00441 renderer->absolutePosition(tx, ty, true); 00442 rootX += tx; 00443 rootY += ty; 00444 } else { 00445 rootX += x().value(); 00446 rootY += y().value(); 00447 } 00448 } 00449 00450 AffineTransform mat = SVGStyledLocatableElement::getScreenCTM(); 00451 mat.translate(rootX, rootY); 00452 00453 if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) { 00454 AffineTransform viewBox = viewBoxToViewTransform(width().value(), height().value()); 00455 mat = viewBox * mat; 00456 } 00457 00458 return mat;*/ 00459 ASSERT(false); 00460 return AffineTransform(); 00461 } 00462 00463 RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*) 00464 { 00465 kDebug() << "create RenderSVGRoot from <svg> element" << endl; 00466 return new (arena) RenderSVGRoot(this); 00467 /*if (isOutermostSVG()) 00468 return new (arena) RenderSVGRoot(this); 00469 else 00470 return new (arena) RenderSVGViewportContainer(this);*/ 00471 } 00472 00473 void SVGSVGElement::insertedIntoDocument() 00474 { 00475 document()->accessSVGExtensions()->addTimeContainer(this); 00476 SVGStyledLocatableElement::insertedIntoDocument(); 00477 } 00478 00479 void SVGSVGElement::removedFromDocument() 00480 { 00481 document()->accessSVGExtensions()->removeTimeContainer(this); 00482 SVGStyledLocatableElement::removedFromDocument(); 00483 } 00484 00485 void SVGSVGElement::pauseAnimations() 00486 { 00487 /*if (!m_timeContainer->isPaused()) 00488 m_timeContainer->pause();*/ 00489 } 00490 00491 void SVGSVGElement::unpauseAnimations() 00492 { 00493 /*if (m_timeContainer->isPaused()) 00494 m_timeContainer->resume();*/ 00495 } 00496 00497 bool SVGSVGElement::animationsPaused() const 00498 { 00499 //return m_timeContainer->isPaused(); 00500 ASSERT(false); 00501 return false; 00502 } 00503 00504 float SVGSVGElement::getCurrentTime() const 00505 { 00506 //return narrowPrecisionToFloat(m_timeContainer->elapsed().value()); 00507 ASSERT(false); 00508 return 0.0; 00509 } 00510 00511 void SVGSVGElement::setCurrentTime(float /* seconds */) 00512 { 00513 // FIXME: Implement me, bug 12073 00514 } 00515 00516 bool SVGSVGElement::hasRelativeValues() const 00517 { 00518 return (x().isRelative() || width().isRelative() || 00519 y().isRelative() || height().isRelative()); 00520 } 00521 00522 bool SVGSVGElement::isOutermostSVG() const 00523 { 00524 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it 00525 return !parentNode()->isSVGElement(); 00526 } 00527 00528 AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const 00529 { 00530 FloatRect viewBoxRect; 00531 if (useCurrentView()) { 00532 if (currentView()) // what if we should use it but it is not set? 00533 viewBoxRect = currentView()->viewBox(); 00534 } else 00535 viewBoxRect = viewBox(); 00536 if (!viewBoxRect.width() || !viewBoxRect.height()) 00537 return AffineTransform(); 00538 00539 AffineTransform ctm = preserveAspectRatio()->getCTM(viewBoxRect.x(), 00540 viewBoxRect.y(), viewBoxRect.width(), viewBoxRect.height(), 00541 0, 0, viewWidth, viewHeight); 00542 00543 if (useCurrentView() && currentView()) 00544 return currentView()->transform()->concatenate().matrix() * ctm; 00545 00546 return ctm; 00547 } 00548 00549 /*void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement) 00550 { 00551 setUseCurrentView(true); 00552 if (viewElement->hasAttribute(SVGNames::viewBoxAttr)) 00553 currentView()->setViewBox(viewElement->viewBox()); 00554 else 00555 currentView()->setViewBox(viewBox()); 00556 if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr)) { 00557 currentView()->preserveAspectRatio()->setAlign(viewElement->preserveAspectRatio()->align()); 00558 currentView()->preserveAspectRatio()->setMeetOrSlice(viewElement->preserveAspectRatio()->meetOrSlice()); 00559 } else { 00560 currentView()->preserveAspectRatio()->setAlign(preserveAspectRatio()->align()); 00561 currentView()->preserveAspectRatio()->setMeetOrSlice(preserveAspectRatio()->meetOrSlice()); 00562 } 00563 if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr)) 00564 currentView()->setZoomAndPan(viewElement->zoomAndPan()); 00565 renderer()->setNeedsLayout(true); 00566 }*/ 00567 00568 void SVGSVGElement::willSaveToCache() 00569 { 00570 //pauseAnimations(); 00571 } 00572 00573 void SVGSVGElement::willRestoreFromCache() 00574 { 00575 //unpauseAnimations(); 00576 } 00577 00578 // KHTML stuff 00579 quint32 SVGSVGElement::id() const { return SVGNames::svgTag.id(); } 00580 00581 } 00582 00583 #endif // ENABLE(SVG) 00584 00585 // vim:ts=4:noet
KDE 4.6 API Reference