SVGSVGElement.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include <stdint.h>
  6. #include "mozilla/ArrayUtils.h"
  7. #include "mozilla/ContentEvents.h"
  8. #include "mozilla/EventDispatcher.h"
  9. #include "mozilla/Likely.h"
  10. #include "nsGkAtoms.h"
  11. #include "nsLayoutUtils.h"
  12. #include "nsLayoutStylesheetCache.h"
  13. #include "DOMSVGNumber.h"
  14. #include "DOMSVGLength.h"
  15. #include "nsSVGAngle.h"
  16. #include "nsCOMPtr.h"
  17. #include "nsIPresShell.h"
  18. #include "nsContentUtils.h"
  19. #include "nsIDocument.h"
  20. #include "mozilla/dom/SVGMatrix.h"
  21. #include "DOMSVGPoint.h"
  22. #include "nsIFrame.h"
  23. #include "nsFrameSelection.h"
  24. #include "nsISVGSVGFrame.h" //XXX
  25. #include "mozilla/dom/SVGRect.h"
  26. #include "nsError.h"
  27. #include "nsISVGChildFrame.h"
  28. #include "mozilla/dom/SVGSVGElement.h"
  29. #include "mozilla/dom/SVGSVGElementBinding.h"
  30. #include "nsSVGUtils.h"
  31. #include "mozilla/dom/SVGViewElement.h"
  32. #include "nsStyleUtil.h"
  33. #include "SVGContentUtils.h"
  34. #include "nsSMILTimeContainer.h"
  35. #include "nsSMILAnimationController.h"
  36. #include "nsSMILTypes.h"
  37. #include "SVGAngle.h"
  38. #include <algorithm>
  39. #include "prtime.h"
  40. NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT_CHECK_PARSER(SVG)
  41. using namespace mozilla::gfx;
  42. namespace mozilla {
  43. namespace dom {
  44. class SVGAnimatedLength;
  45. JSObject*
  46. SVGSVGElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
  47. {
  48. return SVGSVGElementBinding::Wrap(aCx, this, aGivenProto);
  49. }
  50. NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMSVGTranslatePoint, nsISVGPoint,
  51. mElement)
  52. NS_IMPL_ADDREF_INHERITED(DOMSVGTranslatePoint, nsISVGPoint)
  53. NS_IMPL_RELEASE_INHERITED(DOMSVGTranslatePoint, nsISVGPoint)
  54. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGTranslatePoint)
  55. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  56. // We have to qualify nsISVGPoint because NS_GET_IID looks for a class in the
  57. // global namespace
  58. NS_INTERFACE_MAP_ENTRY(mozilla::nsISVGPoint)
  59. NS_INTERFACE_MAP_ENTRY(nsISupports)
  60. NS_INTERFACE_MAP_END
  61. SVGSVGElement::~SVGSVGElement()
  62. {
  63. }
  64. DOMSVGPoint*
  65. DOMSVGTranslatePoint::Copy()
  66. {
  67. return new DOMSVGPoint(mPt.GetX(), mPt.GetY());
  68. }
  69. nsISupports*
  70. DOMSVGTranslatePoint::GetParentObject()
  71. {
  72. return static_cast<nsIDOMSVGElement*>(mElement);
  73. }
  74. void
  75. DOMSVGTranslatePoint::SetX(float aValue, ErrorResult& rv)
  76. {
  77. mElement->SetCurrentTranslate(aValue, mPt.GetY());
  78. }
  79. void
  80. DOMSVGTranslatePoint::SetY(float aValue, ErrorResult& rv)
  81. {
  82. mElement->SetCurrentTranslate(mPt.GetX(), aValue);
  83. }
  84. already_AddRefed<nsISVGPoint>
  85. DOMSVGTranslatePoint::MatrixTransform(SVGMatrix& matrix)
  86. {
  87. float a = matrix.A(), b = matrix.B(), c = matrix.C();
  88. float d = matrix.D(), e = matrix.E(), f = matrix.F();
  89. float x = mPt.GetX();
  90. float y = mPt.GetY();
  91. nsCOMPtr<nsISVGPoint> point = new DOMSVGPoint(a*x + c*y + e, b*x + d*y + f);
  92. return point.forget();
  93. }
  94. SVGView::SVGView()
  95. {
  96. mZoomAndPan.Init(SVGSVGElement::ZOOMANDPAN,
  97. SVG_ZOOMANDPAN_MAGNIFY);
  98. mViewBox.Init();
  99. mPreserveAspectRatio.Init();
  100. }
  101. nsSVGElement::LengthInfo SVGSVGElement::sLengthInfo[4] =
  102. {
  103. { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::X },
  104. { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, SVGContentUtils::Y },
  105. { &nsGkAtoms::width, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::X },
  106. { &nsGkAtoms::height, 100, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, SVGContentUtils::Y },
  107. };
  108. nsSVGEnumMapping SVGSVGElement::sZoomAndPanMap[] = {
  109. {&nsGkAtoms::disable, SVG_ZOOMANDPAN_DISABLE},
  110. {&nsGkAtoms::magnify, SVG_ZOOMANDPAN_MAGNIFY},
  111. {nullptr, 0}
  112. };
  113. nsSVGElement::EnumInfo SVGSVGElement::sEnumInfo[1] =
  114. {
  115. { &nsGkAtoms::zoomAndPan,
  116. sZoomAndPanMap,
  117. SVG_ZOOMANDPAN_MAGNIFY
  118. }
  119. };
  120. //----------------------------------------------------------------------
  121. // nsISupports methods
  122. NS_IMPL_CYCLE_COLLECTION_CLASS(SVGSVGElement)
  123. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGSVGElement,
  124. SVGSVGElementBase)
  125. if (tmp->mTimedDocumentRoot) {
  126. tmp->mTimedDocumentRoot->Unlink();
  127. }
  128. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  129. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGSVGElement,
  130. SVGSVGElementBase)
  131. if (tmp->mTimedDocumentRoot) {
  132. tmp->mTimedDocumentRoot->Traverse(&cb);
  133. }
  134. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  135. NS_IMPL_ADDREF_INHERITED(SVGSVGElement,SVGSVGElementBase)
  136. NS_IMPL_RELEASE_INHERITED(SVGSVGElement,SVGSVGElementBase)
  137. NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(SVGSVGElement)
  138. NS_INTERFACE_TABLE_INHERITED(SVGSVGElement, nsIDOMNode, nsIDOMElement,
  139. nsIDOMSVGElement)
  140. NS_INTERFACE_TABLE_TAIL_INHERITING(SVGSVGElementBase)
  141. //----------------------------------------------------------------------
  142. // Implementation
  143. SVGSVGElement::SVGSVGElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
  144. FromParser aFromParser)
  145. : SVGSVGElementBase(aNodeInfo),
  146. mViewportWidth(0),
  147. mViewportHeight(0),
  148. mCurrentTranslate(0.0f, 0.0f),
  149. mCurrentScale(1.0f),
  150. mPreviousTranslate(0.0f, 0.0f),
  151. mPreviousScale(1.0f),
  152. mStartAnimationOnBindToTree(aFromParser == NOT_FROM_PARSER ||
  153. aFromParser == FROM_PARSER_FRAGMENT ||
  154. aFromParser == FROM_PARSER_XSLT),
  155. mImageNeedsTransformInvalidation(false),
  156. mIsPaintingSVGImageElement(false),
  157. mHasChildrenOnlyTransform(false)
  158. {
  159. }
  160. //----------------------------------------------------------------------
  161. // nsIDOMNode methods
  162. // From NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSVGElement)
  163. nsresult
  164. SVGSVGElement::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
  165. {
  166. *aResult = nullptr;
  167. already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
  168. SVGSVGElement *it = new SVGSVGElement(ni, NOT_FROM_PARSER);
  169. nsCOMPtr<nsINode> kungFuDeathGrip = it;
  170. nsresult rv1 = it->Init();
  171. nsresult rv2 = const_cast<SVGSVGElement*>(this)->CopyInnerTo(it);
  172. if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
  173. kungFuDeathGrip.swap(*aResult);
  174. }
  175. return NS_FAILED(rv1) ? rv1 : rv2;
  176. }
  177. //----------------------------------------------------------------------
  178. // nsIDOMSVGSVGElement methods:
  179. already_AddRefed<SVGAnimatedLength>
  180. SVGSVGElement::X()
  181. {
  182. return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
  183. }
  184. already_AddRefed<SVGAnimatedLength>
  185. SVGSVGElement::Y()
  186. {
  187. return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
  188. }
  189. already_AddRefed<SVGAnimatedLength>
  190. SVGSVGElement::Width()
  191. {
  192. return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
  193. }
  194. already_AddRefed<SVGAnimatedLength>
  195. SVGSVGElement::Height()
  196. {
  197. return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
  198. }
  199. float
  200. SVGSVGElement::PixelUnitToMillimeterX()
  201. {
  202. return MM_PER_INCH_FLOAT / 96;
  203. }
  204. float
  205. SVGSVGElement::PixelUnitToMillimeterY()
  206. {
  207. return PixelUnitToMillimeterX();
  208. }
  209. float
  210. SVGSVGElement::ScreenPixelToMillimeterX()
  211. {
  212. return MM_PER_INCH_FLOAT / 96;
  213. }
  214. float
  215. SVGSVGElement::ScreenPixelToMillimeterY()
  216. {
  217. return ScreenPixelToMillimeterX();
  218. }
  219. bool
  220. SVGSVGElement::UseCurrentView()
  221. {
  222. return mSVGView || mCurrentViewID;
  223. }
  224. float
  225. SVGSVGElement::CurrentScale()
  226. {
  227. return mCurrentScale;
  228. }
  229. #define CURRENT_SCALE_MAX 16.0f
  230. #define CURRENT_SCALE_MIN 0.0625f
  231. void
  232. SVGSVGElement::SetCurrentScale(float aCurrentScale)
  233. {
  234. SetCurrentScaleTranslate(aCurrentScale,
  235. mCurrentTranslate.GetX(), mCurrentTranslate.GetY());
  236. }
  237. already_AddRefed<nsISVGPoint>
  238. SVGSVGElement::CurrentTranslate()
  239. {
  240. nsCOMPtr<nsISVGPoint> point = new DOMSVGTranslatePoint(&mCurrentTranslate, this);
  241. return point.forget();
  242. }
  243. uint32_t
  244. SVGSVGElement::SuspendRedraw(uint32_t max_wait_milliseconds)
  245. {
  246. // suspendRedraw is a no-op in Mozilla, so it doesn't matter what
  247. // we return
  248. return 1;
  249. }
  250. void
  251. SVGSVGElement::UnsuspendRedraw(uint32_t suspend_handle_id)
  252. {
  253. // no-op
  254. }
  255. void
  256. SVGSVGElement::UnsuspendRedrawAll()
  257. {
  258. // no-op
  259. }
  260. void
  261. SVGSVGElement::ForceRedraw()
  262. {
  263. // no-op
  264. }
  265. void
  266. SVGSVGElement::PauseAnimations()
  267. {
  268. if (mTimedDocumentRoot) {
  269. mTimedDocumentRoot->Pause(nsSMILTimeContainer::PAUSE_SCRIPT);
  270. }
  271. // else we're not the outermost <svg> or not bound to a tree, so silently fail
  272. }
  273. void
  274. SVGSVGElement::UnpauseAnimations()
  275. {
  276. if (mTimedDocumentRoot) {
  277. mTimedDocumentRoot->Resume(nsSMILTimeContainer::PAUSE_SCRIPT);
  278. }
  279. // else we're not the outermost <svg> or not bound to a tree, so silently fail
  280. }
  281. bool
  282. SVGSVGElement::AnimationsPaused()
  283. {
  284. nsSMILTimeContainer* root = GetTimedDocumentRoot();
  285. return root && root->IsPausedByType(nsSMILTimeContainer::PAUSE_SCRIPT);
  286. }
  287. float
  288. SVGSVGElement::GetCurrentTime()
  289. {
  290. nsSMILTimeContainer* root = GetTimedDocumentRoot();
  291. if (root) {
  292. double fCurrentTimeMs = double(root->GetCurrentTime());
  293. return (float)(fCurrentTimeMs / PR_MSEC_PER_SEC);
  294. } else {
  295. return 0.f;
  296. }
  297. }
  298. void
  299. SVGSVGElement::SetCurrentTime(float seconds)
  300. {
  301. if (mTimedDocumentRoot) {
  302. // Make sure the timegraph is up-to-date
  303. FlushAnimations();
  304. double fMilliseconds = double(seconds) * PR_MSEC_PER_SEC;
  305. // Round to nearest whole number before converting, to avoid precision
  306. // errors
  307. nsSMILTime lMilliseconds = int64_t(NS_round(fMilliseconds));
  308. mTimedDocumentRoot->SetCurrentTime(lMilliseconds);
  309. AnimationNeedsResample();
  310. // Trigger synchronous sample now, to:
  311. // - Make sure we get an up-to-date paint after this method
  312. // - re-enable event firing (it got disabled during seeking, and it
  313. // doesn't get re-enabled until the first sample after the seek -- so
  314. // let's make that happen now.)
  315. FlushAnimations();
  316. }
  317. // else we're not the outermost <svg> or not bound to a tree, so silently fail
  318. }
  319. void
  320. SVGSVGElement::DeselectAll()
  321. {
  322. nsIFrame* frame = GetPrimaryFrame();
  323. if (frame) {
  324. RefPtr<nsFrameSelection> frameSelection = frame->GetFrameSelection();
  325. frameSelection->ClearNormalSelection();
  326. }
  327. }
  328. already_AddRefed<DOMSVGNumber>
  329. SVGSVGElement::CreateSVGNumber()
  330. {
  331. RefPtr<DOMSVGNumber> number = new DOMSVGNumber(ToSupports(this));
  332. return number.forget();
  333. }
  334. already_AddRefed<DOMSVGLength>
  335. SVGSVGElement::CreateSVGLength()
  336. {
  337. nsCOMPtr<DOMSVGLength> length = new DOMSVGLength();
  338. return length.forget();
  339. }
  340. already_AddRefed<SVGAngle>
  341. SVGSVGElement::CreateSVGAngle()
  342. {
  343. nsSVGAngle* angle = new nsSVGAngle();
  344. angle->Init();
  345. RefPtr<SVGAngle> svgangle = new SVGAngle(angle, this, SVGAngle::CreatedValue);
  346. return svgangle.forget();
  347. }
  348. already_AddRefed<nsISVGPoint>
  349. SVGSVGElement::CreateSVGPoint()
  350. {
  351. nsCOMPtr<nsISVGPoint> point = new DOMSVGPoint(0, 0);
  352. return point.forget();
  353. }
  354. already_AddRefed<SVGMatrix>
  355. SVGSVGElement::CreateSVGMatrix()
  356. {
  357. RefPtr<SVGMatrix> matrix = new SVGMatrix();
  358. return matrix.forget();
  359. }
  360. already_AddRefed<SVGIRect>
  361. SVGSVGElement::CreateSVGRect()
  362. {
  363. return NS_NewSVGRect(this);
  364. }
  365. already_AddRefed<SVGTransform>
  366. SVGSVGElement::CreateSVGTransform()
  367. {
  368. RefPtr<SVGTransform> transform = new SVGTransform();
  369. return transform.forget();
  370. }
  371. already_AddRefed<SVGTransform>
  372. SVGSVGElement::CreateSVGTransformFromMatrix(SVGMatrix& matrix)
  373. {
  374. RefPtr<SVGTransform> transform = new SVGTransform(matrix.GetMatrix());
  375. return transform.forget();
  376. }
  377. //----------------------------------------------------------------------
  378. already_AddRefed<SVGAnimatedRect>
  379. SVGSVGElement::ViewBox()
  380. {
  381. return mViewBox.ToSVGAnimatedRect(this);
  382. }
  383. already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
  384. SVGSVGElement::PreserveAspectRatio()
  385. {
  386. return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
  387. }
  388. uint16_t
  389. SVGSVGElement::ZoomAndPan()
  390. {
  391. return mEnumAttributes[ZOOMANDPAN].GetAnimValue();
  392. }
  393. void
  394. SVGSVGElement::SetZoomAndPan(uint16_t aZoomAndPan, ErrorResult& rv)
  395. {
  396. if (aZoomAndPan == SVG_ZOOMANDPAN_DISABLE ||
  397. aZoomAndPan == SVG_ZOOMANDPAN_MAGNIFY) {
  398. mEnumAttributes[ZOOMANDPAN].SetBaseValue(aZoomAndPan, this);
  399. return;
  400. }
  401. rv.ThrowRangeError<MSG_INVALID_ZOOMANDPAN_VALUE_ERROR>();
  402. }
  403. //----------------------------------------------------------------------
  404. // helper methods for implementing SVGZoomEvent:
  405. void
  406. SVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y)
  407. {
  408. if (s == mCurrentScale &&
  409. x == mCurrentTranslate.GetX() && y == mCurrentTranslate.GetY()) {
  410. return;
  411. }
  412. // Prevent bizarre behaviour and maxing out of CPU and memory by clamping
  413. if (s < CURRENT_SCALE_MIN)
  414. s = CURRENT_SCALE_MIN;
  415. else if (s > CURRENT_SCALE_MAX)
  416. s = CURRENT_SCALE_MAX;
  417. // IMPORTANT: If either mCurrentTranslate *or* mCurrentScale is changed then
  418. // mPreviousTranslate_x, mPreviousTranslate_y *and* mPreviousScale must all
  419. // be updated otherwise SVGZoomEvents will end up with invalid data. I.e. an
  420. // SVGZoomEvent's properties previousScale and previousTranslate must contain
  421. // the state of currentScale and currentTranslate immediately before the
  422. // change that caused the event's dispatch, which is *not* necessarily the
  423. // same thing as the values of currentScale and currentTranslate prior to
  424. // their own last change.
  425. mPreviousScale = mCurrentScale;
  426. mPreviousTranslate = mCurrentTranslate;
  427. mCurrentScale = s;
  428. mCurrentTranslate = SVGPoint(x, y);
  429. // now dispatch the appropriate event if we are the root element
  430. nsIDocument* doc = GetUncomposedDoc();
  431. if (doc) {
  432. nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
  433. if (presShell && IsRoot()) {
  434. nsEventStatus status = nsEventStatus_eIgnore;
  435. if (mPreviousScale != mCurrentScale) {
  436. InternalSVGZoomEvent svgZoomEvent(true, eSVGZoom);
  437. presShell->HandleDOMEventWithTarget(this, &svgZoomEvent, &status);
  438. } else {
  439. WidgetEvent svgScrollEvent(true, eSVGScroll);
  440. presShell->HandleDOMEventWithTarget(this, &svgScrollEvent, &status);
  441. }
  442. InvalidateTransformNotifyFrame();
  443. }
  444. }
  445. }
  446. void
  447. SVGSVGElement::SetCurrentTranslate(float x, float y)
  448. {
  449. SetCurrentScaleTranslate(mCurrentScale, x, y);
  450. }
  451. nsSMILTimeContainer*
  452. SVGSVGElement::GetTimedDocumentRoot()
  453. {
  454. if (mTimedDocumentRoot) {
  455. return mTimedDocumentRoot;
  456. }
  457. // We must not be the outermost <svg> element, try to find it
  458. SVGSVGElement *outerSVGElement =
  459. SVGContentUtils::GetOuterSVGElement(this);
  460. if (outerSVGElement) {
  461. return outerSVGElement->GetTimedDocumentRoot();
  462. }
  463. // invalid structure
  464. return nullptr;
  465. }
  466. //----------------------------------------------------------------------
  467. // nsIContent methods
  468. NS_IMETHODIMP_(bool)
  469. SVGSVGElement::IsAttributeMapped(const nsIAtom* name) const
  470. {
  471. // We want to map the 'width' and 'height' attributes into style for
  472. // outer-<svg>, except when the attributes aren't set (since their default
  473. // values of '100%' can cause unexpected and undesirable behaviour for SVG
  474. // inline in HTML). We rely on nsSVGElement::UpdateContentStyleRule() to
  475. // prevent mapping of the default values into style (it only maps attributes
  476. // that are set). We also rely on a check in nsSVGElement::
  477. // UpdateContentStyleRule() to prevent us mapping the attributes when they're
  478. // given a <length> value that is not currently recognized by the SVG
  479. // specification.
  480. if (!IsInner() && (name == nsGkAtoms::width || name == nsGkAtoms::height)) {
  481. return true;
  482. }
  483. static const MappedAttributeEntry* const map[] = {
  484. sColorMap,
  485. sFEFloodMap,
  486. sFillStrokeMap,
  487. sFiltersMap,
  488. sFontSpecificationMap,
  489. sGradientStopMap,
  490. sGraphicsMap,
  491. sLightingEffectsMap,
  492. sMarkersMap,
  493. sTextContentElementsMap,
  494. sViewportsMap
  495. };
  496. return FindAttributeDependence(name, map) ||
  497. SVGSVGElementBase::IsAttributeMapped(name);
  498. }
  499. //----------------------------------------------------------------------
  500. // nsIContent methods:
  501. nsresult
  502. SVGSVGElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
  503. {
  504. if (aVisitor.mEvent->mMessage == eSVGLoad) {
  505. if (mTimedDocumentRoot) {
  506. mTimedDocumentRoot->Begin();
  507. // Set 'resample needed' flag, so that if any script calls a DOM method
  508. // that requires up-to-date animations before our first sample callback,
  509. // we'll force a synchronous sample.
  510. AnimationNeedsResample();
  511. }
  512. }
  513. return SVGSVGElementBase::GetEventTargetParent(aVisitor);
  514. }
  515. bool
  516. SVGSVGElement::IsEventAttributeName(nsIAtom* aName)
  517. {
  518. /* The events in EventNameType_SVGSVG are for events that are only
  519. applicable to outermost 'svg' elements. We don't check if we're an outer
  520. 'svg' element in case we're not inserted into the document yet, but since
  521. the target of the events in question will always be the outermost 'svg'
  522. element, this shouldn't cause any real problems.
  523. */
  524. return nsContentUtils::IsEventAttributeName(aName,
  525. (EventNameType_SVGGraphic | EventNameType_SVGSVG));
  526. }
  527. //----------------------------------------------------------------------
  528. // nsSVGElement overrides
  529. // Helper for GetViewBoxTransform on root <svg> node
  530. // * aLength: internal value for our <svg> width or height attribute.
  531. // * aViewportLength: length of the corresponding dimension of the viewport.
  532. // * aSelf: the outermost <svg> node itself.
  533. // NOTE: aSelf is not an ancestor viewport element, so it can't be used to
  534. // resolve percentage lengths. (It can only be used to resolve
  535. // 'em'/'ex'-valued units).
  536. inline float
  537. ComputeSynthesizedViewBoxDimension(const nsSVGLength2& aLength,
  538. float aViewportLength,
  539. const SVGSVGElement* aSelf)
  540. {
  541. if (aLength.IsPercentage()) {
  542. return aViewportLength * aLength.GetAnimValInSpecifiedUnits() / 100.0f;
  543. }
  544. return aLength.GetAnimValue(const_cast<SVGSVGElement*>(aSelf));
  545. }
  546. //----------------------------------------------------------------------
  547. // public helpers:
  548. gfx::Matrix
  549. SVGSVGElement::GetViewBoxTransform() const
  550. {
  551. float viewportWidth, viewportHeight;
  552. if (IsInner()) {
  553. SVGSVGElement *ctx = GetCtx();
  554. viewportWidth = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
  555. viewportHeight = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
  556. } else {
  557. viewportWidth = mViewportWidth;
  558. viewportHeight = mViewportHeight;
  559. }
  560. if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {
  561. return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
  562. }
  563. nsSVGViewBoxRect viewBox =
  564. GetViewBoxWithSynthesis(viewportWidth, viewportHeight);
  565. if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
  566. return gfx::Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
  567. }
  568. return SVGContentUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
  569. viewBox.x, viewBox.y,
  570. viewBox.width, viewBox.height,
  571. GetPreserveAspectRatioWithOverride());
  572. }
  573. void
  574. SVGSVGElement::UpdateHasChildrenOnlyTransform()
  575. {
  576. bool hasChildrenOnlyTransform =
  577. HasViewBoxOrSyntheticViewBox() ||
  578. (IsRoot() && (mCurrentTranslate != SVGPoint(0.0f, 0.0f) ||
  579. mCurrentScale != 1.0f));
  580. mHasChildrenOnlyTransform = hasChildrenOnlyTransform;
  581. }
  582. void
  583. SVGSVGElement::ChildrenOnlyTransformChanged(uint32_t aFlags)
  584. {
  585. // Avoid wasteful calls:
  586. MOZ_ASSERT(!(GetPrimaryFrame()->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
  587. "Non-display SVG frames don't maintain overflow rects");
  588. nsChangeHint changeHint;
  589. bool hadChildrenOnlyTransform = mHasChildrenOnlyTransform;
  590. UpdateHasChildrenOnlyTransform();
  591. if (hadChildrenOnlyTransform != mHasChildrenOnlyTransform) {
  592. // Reconstruct the frame tree to handle stacking context changes:
  593. // XXXjwatt don't do this for root-<svg> or even outer-<svg>?
  594. changeHint = nsChangeHint_ReconstructFrame;
  595. } else {
  596. // We just assume the old and new transforms are different.
  597. changeHint = nsChangeHint(nsChangeHint_UpdateOverflow |
  598. nsChangeHint_ChildrenOnlyTransform);
  599. }
  600. // If we're not reconstructing the frame tree, then we only call
  601. // PostRestyleEvent if we're not being called under reflow to avoid recursing
  602. // to death. See bug 767056 comments 10 and 12. Since our nsSVGOuterSVGFrame
  603. // is being reflowed we're going to invalidate and repaint its entire area
  604. // anyway (which will include our children).
  605. if ((changeHint & nsChangeHint_ReconstructFrame) ||
  606. !(aFlags & eDuringReflow)) {
  607. nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), changeHint);
  608. }
  609. }
  610. nsresult
  611. SVGSVGElement::BindToTree(nsIDocument* aDocument,
  612. nsIContent* aParent,
  613. nsIContent* aBindingParent,
  614. bool aCompileEventHandlers)
  615. {
  616. nsSMILAnimationController* smilController = nullptr;
  617. if (aDocument) {
  618. smilController = aDocument->GetAnimationController();
  619. if (smilController) {
  620. // SMIL is enabled in this document
  621. if (WillBeOutermostSVG(aParent, aBindingParent)) {
  622. // We'll be the outermost <svg> element. We'll need a time container.
  623. if (!mTimedDocumentRoot) {
  624. mTimedDocumentRoot = new nsSMILTimeContainer();
  625. }
  626. } else {
  627. // We're a child of some other <svg> element, so we don't need our own
  628. // time container. However, we need to make sure that we'll get a
  629. // kick-start if we get promoted to be outermost later on.
  630. mTimedDocumentRoot = nullptr;
  631. mStartAnimationOnBindToTree = true;
  632. }
  633. }
  634. }
  635. nsresult rv = SVGSVGElementBase::BindToTree(aDocument, aParent,
  636. aBindingParent,
  637. aCompileEventHandlers);
  638. NS_ENSURE_SUCCESS(rv,rv);
  639. nsIDocument* doc = GetComposedDoc();
  640. if (doc) {
  641. // Setup the style sheet during binding, not element construction,
  642. // because we could move the root SVG element from the document
  643. // that created it to another document.
  644. auto cache = nsLayoutStylesheetCache::For(doc->GetStyleBackendType());
  645. doc->EnsureOnDemandBuiltInUASheet(cache->SVGSheet());
  646. }
  647. if (mTimedDocumentRoot && smilController) {
  648. rv = mTimedDocumentRoot->SetParent(smilController);
  649. if (mStartAnimationOnBindToTree) {
  650. mTimedDocumentRoot->Begin();
  651. mStartAnimationOnBindToTree = false;
  652. }
  653. }
  654. return rv;
  655. }
  656. void
  657. SVGSVGElement::UnbindFromTree(bool aDeep, bool aNullParent)
  658. {
  659. if (mTimedDocumentRoot) {
  660. mTimedDocumentRoot->SetParent(nullptr);
  661. }
  662. SVGSVGElementBase::UnbindFromTree(aDeep, aNullParent);
  663. }
  664. //----------------------------------------------------------------------
  665. // implementation helpers
  666. bool
  667. SVGSVGElement::WillBeOutermostSVG(nsIContent* aParent,
  668. nsIContent* aBindingParent) const
  669. {
  670. nsIContent* parent = aBindingParent ? aBindingParent : aParent;
  671. while (parent && parent->IsSVGElement()) {
  672. if (parent->IsSVGElement(nsGkAtoms::foreignObject)) {
  673. // SVG in a foreignObject must have its own <svg> (nsSVGOuterSVGFrame).
  674. return false;
  675. }
  676. if (parent->IsSVGElement(nsGkAtoms::svg)) {
  677. return false;
  678. }
  679. parent = parent->GetParent();
  680. }
  681. return true;
  682. }
  683. void
  684. SVGSVGElement::InvalidateTransformNotifyFrame()
  685. {
  686. nsISVGSVGFrame* svgframe = do_QueryFrame(GetPrimaryFrame());
  687. // might fail this check if we've failed conditional processing
  688. if (svgframe) {
  689. svgframe->NotifyViewportOrTransformChanged(
  690. nsISVGChildFrame::TRANSFORM_CHANGED);
  691. }
  692. }
  693. bool
  694. SVGSVGElement::HasPreserveAspectRatio()
  695. {
  696. return HasAttr(kNameSpaceID_None, nsGkAtoms::preserveAspectRatio) ||
  697. mPreserveAspectRatio.IsAnimated();
  698. }
  699. SVGViewElement*
  700. SVGSVGElement::GetCurrentViewElement() const
  701. {
  702. if (mCurrentViewID) {
  703. //XXXsmaug It is unclear how this should work in case we're in Shadow DOM.
  704. nsIDocument* doc = GetUncomposedDoc();
  705. if (doc) {
  706. Element *element = doc->GetElementById(*mCurrentViewID);
  707. if (element && element->IsSVGElement(nsGkAtoms::view)) {
  708. return static_cast<SVGViewElement*>(element);
  709. }
  710. }
  711. }
  712. return nullptr;
  713. }
  714. nsSVGViewBoxRect
  715. SVGSVGElement::GetViewBoxWithSynthesis(
  716. float aViewportWidth, float aViewportHeight) const
  717. {
  718. // The logic here should match HasViewBoxRect().
  719. SVGViewElement* viewElement = GetCurrentViewElement();
  720. if (viewElement && viewElement->mViewBox.HasRect()) {
  721. return viewElement->mViewBox.GetAnimValue();
  722. }
  723. if (mSVGView && mSVGView->mViewBox.HasRect()) {
  724. return mSVGView->mViewBox.GetAnimValue();
  725. }
  726. if (mViewBox.HasRect()) {
  727. return mViewBox.GetAnimValue();
  728. }
  729. if (ShouldSynthesizeViewBox()) {
  730. // Special case -- fake a viewBox, using height & width attrs.
  731. // (Use |this| as context, since if we get here, we're outermost <svg>.)
  732. return nsSVGViewBoxRect(0, 0,
  733. ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
  734. mViewportWidth, this),
  735. ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
  736. mViewportHeight, this));
  737. }
  738. // No viewBox attribute, so we shouldn't auto-scale. This is equivalent
  739. // to having a viewBox that exactly matches our viewport size.
  740. return nsSVGViewBoxRect(0, 0, aViewportWidth, aViewportHeight);
  741. }
  742. SVGPreserveAspectRatio
  743. SVGSVGElement::GetPreserveAspectRatioWithOverride() const
  744. {
  745. nsIDocument* doc = GetUncomposedDoc();
  746. if (doc && doc->IsBeingUsedAsImage()) {
  747. const SVGPreserveAspectRatio *pAROverridePtr = GetPreserveAspectRatioProperty();
  748. if (pAROverridePtr) {
  749. return *pAROverridePtr;
  750. }
  751. }
  752. SVGViewElement* viewElement = GetCurrentViewElement();
  753. // This check is equivalent to "!HasViewBoxRect() && ShouldSynthesizeViewBox()".
  754. // We're just holding onto the viewElement that HasViewBoxRect() would look up,
  755. // so that we don't have to look it up again later.
  756. if (!((viewElement && viewElement->mViewBox.HasRect()) ||
  757. (mSVGView && mSVGView->mViewBox.HasRect()) ||
  758. mViewBox.HasRect()) &&
  759. ShouldSynthesizeViewBox()) {
  760. // If we're synthesizing a viewBox, use preserveAspectRatio="none";
  761. return SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE, SVG_MEETORSLICE_SLICE);
  762. }
  763. if (viewElement && viewElement->mPreserveAspectRatio.IsExplicitlySet()) {
  764. return viewElement->mPreserveAspectRatio.GetAnimValue();
  765. }
  766. if (mSVGView && mSVGView->mPreserveAspectRatio.IsExplicitlySet()) {
  767. return mSVGView->mPreserveAspectRatio.GetAnimValue();
  768. }
  769. return mPreserveAspectRatio.GetAnimValue();
  770. }
  771. //----------------------------------------------------------------------
  772. // SVGSVGElement
  773. float
  774. SVGSVGElement::GetLength(uint8_t aCtxType)
  775. {
  776. float h, w;
  777. SVGViewElement* viewElement = GetCurrentViewElement();
  778. const nsSVGViewBoxRect* viewbox = nullptr;
  779. // The logic here should match HasViewBoxRect().
  780. if (viewElement && viewElement->mViewBox.HasRect()) {
  781. viewbox = &viewElement->mViewBox.GetAnimValue();
  782. } else if (mSVGView && mSVGView->mViewBox.HasRect()) {
  783. viewbox = &mSVGView->mViewBox.GetAnimValue();
  784. } else if (mViewBox.HasRect()) {
  785. viewbox = &mViewBox.GetAnimValue();
  786. }
  787. if (viewbox) {
  788. w = viewbox->width;
  789. h = viewbox->height;
  790. } else if (IsInner()) {
  791. SVGSVGElement *ctx = GetCtx();
  792. w = mLengthAttributes[ATTR_WIDTH].GetAnimValue(ctx);
  793. h = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(ctx);
  794. } else if (ShouldSynthesizeViewBox()) {
  795. w = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_WIDTH],
  796. mViewportWidth, this);
  797. h = ComputeSynthesizedViewBoxDimension(mLengthAttributes[ATTR_HEIGHT],
  798. mViewportHeight, this);
  799. } else {
  800. w = mViewportWidth;
  801. h = mViewportHeight;
  802. }
  803. w = std::max(w, 0.0f);
  804. h = std::max(h, 0.0f);
  805. switch (aCtxType) {
  806. case SVGContentUtils::X:
  807. return w;
  808. case SVGContentUtils::Y:
  809. return h;
  810. case SVGContentUtils::XY:
  811. return float(SVGContentUtils::ComputeNormalizedHypotenuse(w, h));
  812. }
  813. return 0;
  814. }
  815. //----------------------------------------------------------------------
  816. // nsSVGElement methods
  817. /* virtual */ gfxMatrix
  818. SVGSVGElement::PrependLocalTransformsTo(
  819. const gfxMatrix &aMatrix, SVGTransformTypes aWhich) const
  820. {
  821. // 'transform' attribute (or an override from a fragment identifier):
  822. gfxMatrix fromUserSpace =
  823. SVGContentUtils::PrependLocalTransformsTo(
  824. aMatrix, aWhich, mAnimateMotionTransform,
  825. mSVGView && mSVGView->mTransforms ? mSVGView->mTransforms : mTransforms);
  826. if (aWhich == eUserSpaceToParent) {
  827. return fromUserSpace;
  828. }
  829. if (IsInner()) {
  830. float x, y;
  831. const_cast<SVGSVGElement*>(this)->GetAnimatedLengthValues(&x, &y, nullptr);
  832. if (aWhich == eAllTransforms) {
  833. // the common case
  834. return ThebesMatrix(GetViewBoxTransform()) * gfxMatrix::Translation(x, y) * fromUserSpace;
  835. }
  836. MOZ_ASSERT(aWhich == eChildToUserSpace, "Unknown TransformTypes");
  837. return ThebesMatrix(GetViewBoxTransform()) * gfxMatrix::Translation(x, y) * aMatrix;
  838. }
  839. if (IsRoot()) {
  840. gfxMatrix zoomPanTM;
  841. zoomPanTM.Translate(gfxPoint(mCurrentTranslate.GetX(), mCurrentTranslate.GetY()));
  842. zoomPanTM.Scale(mCurrentScale, mCurrentScale);
  843. return ThebesMatrix(GetViewBoxTransform()) * zoomPanTM * fromUserSpace;
  844. }
  845. // outer-<svg>, but inline in some other content:
  846. return ThebesMatrix(GetViewBoxTransform()) * fromUserSpace;
  847. }
  848. nsSVGAnimatedTransformList*
  849. SVGSVGElement::GetAnimatedTransformList(uint32_t aFlags)
  850. {
  851. if (!(aFlags & DO_ALLOCATE) && mSVGView && mSVGView->mTransforms) {
  852. return mSVGView->mTransforms;
  853. }
  854. return SVGSVGElementBase::GetAnimatedTransformList(aFlags);
  855. }
  856. /* virtual */ bool
  857. SVGSVGElement::HasValidDimensions() const
  858. {
  859. return !IsInner() ||
  860. ((!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
  861. mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
  862. (!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
  863. mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0));
  864. }
  865. nsSVGElement::LengthAttributesInfo
  866. SVGSVGElement::GetLengthInfo()
  867. {
  868. return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
  869. ArrayLength(sLengthInfo));
  870. }
  871. nsSVGElement::EnumAttributesInfo
  872. SVGSVGElement::GetEnumInfo()
  873. {
  874. return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
  875. ArrayLength(sEnumInfo));
  876. }
  877. nsSVGViewBox*
  878. SVGSVGElement::GetViewBox()
  879. {
  880. return &mViewBox;
  881. }
  882. SVGAnimatedPreserveAspectRatio *
  883. SVGSVGElement::GetPreserveAspectRatio()
  884. {
  885. return &mPreserveAspectRatio;
  886. }
  887. bool
  888. SVGSVGElement::HasViewBoxRect() const
  889. {
  890. SVGViewElement* viewElement = GetCurrentViewElement();
  891. if ((viewElement && viewElement->mViewBox.HasRect()) ||
  892. (mSVGView && mSVGView->mViewBox.HasRect())) {
  893. return true;
  894. }
  895. return mViewBox.HasRect();
  896. }
  897. bool
  898. SVGSVGElement::ShouldSynthesizeViewBox() const
  899. {
  900. MOZ_ASSERT(!HasViewBoxRect(),
  901. "Should only be called if we lack a viewBox");
  902. nsIDocument* doc = GetUncomposedDoc();
  903. return doc &&
  904. doc->IsBeingUsedAsImage() &&
  905. !mIsPaintingSVGImageElement &&
  906. !GetParent();
  907. }
  908. bool
  909. SVGSVGElement::SetPreserveAspectRatioProperty(const SVGPreserveAspectRatio& aPAR)
  910. {
  911. SVGPreserveAspectRatio* pAROverridePtr = new SVGPreserveAspectRatio(aPAR);
  912. nsresult rv = SetProperty(nsGkAtoms::overridePreserveAspectRatio,
  913. pAROverridePtr,
  914. nsINode::DeleteProperty<SVGPreserveAspectRatio>,
  915. true);
  916. MOZ_ASSERT(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
  917. "Setting override value when it's already set...?");
  918. if (MOZ_UNLIKELY(NS_FAILED(rv))) {
  919. // property-insertion failed (e.g. OOM in property-table code)
  920. delete pAROverridePtr;
  921. return false;
  922. }
  923. return true;
  924. }
  925. const SVGPreserveAspectRatio*
  926. SVGSVGElement::GetPreserveAspectRatioProperty() const
  927. {
  928. void* valPtr = GetProperty(nsGkAtoms::overridePreserveAspectRatio);
  929. if (valPtr) {
  930. return static_cast<SVGPreserveAspectRatio*>(valPtr);
  931. }
  932. return nullptr;
  933. }
  934. bool
  935. SVGSVGElement::ClearPreserveAspectRatioProperty()
  936. {
  937. void* valPtr = UnsetProperty(nsGkAtoms::overridePreserveAspectRatio);
  938. delete static_cast<SVGPreserveAspectRatio*>(valPtr);
  939. return valPtr;
  940. }
  941. void
  942. SVGSVGElement::SetIsPaintingForSVGImageElement(bool aIsPaintingSVGImageElement)
  943. {
  944. mIsPaintingSVGImageElement = aIsPaintingSVGImageElement;
  945. }
  946. void
  947. SVGSVGElement::
  948. SetImageOverridePreserveAspectRatio(const SVGPreserveAspectRatio& aPAR)
  949. {
  950. #ifdef DEBUG
  951. MOZ_ASSERT(OwnerDoc()->IsBeingUsedAsImage(),
  952. "should only override preserveAspectRatio in images");
  953. #endif
  954. bool hasViewBoxRect = HasViewBoxRect();
  955. if (!hasViewBoxRect && ShouldSynthesizeViewBox()) {
  956. // My non-<svg:image> clients will have been painting me with a synthesized
  957. // viewBox, but my <svg:image> client that's about to paint me now does NOT
  958. // want that. Need to tell ourselves to flush our transform.
  959. mImageNeedsTransformInvalidation = true;
  960. }
  961. if (!hasViewBoxRect) {
  962. return; // preserveAspectRatio irrelevant (only matters if we have viewBox)
  963. }
  964. if (SetPreserveAspectRatioProperty(aPAR)) {
  965. mImageNeedsTransformInvalidation = true;
  966. }
  967. }
  968. void
  969. SVGSVGElement::ClearImageOverridePreserveAspectRatio()
  970. {
  971. #ifdef DEBUG
  972. MOZ_ASSERT(OwnerDoc()->IsBeingUsedAsImage(),
  973. "should only override image preserveAspectRatio in images");
  974. #endif
  975. if (!HasViewBoxRect() && ShouldSynthesizeViewBox()) {
  976. // My non-<svg:image> clients will want to paint me with a synthesized
  977. // viewBox, but my <svg:image> client that just painted me did NOT
  978. // use that. Need to tell ourselves to flush our transform.
  979. mImageNeedsTransformInvalidation = true;
  980. }
  981. if (ClearPreserveAspectRatioProperty()) {
  982. mImageNeedsTransformInvalidation = true;
  983. }
  984. }
  985. void
  986. SVGSVGElement::FlushImageTransformInvalidation()
  987. {
  988. MOZ_ASSERT(!GetParent(), "Should only be called on root node");
  989. MOZ_ASSERT(OwnerDoc()->IsBeingUsedAsImage(),
  990. "Should only be called on image documents");
  991. if (mImageNeedsTransformInvalidation) {
  992. InvalidateTransformNotifyFrame();
  993. mImageNeedsTransformInvalidation = false;
  994. }
  995. }
  996. int32_t
  997. SVGSVGElement::GetIntrinsicWidth()
  998. {
  999. if (mLengthAttributes[ATTR_WIDTH].IsPercentage()) {
  1000. return -1;
  1001. }
  1002. // Passing |this| as a SVGSVGElement* invokes the variant of GetAnimValue
  1003. // that uses the passed argument as the context, but that's fine since we
  1004. // know the length isn't a percentage so the context won't be used (and we
  1005. // need to pass the element to be able to resolve em/ex units).
  1006. float width = mLengthAttributes[ATTR_WIDTH].GetAnimValue(this);
  1007. return nsSVGUtils::ClampToInt(width);
  1008. }
  1009. int32_t
  1010. SVGSVGElement::GetIntrinsicHeight()
  1011. {
  1012. if (mLengthAttributes[ATTR_HEIGHT].IsPercentage()) {
  1013. return -1;
  1014. }
  1015. // Passing |this| as a SVGSVGElement* invokes the variant of GetAnimValue
  1016. // that uses the passed argument as the context, but that's fine since we
  1017. // know the length isn't a percentage so the context won't be used (and we
  1018. // need to pass the element to be able to resolve em/ex units).
  1019. float height = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(this);
  1020. return nsSVGUtils::ClampToInt(height);
  1021. }
  1022. } // namespace dom
  1023. } // namespace mozilla