PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/qt/qtwebkit/Source/WebCore/svg/SVGSVGElement.cpp

https://gitlab.com/x33n/phantomjs
C++ | 801 lines | 586 code | 130 blank | 85 comment | 164 complexity | 30c434df31ff1bf0e8679799f4744abe MD5 | raw file
  1. /*
  2. * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
  3. * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis@kde.org>
  4. * Copyright (C) 2007 Apple Inc. All rights reserved.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Library General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Library General Public License
  17. * along with this library; see the file COPYING.LIB. If not, write to
  18. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19. * Boston, MA 02110-1301, USA.
  20. */
  21. #include "config.h"
  22. #if ENABLE(SVG)
  23. #include "SVGSVGElement.h"
  24. #include "AffineTransform.h"
  25. #include "Attribute.h"
  26. #include "CSSHelper.h"
  27. #include "Document.h"
  28. #include "EventListener.h"
  29. #include "EventNames.h"
  30. #include "FloatConversion.h"
  31. #include "FloatRect.h"
  32. #include "Frame.h"
  33. #include "FrameSelection.h"
  34. #include "FrameTree.h"
  35. #include "FrameView.h"
  36. #include "HTMLNames.h"
  37. #include "NodeTraversal.h"
  38. #include "RenderObject.h"
  39. #include "RenderPart.h"
  40. #include "RenderSVGResource.h"
  41. #include "RenderSVGModelObject.h"
  42. #include "RenderSVGRoot.h"
  43. #include "RenderSVGViewportContainer.h"
  44. #include "SMILTimeContainer.h"
  45. #include "SVGAngle.h"
  46. #include "SVGElementInstance.h"
  47. #include "SVGFitToViewBox.h"
  48. #include "SVGNames.h"
  49. #include "SVGPreserveAspectRatio.h"
  50. #include "SVGTransform.h"
  51. #include "SVGTransformList.h"
  52. #include "SVGViewElement.h"
  53. #include "SVGViewSpec.h"
  54. #include "SVGZoomEvent.h"
  55. #include "ScriptEventListener.h"
  56. #include "StaticNodeList.h"
  57. #include <wtf/StdLibExtras.h>
  58. namespace WebCore {
  59. // Animated property definitions
  60. DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::xAttr, X, x)
  61. DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::yAttr, Y, y)
  62. DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::widthAttr, Width, width)
  63. DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::heightAttr, Height, height)
  64. DEFINE_ANIMATED_BOOLEAN(SVGSVGElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
  65. DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGSVGElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio)
  66. DEFINE_ANIMATED_RECT(SVGSVGElement, SVGNames::viewBoxAttr, ViewBox, viewBox)
  67. BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGSVGElement)
  68. REGISTER_LOCAL_ANIMATED_PROPERTY(x)
  69. REGISTER_LOCAL_ANIMATED_PROPERTY(y)
  70. REGISTER_LOCAL_ANIMATED_PROPERTY(width)
  71. REGISTER_LOCAL_ANIMATED_PROPERTY(height)
  72. REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
  73. REGISTER_LOCAL_ANIMATED_PROPERTY(viewBox)
  74. REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAspectRatio)
  75. REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
  76. END_REGISTER_ANIMATED_PROPERTIES
  77. inline SVGSVGElement::SVGSVGElement(const QualifiedName& tagName, Document* doc)
  78. : SVGGraphicsElement(tagName, doc)
  79. , m_x(LengthModeWidth)
  80. , m_y(LengthModeHeight)
  81. , m_width(LengthModeWidth, "100%")
  82. , m_height(LengthModeHeight, "100%")
  83. , m_useCurrentView(false)
  84. , m_zoomAndPan(SVGZoomAndPanMagnify)
  85. , m_timeContainer(SMILTimeContainer::create(this))
  86. {
  87. ASSERT(hasTagName(SVGNames::svgTag));
  88. registerAnimatedPropertiesForSVGSVGElement();
  89. doc->registerForPageCacheSuspensionCallbacks(this);
  90. }
  91. PassRefPtr<SVGSVGElement> SVGSVGElement::create(const QualifiedName& tagName, Document* document)
  92. {
  93. return adoptRef(new SVGSVGElement(tagName, document));
  94. }
  95. SVGSVGElement::~SVGSVGElement()
  96. {
  97. if (m_viewSpec)
  98. m_viewSpec->resetContextElement();
  99. document()->unregisterForPageCacheSuspensionCallbacks(this);
  100. // There are cases where removedFromDocument() is not called.
  101. // see ContainerNode::removeAllChildren, called by its destructor.
  102. document()->accessSVGExtensions()->removeTimeContainer(this);
  103. }
  104. void SVGSVGElement::didMoveToNewDocument(Document* oldDocument)
  105. {
  106. if (oldDocument)
  107. oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
  108. document()->registerForPageCacheSuspensionCallbacks(this);
  109. SVGGraphicsElement::didMoveToNewDocument(oldDocument);
  110. }
  111. const AtomicString& SVGSVGElement::contentScriptType() const
  112. {
  113. DEFINE_STATIC_LOCAL(const AtomicString, defaultValue, ("text/ecmascript", AtomicString::ConstructFromLiteral));
  114. const AtomicString& n = fastGetAttribute(SVGNames::contentScriptTypeAttr);
  115. return n.isNull() ? defaultValue : n;
  116. }
  117. void SVGSVGElement::setContentScriptType(const AtomicString& type)
  118. {
  119. setAttribute(SVGNames::contentScriptTypeAttr, type);
  120. }
  121. const AtomicString& SVGSVGElement::contentStyleType() const
  122. {
  123. DEFINE_STATIC_LOCAL(const AtomicString, defaultValue, ("text/css", AtomicString::ConstructFromLiteral));
  124. const AtomicString& n = fastGetAttribute(SVGNames::contentStyleTypeAttr);
  125. return n.isNull() ? defaultValue : n;
  126. }
  127. void SVGSVGElement::setContentStyleType(const AtomicString& type)
  128. {
  129. setAttribute(SVGNames::contentStyleTypeAttr, type);
  130. }
  131. FloatRect SVGSVGElement::viewport() const
  132. {
  133. // FIXME: This method doesn't follow the spec and is basically untested. Parent documents are not considered here.
  134. // As we have no test coverage for this, we're going to disable it completly for now.
  135. return FloatRect();
  136. }
  137. float SVGSVGElement::pixelUnitToMillimeterX() const
  138. {
  139. // 2.54 / cssPixelsPerInch gives CM.
  140. return (2.54f / cssPixelsPerInch) * 10.0f;
  141. }
  142. float SVGSVGElement::pixelUnitToMillimeterY() const
  143. {
  144. // 2.54 / cssPixelsPerInch gives CM.
  145. return (2.54f / cssPixelsPerInch) * 10.0f;
  146. }
  147. float SVGSVGElement::screenPixelToMillimeterX() const
  148. {
  149. return pixelUnitToMillimeterX();
  150. }
  151. float SVGSVGElement::screenPixelToMillimeterY() const
  152. {
  153. return pixelUnitToMillimeterY();
  154. }
  155. SVGViewSpec* SVGSVGElement::currentView()
  156. {
  157. if (!m_viewSpec)
  158. m_viewSpec = SVGViewSpec::create(this);
  159. return m_viewSpec.get();
  160. }
  161. float SVGSVGElement::currentScale() const
  162. {
  163. if (!inDocument() || !isOutermostSVGSVGElement())
  164. return 1;
  165. Frame* frame = document()->frame();
  166. if (!frame)
  167. return 1;
  168. FrameTree* frameTree = frame->tree();
  169. ASSERT(frameTree);
  170. // The behaviour of currentScale() is undefined, when we're dealing with non-standalone SVG documents.
  171. // If the svg is embedded, the scaling is handled by the host renderer, so when asking from inside
  172. // the SVG document, a scale value of 1 seems reasonable, as it doesn't know anything about the parent scale.
  173. return frameTree->parent() ? 1 : frame->pageZoomFactor();
  174. }
  175. void SVGSVGElement::setCurrentScale(float scale)
  176. {
  177. if (!inDocument() || !isOutermostSVGSVGElement())
  178. return;
  179. Frame* frame = document()->frame();
  180. if (!frame)
  181. return;
  182. FrameTree* frameTree = frame->tree();
  183. ASSERT(frameTree);
  184. // The behaviour of setCurrentScale() is undefined, when we're dealing with non-standalone SVG documents.
  185. // We choose the ignore this call, it's pretty useless to support calling setCurrentScale() from within
  186. // an embedded SVG document, for the same reasons as in currentScale() - needs resolution by SVG WG.
  187. if (frameTree->parent())
  188. return;
  189. frame->setPageZoomFactor(scale);
  190. }
  191. void SVGSVGElement::setCurrentTranslate(const FloatPoint& translation)
  192. {
  193. m_translation = translation;
  194. updateCurrentTranslate();
  195. }
  196. void SVGSVGElement::updateCurrentTranslate()
  197. {
  198. if (RenderObject* object = renderer())
  199. object->setNeedsLayout(true);
  200. if (parentNode() == document() && document()->renderer())
  201. document()->renderer()->repaint();
  202. }
  203. void SVGSVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
  204. {
  205. SVGParsingError parseError = NoError;
  206. if (!nearestViewportElement()) {
  207. bool setListener = true;
  208. // Only handle events if we're the outermost <svg> element
  209. if (name == HTMLNames::onunloadAttr)
  210. document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), name, value));
  211. else if (name == HTMLNames::onresizeAttr)
  212. document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), name, value));
  213. else if (name == HTMLNames::onscrollAttr)
  214. document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), name, value));
  215. else if (name == SVGNames::onzoomAttr)
  216. document()->setWindowAttributeEventListener(eventNames().zoomEvent, createAttributeEventListener(document()->frame(), name, value));
  217. else
  218. setListener = false;
  219. if (setListener)
  220. return;
  221. }
  222. if (name == HTMLNames::onabortAttr)
  223. document()->setWindowAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(document()->frame(), name, value));
  224. else if (name == HTMLNames::onerrorAttr)
  225. document()->setWindowAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(document()->frame(), name, value));
  226. else if (name == SVGNames::xAttr)
  227. setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
  228. else if (name == SVGNames::yAttr)
  229. setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
  230. else if (name == SVGNames::widthAttr)
  231. setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
  232. else if (name == SVGNames::heightAttr)
  233. setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
  234. else if (SVGLangSpace::parseAttribute(name, value)
  235. || SVGExternalResourcesRequired::parseAttribute(name, value)
  236. || SVGFitToViewBox::parseAttribute(this, name, value)
  237. || SVGZoomAndPan::parseAttribute(this, name, value)) {
  238. } else
  239. SVGGraphicsElement::parseAttribute(name, value);
  240. reportAttributeParsingError(parseError, name, value);
  241. }
  242. void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName)
  243. {
  244. bool updateRelativeLengthsOrViewBox = false;
  245. bool widthChanged = attrName == SVGNames::widthAttr;
  246. if (widthChanged
  247. || attrName == SVGNames::heightAttr
  248. || attrName == SVGNames::xAttr
  249. || attrName == SVGNames::yAttr) {
  250. updateRelativeLengthsOrViewBox = true;
  251. updateRelativeLengthsInformation();
  252. // At the SVG/HTML boundary (aka RenderSVGRoot), the width attribute can
  253. // affect the replaced size so we need to mark it for updating.
  254. if (widthChanged) {
  255. RenderObject* renderObject = renderer();
  256. if (renderObject && renderObject->isSVGRoot())
  257. toRenderSVGRoot(renderObject)->setNeedsLayoutAndPrefWidthsRecalc();
  258. }
  259. }
  260. if (SVGFitToViewBox::isKnownAttribute(attrName)) {
  261. updateRelativeLengthsOrViewBox = true;
  262. if (RenderObject* object = renderer())
  263. object->setNeedsTransformUpdate();
  264. }
  265. SVGElementInstance::InvalidationGuard invalidationGuard(this);
  266. if (updateRelativeLengthsOrViewBox
  267. || SVGLangSpace::isKnownAttribute(attrName)
  268. || SVGExternalResourcesRequired::isKnownAttribute(attrName)
  269. || SVGZoomAndPan::isKnownAttribute(attrName)) {
  270. if (renderer())
  271. RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer());
  272. return;
  273. }
  274. SVGGraphicsElement::svgAttributeChanged(attrName);
  275. }
  276. unsigned SVGSVGElement::suspendRedraw(unsigned /* maxWaitMilliseconds */)
  277. {
  278. // FIXME: Implement me (see bug 11275)
  279. return 0;
  280. }
  281. void SVGSVGElement::unsuspendRedraw(unsigned /* suspendHandleId */)
  282. {
  283. // FIXME: Implement me (see bug 11275)
  284. }
  285. void SVGSVGElement::unsuspendRedrawAll()
  286. {
  287. // FIXME: Implement me (see bug 11275)
  288. }
  289. void SVGSVGElement::forceRedraw()
  290. {
  291. // FIXME: Implement me (see bug 11275)
  292. }
  293. PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const FloatRect& rect, SVGElement* referenceElement, CollectIntersectionOrEnclosure collect) const
  294. {
  295. Vector<RefPtr<Node> > nodes;
  296. Element* element = ElementTraversal::next(referenceElement ? referenceElement : this);
  297. while (element) {
  298. if (element->isSVGElement()) {
  299. SVGElement* svgElement = toSVGElement(element);
  300. if (collect == CollectIntersectionList) {
  301. if (checkIntersection(svgElement, rect))
  302. nodes.append(element);
  303. } else {
  304. if (checkEnclosure(svgElement, rect))
  305. nodes.append(element);
  306. }
  307. }
  308. element = ElementTraversal::next(element, referenceElement ? referenceElement : this);
  309. }
  310. return StaticNodeList::adopt(nodes);
  311. }
  312. PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(const FloatRect& rect, SVGElement* referenceElement) const
  313. {
  314. return collectIntersectionOrEnclosureList(rect, referenceElement, CollectIntersectionList);
  315. }
  316. PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(const FloatRect& rect, SVGElement* referenceElement) const
  317. {
  318. return collectIntersectionOrEnclosureList(rect, referenceElement, CollectEnclosureList);
  319. }
  320. bool SVGSVGElement::checkIntersection(SVGElement* element, const FloatRect& rect) const
  321. {
  322. if (!element)
  323. return false;
  324. return RenderSVGModelObject::checkIntersection(element->renderer(), rect);
  325. }
  326. bool SVGSVGElement::checkEnclosure(SVGElement* element, const FloatRect& rect) const
  327. {
  328. if (!element)
  329. return false;
  330. return RenderSVGModelObject::checkEnclosure(element->renderer(), rect);
  331. }
  332. void SVGSVGElement::deselectAll()
  333. {
  334. if (Frame* frame = document()->frame())
  335. frame->selection()->clear();
  336. }
  337. float SVGSVGElement::createSVGNumber()
  338. {
  339. return 0.0f;
  340. }
  341. SVGLength SVGSVGElement::createSVGLength()
  342. {
  343. return SVGLength();
  344. }
  345. SVGAngle SVGSVGElement::createSVGAngle()
  346. {
  347. return SVGAngle();
  348. }
  349. SVGPoint SVGSVGElement::createSVGPoint()
  350. {
  351. return SVGPoint();
  352. }
  353. SVGMatrix SVGSVGElement::createSVGMatrix()
  354. {
  355. return SVGMatrix();
  356. }
  357. FloatRect SVGSVGElement::createSVGRect()
  358. {
  359. return FloatRect();
  360. }
  361. SVGTransform SVGSVGElement::createSVGTransform()
  362. {
  363. return SVGTransform(SVGTransform::SVG_TRANSFORM_MATRIX);
  364. }
  365. SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix& matrix)
  366. {
  367. return SVGTransform(static_cast<const AffineTransform&>(matrix));
  368. }
  369. AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const
  370. {
  371. AffineTransform viewBoxTransform;
  372. if (!hasEmptyViewBox()) {
  373. FloatSize size = currentViewportSize();
  374. viewBoxTransform = viewBoxToViewTransform(size.width(), size.height());
  375. }
  376. AffineTransform transform;
  377. if (!isOutermostSVGSVGElement()) {
  378. SVGLengthContext lengthContext(this);
  379. transform.translate(x().value(lengthContext), y().value(lengthContext));
  380. } else if (mode == SVGLocatable::ScreenScope) {
  381. if (RenderObject* renderer = this->renderer()) {
  382. FloatPoint location;
  383. float zoomFactor = 1;
  384. // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform
  385. // to map an element from SVG viewport coordinates to CSS box coordinates.
  386. // RenderSVGRoot's localToAbsolute method expects CSS box coordinates.
  387. // We also need to adjust for the zoom level factored into CSS coordinates (bug #96361).
  388. if (renderer->isSVGRoot()) {
  389. location = toRenderSVGRoot(renderer)->localToBorderBoxTransform().mapPoint(location);
  390. zoomFactor = 1 / renderer->style()->effectiveZoom();
  391. }
  392. // Translate in our CSS parent coordinate space
  393. // FIXME: This doesn't work correctly with CSS transforms.
  394. location = renderer->localToAbsolute(location, UseTransforms);
  395. location.scale(zoomFactor, zoomFactor);
  396. // Be careful here! localToBorderBoxTransform() included the x/y offset coming from the viewBoxToViewTransform(),
  397. // so we have to subtract it here (original cause of bug #27183)
  398. transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f());
  399. // Respect scroll offset.
  400. if (FrameView* view = document()->view()) {
  401. LayoutSize scrollOffset = view->scrollOffset();
  402. scrollOffset.scale(zoomFactor);
  403. transform.translate(-scrollOffset.width(), -scrollOffset.height());
  404. }
  405. }
  406. }
  407. return transform.multiply(viewBoxTransform);
  408. }
  409. bool SVGSVGElement::rendererIsNeeded(const NodeRenderingContext& context)
  410. {
  411. // FIXME: We should respect display: none on the documentElement svg element
  412. // but many things in FrameView and SVGImage depend on the RenderSVGRoot when
  413. // they should instead depend on the RenderView.
  414. // https://bugs.webkit.org/show_bug.cgi?id=103493
  415. if (document()->documentElement() == this)
  416. return true;
  417. return StyledElement::rendererIsNeeded(context);
  418. }
  419. RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*)
  420. {
  421. if (isOutermostSVGSVGElement())
  422. return new (arena) RenderSVGRoot(this);
  423. return new (arena) RenderSVGViewportContainer(this);
  424. }
  425. Node::InsertionNotificationRequest SVGSVGElement::insertedInto(ContainerNode* rootParent)
  426. {
  427. if (rootParent->inDocument()) {
  428. document()->accessSVGExtensions()->addTimeContainer(this);
  429. // Animations are started at the end of document parsing and after firing the load event,
  430. // but if we miss that train (deferred programmatic element insertion for example) we need
  431. // to initialize the time container here.
  432. if (!document()->parsing() && !document()->processingLoadEvent() && document()->loadEventFinished() && !timeContainer()->isStarted())
  433. timeContainer()->begin();
  434. }
  435. return SVGGraphicsElement::insertedInto(rootParent);
  436. }
  437. void SVGSVGElement::removedFrom(ContainerNode* rootParent)
  438. {
  439. if (rootParent->inDocument())
  440. document()->accessSVGExtensions()->removeTimeContainer(this);
  441. SVGGraphicsElement::removedFrom(rootParent);
  442. }
  443. void SVGSVGElement::pauseAnimations()
  444. {
  445. if (!m_timeContainer->isPaused())
  446. m_timeContainer->pause();
  447. }
  448. void SVGSVGElement::unpauseAnimations()
  449. {
  450. if (m_timeContainer->isPaused())
  451. m_timeContainer->resume();
  452. }
  453. bool SVGSVGElement::animationsPaused() const
  454. {
  455. return m_timeContainer->isPaused();
  456. }
  457. float SVGSVGElement::getCurrentTime() const
  458. {
  459. return narrowPrecisionToFloat(m_timeContainer->elapsed().value());
  460. }
  461. void SVGSVGElement::setCurrentTime(float seconds)
  462. {
  463. if (std::isnan(seconds))
  464. return;
  465. seconds = max(seconds, 0.0f);
  466. m_timeContainer->setElapsed(seconds);
  467. }
  468. bool SVGSVGElement::selfHasRelativeLengths() const
  469. {
  470. return x().isRelative()
  471. || y().isRelative()
  472. || width().isRelative()
  473. || height().isRelative()
  474. || hasAttribute(SVGNames::viewBoxAttr);
  475. }
  476. FloatRect SVGSVGElement::currentViewBoxRect() const
  477. {
  478. if (m_useCurrentView)
  479. return m_viewSpec ? m_viewSpec->viewBox() : FloatRect();
  480. FloatRect useViewBox = viewBox();
  481. if (!useViewBox.isEmpty())
  482. return useViewBox;
  483. if (!renderer() || !renderer()->isSVGRoot())
  484. return FloatRect();
  485. if (!toRenderSVGRoot(renderer())->isEmbeddedThroughSVGImage())
  486. return FloatRect();
  487. Length intrinsicWidth = this->intrinsicWidth();
  488. Length intrinsicHeight = this->intrinsicHeight();
  489. if (!intrinsicWidth.isFixed() || !intrinsicHeight.isFixed())
  490. return FloatRect();
  491. // If no viewBox is specified but non-relative width/height values, then we
  492. // should always synthesize a viewBox if we're embedded through a SVGImage.
  493. return FloatRect(FloatPoint(), FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0)));
  494. }
  495. FloatSize SVGSVGElement::currentViewportSize() const
  496. {
  497. Length intrinsicWidth = this->intrinsicWidth();
  498. Length intrinsicHeight = this->intrinsicHeight();
  499. if (intrinsicWidth.isFixed() && intrinsicHeight.isFixed())
  500. return FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0));
  501. if (!renderer())
  502. return FloatSize();
  503. if (renderer()->isSVGRoot()) {
  504. LayoutRect contentBoxRect = toRenderSVGRoot(renderer())->contentBoxRect();
  505. return FloatSize(contentBoxRect.width() / renderer()->style()->effectiveZoom(), contentBoxRect.height() / renderer()->style()->effectiveZoom());
  506. }
  507. FloatRect viewportRect = toRenderSVGViewportContainer(renderer())->viewport();
  508. return FloatSize(viewportRect.width(), viewportRect.height());
  509. }
  510. bool SVGSVGElement::widthAttributeEstablishesViewport() const
  511. {
  512. if (!renderer() || renderer()->isSVGViewportContainer())
  513. return true;
  514. // Spec: http://www.w3.org/TR/SVG/coords.html#ViewportSpace
  515. // The ‘width’ attribute on the outermost svg element establishes the viewport's width, unless the following conditions are met:
  516. // - the SVG content is a separately stored resource that is embedded by reference (such as the ‘object’ element in XHTML [XHTML]), or
  517. // the SVG content is embedded inline within a containing document;
  518. // - and the referencing element or containing document is styled using CSS [CSS2] or XSL [XSL];
  519. // - and there are CSS-compatible positioning properties ([CSS2], section 9.3) specified on the referencing element (e.g., the ‘object’ element)
  520. // or on the containing document's outermost svg element that are sufficient to establish the width of the viewport. Under these conditions,
  521. // the positioning properties establish the viewport's width.
  522. RenderSVGRoot* root = toRenderSVGRoot(renderer());
  523. // SVG embedded through object/embed/iframe.
  524. if (root->isEmbeddedThroughFrameContainingSVGDocument())
  525. return !root->hasReplacedLogicalWidth() && !document()->frame()->ownerRenderer()->hasReplacedLogicalWidth();
  526. // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG.
  527. if (root->isEmbeddedThroughSVGImage() || document()->documentElement() != this)
  528. return !root->hasReplacedLogicalWidth();
  529. return true;
  530. }
  531. bool SVGSVGElement::heightAttributeEstablishesViewport() const
  532. {
  533. if (!renderer() || renderer()->isSVGViewportContainer())
  534. return true;
  535. // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing
  536. // Similarly, if there are positioning properties specified on the referencing element or on the outermost svg element
  537. // that are sufficient to establish the height of the viewport, then these positioning properties establish the viewport's
  538. // height; otherwise, the ‘height’ attribute on the outermost svg element establishes the viewport's height.
  539. RenderSVGRoot* root = toRenderSVGRoot(renderer());
  540. // SVG embedded through object/embed/iframe.
  541. if (root->isEmbeddedThroughFrameContainingSVGDocument())
  542. return !root->hasReplacedLogicalHeight() && !document()->frame()->ownerRenderer()->hasReplacedLogicalHeight();
  543. // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG.
  544. if (root->isEmbeddedThroughSVGImage() || document()->documentElement() != this)
  545. return !root->hasReplacedLogicalHeight();
  546. return true;
  547. }
  548. Length SVGSVGElement::intrinsicWidth(ConsiderCSSMode mode) const
  549. {
  550. if (widthAttributeEstablishesViewport() || mode == IgnoreCSSProperties) {
  551. if (width().unitType() == LengthTypePercentage)
  552. return Length(width().valueAsPercentage() * 100, Percent);
  553. SVGLengthContext lengthContext(this);
  554. return Length(width().value(lengthContext), Fixed);
  555. }
  556. ASSERT(renderer());
  557. return renderer()->style()->width();
  558. }
  559. Length SVGSVGElement::intrinsicHeight(ConsiderCSSMode mode) const
  560. {
  561. if (heightAttributeEstablishesViewport() || mode == IgnoreCSSProperties) {
  562. if (height().unitType() == LengthTypePercentage)
  563. return Length(height().valueAsPercentage() * 100, Percent);
  564. SVGLengthContext lengthContext(this);
  565. return Length(height().value(lengthContext), Fixed);
  566. }
  567. ASSERT(renderer());
  568. return renderer()->style()->height();
  569. }
  570. AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const
  571. {
  572. if (!m_useCurrentView || !m_viewSpec)
  573. return SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), preserveAspectRatio(), viewWidth, viewHeight);
  574. AffineTransform ctm = SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), m_viewSpec->preserveAspectRatio(), viewWidth, viewHeight);
  575. const SVGTransformList& transformList = m_viewSpec->transformBaseValue();
  576. if (transformList.isEmpty())
  577. return ctm;
  578. AffineTransform transform;
  579. if (transformList.concatenate(transform))
  580. ctm *= transform;
  581. return ctm;
  582. }
  583. void SVGSVGElement::setupInitialView(const String& fragmentIdentifier, Element* anchorNode)
  584. {
  585. RenderObject* renderer = this->renderer();
  586. SVGViewSpec* view = m_viewSpec.get();
  587. if (view)
  588. view->reset();
  589. bool hadUseCurrentView = m_useCurrentView;
  590. m_useCurrentView = false;
  591. if (fragmentIdentifier.startsWith("xpointer(")) {
  592. // FIXME: XPointer references are ignored (https://bugs.webkit.org/show_bug.cgi?id=17491)
  593. if (renderer && hadUseCurrentView)
  594. RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
  595. return;
  596. }
  597. if (fragmentIdentifier.startsWith("svgView(")) {
  598. if (!view)
  599. view = currentView(); // Create the SVGViewSpec.
  600. if (view->parseViewSpec(fragmentIdentifier))
  601. m_useCurrentView = true;
  602. else
  603. view->reset();
  604. if (renderer && (hadUseCurrentView || m_useCurrentView))
  605. RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
  606. return;
  607. }
  608. // Spec: If the SVG fragment identifier addresses a ‘view’ element within an SVG document (e.g., MyDrawing.svg#MyView
  609. // or MyDrawing.svg#xpointer(id('MyView'))) then the closest ancestor ‘svg’ element is displayed in the viewport.
  610. // Any view specification attributes included on the given ‘view’ element override the corresponding view specification
  611. // attributes on the closest ancestor ‘svg’ element.
  612. if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
  613. if (SVGViewElement* viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0) {
  614. SVGElement* element = SVGLocatable::nearestViewportElement(viewElement);
  615. if (element->hasTagName(SVGNames::svgTag)) {
  616. SVGSVGElement* svg = static_cast<SVGSVGElement*>(element);
  617. svg->inheritViewAttributes(viewElement);
  618. if (RenderObject* renderer = svg->renderer())
  619. RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
  620. }
  621. }
  622. return;
  623. }
  624. // FIXME: We need to decide which <svg> to focus on, and zoom to it.
  625. // FIXME: We need to actually "highlight" the viewTarget(s).
  626. }
  627. void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement)
  628. {
  629. SVGViewSpec* view = currentView();
  630. m_useCurrentView = true;
  631. if (viewElement->hasAttribute(SVGNames::viewBoxAttr))
  632. view->setViewBoxBaseValue(viewElement->viewBox());
  633. else
  634. view->setViewBoxBaseValue(viewBox());
  635. if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr))
  636. view->setPreserveAspectRatioBaseValue(viewElement->preserveAspectRatioBaseValue());
  637. else
  638. view->setPreserveAspectRatioBaseValue(preserveAspectRatioBaseValue());
  639. if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr))
  640. view->setZoomAndPanBaseValue(viewElement->zoomAndPan());
  641. else
  642. view->setZoomAndPanBaseValue(zoomAndPan());
  643. }
  644. void SVGSVGElement::documentWillSuspendForPageCache()
  645. {
  646. pauseAnimations();
  647. }
  648. void SVGSVGElement::documentDidResumeFromPageCache()
  649. {
  650. unpauseAnimations();
  651. }
  652. // getElementById on SVGSVGElement is restricted to only the child subtree defined by the <svg> element.
  653. // See http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGSVGElement
  654. Element* SVGSVGElement::getElementById(const AtomicString& id) const
  655. {
  656. Element* element = treeScope()->getElementById(id);
  657. if (element && element->isDescendantOf(this))
  658. return element;
  659. // Fall back to traversing our subtree. Duplicate ids are allowed, the first found will
  660. // be returned.
  661. for (Node* node = firstChild(); node; node = NodeTraversal::next(node, this)) {
  662. if (!node->isElementNode())
  663. continue;
  664. Element* element = toElement(node);
  665. if (element->getIdAttribute() == id)
  666. return element;
  667. }
  668. return 0;
  669. }
  670. }
  671. #endif // ENABLE(SVG)