nsSVGOuterSVGFrame.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. /* -*- Mode: C++; tab-width: 2; 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. // Main header first:
  6. #include "nsSVGOuterSVGFrame.h"
  7. // Keep others in (case-insensitive) order:
  8. #include "nsDisplayList.h"
  9. #include "nsIDocument.h"
  10. #include "nsIDOMHTMLIFrameElement.h"
  11. #include "nsIInterfaceRequestorUtils.h"
  12. #include "nsIObjectLoadingContent.h"
  13. #include "nsRenderingContext.h"
  14. #include "nsSVGIntegrationUtils.h"
  15. #include "nsSVGForeignObjectFrame.h"
  16. #include "mozilla/dom/SVGSVGElement.h"
  17. #include "mozilla/dom/SVGViewElement.h"
  18. #include "nsSubDocumentFrame.h"
  19. #include "gfxMatrix.h"
  20. using namespace mozilla;
  21. using namespace mozilla::dom;
  22. using namespace mozilla::gfx;
  23. using namespace mozilla::image;
  24. //----------------------------------------------------------------------
  25. // Implementation helpers
  26. void
  27. nsSVGOuterSVGFrame::RegisterForeignObject(nsSVGForeignObjectFrame* aFrame)
  28. {
  29. NS_ASSERTION(aFrame, "Who on earth is calling us?!");
  30. if (!mForeignObjectHash) {
  31. mForeignObjectHash = new nsTHashtable<nsPtrHashKey<nsSVGForeignObjectFrame> >();
  32. }
  33. NS_ASSERTION(!mForeignObjectHash->GetEntry(aFrame),
  34. "nsSVGForeignObjectFrame already registered!");
  35. mForeignObjectHash->PutEntry(aFrame);
  36. NS_ASSERTION(mForeignObjectHash->GetEntry(aFrame),
  37. "Failed to register nsSVGForeignObjectFrame!");
  38. }
  39. void
  40. nsSVGOuterSVGFrame::UnregisterForeignObject(nsSVGForeignObjectFrame* aFrame)
  41. {
  42. NS_ASSERTION(aFrame, "Who on earth is calling us?!");
  43. NS_ASSERTION(mForeignObjectHash && mForeignObjectHash->GetEntry(aFrame),
  44. "nsSVGForeignObjectFrame not in registry!");
  45. return mForeignObjectHash->RemoveEntry(aFrame);
  46. }
  47. //----------------------------------------------------------------------
  48. // Implementation
  49. nsContainerFrame*
  50. NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  51. {
  52. return new (aPresShell) nsSVGOuterSVGFrame(aContext);
  53. }
  54. NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGFrame)
  55. nsSVGOuterSVGFrame::nsSVGOuterSVGFrame(nsStyleContext* aContext)
  56. : nsSVGDisplayContainerFrame(aContext)
  57. , mFullZoom(aContext->PresContext()->GetFullZoom())
  58. , mViewportInitialized(false)
  59. , mIsRootContent(false)
  60. {
  61. // Outer-<svg> has CSS layout, so remove this bit:
  62. RemoveStateBits(NS_FRAME_SVG_LAYOUT);
  63. }
  64. // helper
  65. static inline bool
  66. DependsOnIntrinsicSize(const nsIFrame* aEmbeddingFrame)
  67. {
  68. const nsStylePosition *pos = aEmbeddingFrame->StylePosition();
  69. const nsStyleCoord &width = pos->mWidth;
  70. const nsStyleCoord &height = pos->mHeight;
  71. // XXX it would be nice to know if the size of aEmbeddingFrame's containing
  72. // block depends on aEmbeddingFrame, then we'd know if we can return false
  73. // for eStyleUnit_Percent too.
  74. return !width.ConvertsToLength() ||
  75. !height.ConvertsToLength();
  76. }
  77. void
  78. nsSVGOuterSVGFrame::Init(nsIContent* aContent,
  79. nsContainerFrame* aParent,
  80. nsIFrame* aPrevInFlow)
  81. {
  82. NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::svg),
  83. "Content is not an SVG 'svg' element!");
  84. AddStateBits(NS_STATE_IS_OUTER_SVG |
  85. NS_FRAME_FONT_INFLATION_CONTAINER |
  86. NS_FRAME_FONT_INFLATION_FLOW_ROOT);
  87. // Check for conditional processing attributes here rather than in
  88. // nsCSSFrameConstructor::FindSVGData because we want to avoid
  89. // simply giving failing outer <svg> elements an nsSVGContainerFrame.
  90. // We don't create other SVG frames if PassesConditionalProcessingTests
  91. // returns false, but since we do create nsSVGOuterSVGFrame frames we
  92. // prevent them from painting by [ab]use NS_FRAME_IS_NONDISPLAY. The
  93. // frame will be recreated via an nsChangeHint_ReconstructFrame restyle if
  94. // the value returned by PassesConditionalProcessingTests changes.
  95. SVGSVGElement *svg = static_cast<SVGSVGElement*>(aContent);
  96. if (!svg->PassesConditionalProcessingTests()) {
  97. AddStateBits(NS_FRAME_IS_NONDISPLAY);
  98. }
  99. nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
  100. nsIDocument* doc = mContent->GetUncomposedDoc();
  101. if (doc) {
  102. // we only care about our content's zoom and pan values if it's the root element
  103. if (doc->GetRootElement() == mContent) {
  104. mIsRootContent = true;
  105. nsIFrame* embeddingFrame;
  106. if (IsRootOfReplacedElementSubDoc(&embeddingFrame) && embeddingFrame) {
  107. if (MOZ_UNLIKELY(!embeddingFrame->HasAllStateBits(NS_FRAME_IS_DIRTY)) &&
  108. DependsOnIntrinsicSize(embeddingFrame)) {
  109. // Looks like this document is loading after the embedding element
  110. // has had its first reflow, and that its size depends on our
  111. // intrinsic size. We need it to resize itself to use our (now
  112. // available) intrinsic size:
  113. embeddingFrame->PresContext()->PresShell()->
  114. FrameNeedsReflow(embeddingFrame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  115. }
  116. }
  117. }
  118. }
  119. }
  120. //----------------------------------------------------------------------
  121. // nsQueryFrame methods
  122. NS_QUERYFRAME_HEAD(nsSVGOuterSVGFrame)
  123. NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
  124. NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
  125. //----------------------------------------------------------------------
  126. // nsIFrame methods
  127. //----------------------------------------------------------------------
  128. // reflowing
  129. /* virtual */ nscoord
  130. nsSVGOuterSVGFrame::GetMinISize(nsRenderingContext *aRenderingContext)
  131. {
  132. nscoord result;
  133. DISPLAY_MIN_WIDTH(this, result);
  134. result = nscoord(0);
  135. return result;
  136. }
  137. /* virtual */ nscoord
  138. nsSVGOuterSVGFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
  139. {
  140. nscoord result;
  141. DISPLAY_PREF_WIDTH(this, result);
  142. SVGSVGElement *svg = static_cast<SVGSVGElement*>(mContent);
  143. WritingMode wm = GetWritingMode();
  144. const nsSVGLength2& isize = wm.IsVertical()
  145. ? svg->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT]
  146. : svg->mLengthAttributes[SVGSVGElement::ATTR_WIDTH];
  147. if (isize.IsPercentage()) {
  148. // It looks like our containing block's isize may depend on our isize. In
  149. // that case our behavior is undefined according to CSS 2.1 section 10.3.2.
  150. // As a last resort, we'll fall back to returning zero.
  151. result = nscoord(0);
  152. // Returning zero may be unhelpful, however, as it leads to unexpected
  153. // disappearance of %-sized SVGs in orthogonal contexts, where our
  154. // containing block wants to shrink-wrap. So let's look for an ancestor
  155. // with non-zero size in this dimension, and use that as a (somewhat
  156. // arbitrary) result instead.
  157. nsIFrame *parent = GetParent();
  158. while (parent) {
  159. nscoord parentISize = parent->GetLogicalSize(wm).ISize(wm);
  160. if (parentISize > 0 && parentISize != NS_UNCONSTRAINEDSIZE) {
  161. result = parentISize;
  162. break;
  163. }
  164. parent = parent->GetParent();
  165. }
  166. } else {
  167. result = nsPresContext::CSSPixelsToAppUnits(isize.GetAnimValue(svg));
  168. if (result < 0) {
  169. result = nscoord(0);
  170. }
  171. }
  172. return result;
  173. }
  174. /* virtual */ IntrinsicSize
  175. nsSVGOuterSVGFrame::GetIntrinsicSize()
  176. {
  177. // XXXjwatt Note that here we want to return the CSS width/height if they're
  178. // specified and we're embedded inside an nsIObjectLoadingContent.
  179. IntrinsicSize intrinsicSize;
  180. SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
  181. nsSVGLength2 &width = content->mLengthAttributes[SVGSVGElement::ATTR_WIDTH];
  182. nsSVGLength2 &height = content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
  183. if (!width.IsPercentage()) {
  184. nscoord val = nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(content));
  185. if (val < 0) val = 0;
  186. intrinsicSize.width.SetCoordValue(val);
  187. }
  188. if (!height.IsPercentage()) {
  189. nscoord val = nsPresContext::CSSPixelsToAppUnits(height.GetAnimValue(content));
  190. if (val < 0) val = 0;
  191. intrinsicSize.height.SetCoordValue(val);
  192. }
  193. return intrinsicSize;
  194. }
  195. /* virtual */ AspectRatio
  196. nsSVGOuterSVGFrame::GetIntrinsicRatio()
  197. {
  198. // When 'contain: size' is implemented, make sure to check for it.
  199. /*
  200. if (this->GetContent->GetParent() && this->StyleDisplay()->IsContainSize()) {
  201. return AspectRatio();
  202. }
  203. */
  204. // We only have an intrinsic size/ratio if our width and height attributes
  205. // are both specified and set to non-percentage values, or we have a viewBox
  206. // rect: http://www.w3.org/TR/SVGMobile12/coords.html#IntrinsicSizing
  207. // Unfortunately we have to return the ratio as two nscoords whereas what
  208. // we have are two floats. Using app units allows for some floating point
  209. // values to work but really small or large numbers will fail.
  210. SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
  211. nsSVGLength2 &width = content->mLengthAttributes[SVGSVGElement::ATTR_WIDTH];
  212. nsSVGLength2 &height = content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
  213. if (!width.IsPercentage() && !height.IsPercentage()) {
  214. return AspectRatio::FromSize(width.GetAnimValue(content),
  215. height.GetAnimValue(content));
  216. }
  217. SVGViewElement* viewElement = content->GetCurrentViewElement();
  218. const nsSVGViewBoxRect* viewbox = nullptr;
  219. // The logic here should match HasViewBox().
  220. if (viewElement && viewElement->mViewBox.HasRect()) {
  221. viewbox = &viewElement->mViewBox.GetAnimValue();
  222. } else if (content->mViewBox.HasRect()) {
  223. viewbox = &content->mViewBox.GetAnimValue();
  224. }
  225. if (viewbox) {
  226. return AspectRatio::FromSize(viewbox->width, viewbox->height);
  227. }
  228. return nsSVGDisplayContainerFrame::GetIntrinsicRatio();
  229. }
  230. /* virtual */
  231. LogicalSize
  232. nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext,
  233. WritingMode aWM,
  234. const LogicalSize& aCBSize,
  235. nscoord aAvailableISize,
  236. const LogicalSize& aMargin,
  237. const LogicalSize& aBorder,
  238. const LogicalSize& aPadding,
  239. ComputeSizeFlags aFlags)
  240. {
  241. if (IsRootOfImage() || IsRootOfReplacedElementSubDoc()) {
  242. // The embedding element has sized itself using the CSS replaced element
  243. // sizing rules, using our intrinsic dimensions as necessary. The SVG spec
  244. // says that the width and height of embedded SVG is overridden by the
  245. // width and height of the embedding element, so we just need to size to
  246. // the viewport that the embedding element has established for us.
  247. return aCBSize;
  248. }
  249. LogicalSize cbSize = aCBSize;
  250. IntrinsicSize intrinsicSize = GetIntrinsicSize();
  251. if (!mContent->GetParent()) {
  252. // We're the root of the outermost browsing context, so we need to scale
  253. // cbSize by the full-zoom so that SVGs with percentage width/height zoom:
  254. NS_ASSERTION(aCBSize.ISize(aWM) != NS_AUTOHEIGHT &&
  255. aCBSize.BSize(aWM) != NS_AUTOHEIGHT,
  256. "root should not have auto-width/height containing block");
  257. cbSize.ISize(aWM) *= PresContext()->GetFullZoom();
  258. cbSize.BSize(aWM) *= PresContext()->GetFullZoom();
  259. // We also need to honour the width and height attributes' default values
  260. // of 100% when we're the root of a browsing context. (GetIntrinsicSize()
  261. // doesn't report these since there's no such thing as a percentage
  262. // intrinsic size. Also note that explicit percentage values are mapped
  263. // into style, so the following isn't for them.)
  264. SVGSVGElement* content = static_cast<SVGSVGElement*>(mContent);
  265. nsSVGLength2 &width =
  266. content->mLengthAttributes[SVGSVGElement::ATTR_WIDTH];
  267. if (width.IsPercentage()) {
  268. MOZ_ASSERT(intrinsicSize.width.GetUnit() == eStyleUnit_None,
  269. "GetIntrinsicSize should have reported no intrinsic width");
  270. float val = width.GetAnimValInSpecifiedUnits() / 100.0f;
  271. if (val < 0.0f) val = 0.0f;
  272. intrinsicSize.width.SetCoordValue(val * cbSize.Width(aWM));
  273. }
  274. nsSVGLength2 &height =
  275. content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
  276. NS_ASSERTION(aCBSize.BSize(aWM) != NS_AUTOHEIGHT,
  277. "root should not have auto-height containing block");
  278. if (height.IsPercentage()) {
  279. MOZ_ASSERT(intrinsicSize.height.GetUnit() == eStyleUnit_None,
  280. "GetIntrinsicSize should have reported no intrinsic height");
  281. float val = height.GetAnimValInSpecifiedUnits() / 100.0f;
  282. if (val < 0.0f) val = 0.0f;
  283. intrinsicSize.height.SetCoordValue(val * cbSize.Height(aWM));
  284. }
  285. MOZ_ASSERT(intrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
  286. intrinsicSize.width.GetUnit() == eStyleUnit_Coord,
  287. "We should have just handled the only situation where"
  288. "we lack an intrinsic height or width.");
  289. }
  290. return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
  291. intrinsicSize, GetIntrinsicRatio(),
  292. cbSize, aMargin, aBorder, aPadding,
  293. aFlags);
  294. }
  295. void
  296. nsSVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
  297. ReflowOutput& aDesiredSize,
  298. const ReflowInput& aReflowInput,
  299. nsReflowStatus& aStatus)
  300. {
  301. MarkInReflow();
  302. DO_GLOBAL_REFLOW_COUNT("nsSVGOuterSVGFrame");
  303. DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
  304. NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
  305. ("enter nsSVGOuterSVGFrame::Reflow: availSize=%d,%d",
  306. aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
  307. NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
  308. aStatus = NS_FRAME_COMPLETE;
  309. aDesiredSize.Width() = aReflowInput.ComputedWidth() +
  310. aReflowInput.ComputedPhysicalBorderPadding().LeftRight();
  311. aDesiredSize.Height() = aReflowInput.ComputedHeight() +
  312. aReflowInput.ComputedPhysicalBorderPadding().TopBottom();
  313. NS_ASSERTION(!GetPrevInFlow(), "SVG can't currently be broken across pages.");
  314. SVGSVGElement *svgElem = static_cast<SVGSVGElement*>(mContent);
  315. nsSVGOuterSVGAnonChildFrame *anonKid =
  316. static_cast<nsSVGOuterSVGAnonChildFrame*>(PrincipalChildList().FirstChild());
  317. if (mState & NS_FRAME_FIRST_REFLOW) {
  318. // Initialize
  319. svgElem->UpdateHasChildrenOnlyTransform();
  320. }
  321. // If our SVG viewport has changed, update our content and notify.
  322. // http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
  323. svgFloatSize newViewportSize(
  324. nsPresContext::AppUnitsToFloatCSSPixels(aReflowInput.ComputedWidth()),
  325. nsPresContext::AppUnitsToFloatCSSPixels(aReflowInput.ComputedHeight()));
  326. svgFloatSize oldViewportSize = svgElem->GetViewportSize();
  327. uint32_t changeBits = 0;
  328. if (newViewportSize != oldViewportSize) {
  329. // When our viewport size changes, we may need to update the overflow rects
  330. // of our child frames. This is the case if:
  331. //
  332. // * We have a real/synthetic viewBox (a children-only transform), since
  333. // the viewBox transform will change as the viewport dimensions change.
  334. //
  335. // * We do not have a real/synthetic viewBox, but the last time we
  336. // reflowed (or the last time UpdateOverflow() was called) we did.
  337. //
  338. // We only handle the former case here, in which case we mark all our child
  339. // frames as dirty so that we reflow them below and update their overflow
  340. // rects.
  341. //
  342. // In the latter case, updating of overflow rects is handled for removal of
  343. // real viewBox (the viewBox attribute) in AttributeChanged. Synthetic
  344. // viewBox "removal" (e.g. a document references the same SVG via both an
  345. // <svg:image> and then as a CSS background image (a synthetic viewBox is
  346. // used when painting the former, but not when painting the latter)) is
  347. // handled in SVGSVGElement::FlushImageTransformInvalidation.
  348. //
  349. if (svgElem->HasViewBoxOrSyntheticViewBox()) {
  350. nsIFrame* anonChild = PrincipalChildList().FirstChild();
  351. anonChild->AddStateBits(NS_FRAME_IS_DIRTY);
  352. for (nsIFrame* child : anonChild->PrincipalChildList()) {
  353. child->AddStateBits(NS_FRAME_IS_DIRTY);
  354. }
  355. }
  356. changeBits |= COORD_CONTEXT_CHANGED;
  357. svgElem->SetViewportSize(newViewportSize);
  358. }
  359. if (mFullZoom != PresContext()->GetFullZoom()) {
  360. changeBits |= FULL_ZOOM_CHANGED;
  361. mFullZoom = PresContext()->GetFullZoom();
  362. }
  363. if (changeBits) {
  364. NotifyViewportOrTransformChanged(changeBits);
  365. }
  366. mViewportInitialized = true;
  367. // Now that we've marked the necessary children as dirty, call
  368. // ReflowSVG() or ReflowSVGNonDisplayText() on them, depending
  369. // on whether we are non-display.
  370. mCallingReflowSVG = true;
  371. if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
  372. ReflowSVGNonDisplayText(this);
  373. } else {
  374. // Update the mRects and visual overflow rects of all our descendants,
  375. // including our anonymous wrapper kid:
  376. anonKid->AddStateBits(mState & NS_FRAME_IS_DIRTY);
  377. anonKid->ReflowSVG();
  378. MOZ_ASSERT(!anonKid->GetNextSibling(),
  379. "We should have one anonymous child frame wrapping our real "
  380. "children");
  381. }
  382. mCallingReflowSVG = false;
  383. // Set our anonymous kid's offset from our border box:
  384. anonKid->SetPosition(GetContentRectRelativeToSelf().TopLeft());
  385. // Including our size in our overflow rects regardless of the value of
  386. // 'background', 'border', etc. makes sure that we usually (when we clip to
  387. // our content area) don't have to keep changing our overflow rects as our
  388. // descendants move about (see perf comment below). Including our size in our
  389. // scrollable overflow rect also makes sure that we scroll if we're too big
  390. // for our viewport.
  391. //
  392. // <svg> never allows scrolling to anything outside its mRect (only panning),
  393. // so we must always keep our scrollable overflow set to our size.
  394. //
  395. // With regards to visual overflow, we always clip root-<svg> (see our
  396. // BuildDisplayList method) regardless of the value of the 'overflow'
  397. // property since that is per-spec, even for the initial 'visible' value. For
  398. // that reason there's no point in adding descendant visual overflow to our
  399. // own when this frame is for a root-<svg>. That said, there's also a very
  400. // good performance reason for us wanting to avoid doing so. If we did, then
  401. // the frame's overflow would often change as descendants that are partially
  402. // or fully outside its rect moved (think animation on/off screen), and that
  403. // would cause us to do a full NS_FRAME_IS_DIRTY reflow and repaint of the
  404. // entire document tree each such move (see bug 875175).
  405. //
  406. // So it's only non-root outer-<svg> that has the visual overflow of its
  407. // descendants added to its own. (Note that the default user-agent style
  408. // sheet makes 'hidden' the default value for :not(root(svg)), so usually
  409. // FinishAndStoreOverflow will still clip this back to the frame's rect.)
  410. //
  411. // WARNING!! Keep UpdateBounds below in sync with whatever we do for our
  412. // overflow rects here! (Again, see bug 875175.)
  413. //
  414. aDesiredSize.SetOverflowAreasToDesiredBounds();
  415. if (!mIsRootContent) {
  416. aDesiredSize.mOverflowAreas.VisualOverflow().UnionRect(
  417. aDesiredSize.mOverflowAreas.VisualOverflow(),
  418. anonKid->GetVisualOverflowRect() + anonKid->GetPosition());
  419. }
  420. FinishAndStoreOverflow(&aDesiredSize);
  421. NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
  422. ("exit nsSVGOuterSVGFrame::Reflow: size=%d,%d",
  423. aDesiredSize.Width(), aDesiredSize.Height()));
  424. NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
  425. }
  426. void
  427. nsSVGOuterSVGFrame::DidReflow(nsPresContext* aPresContext,
  428. const ReflowInput* aReflowInput,
  429. nsDidReflowStatus aStatus)
  430. {
  431. nsSVGDisplayContainerFrame::DidReflow(aPresContext,aReflowInput,aStatus);
  432. // Make sure elements styled by :hover get updated if script/animation moves
  433. // them under or out from under the pointer:
  434. PresContext()->PresShell()->SynthesizeMouseMove(false);
  435. }
  436. /* virtual */ void
  437. nsSVGOuterSVGFrame::UnionChildOverflow(nsOverflowAreas& aOverflowAreas)
  438. {
  439. // See the comments in Reflow above.
  440. // WARNING!! Keep this in sync with Reflow above!
  441. if (!mIsRootContent) {
  442. nsIFrame *anonKid = PrincipalChildList().FirstChild();
  443. aOverflowAreas.VisualOverflow().UnionRect(
  444. aOverflowAreas.VisualOverflow(),
  445. anonKid->GetVisualOverflowRect() + anonKid->GetPosition());
  446. }
  447. }
  448. //----------------------------------------------------------------------
  449. // container methods
  450. /**
  451. * Used to paint/hit-test SVG when SVG display lists are disabled.
  452. */
  453. class nsDisplayOuterSVG : public nsDisplayItem {
  454. public:
  455. nsDisplayOuterSVG(nsDisplayListBuilder* aBuilder,
  456. nsSVGOuterSVGFrame* aFrame) :
  457. nsDisplayItem(aBuilder, aFrame) {
  458. MOZ_COUNT_CTOR(nsDisplayOuterSVG);
  459. }
  460. #ifdef NS_BUILD_REFCNT_LOGGING
  461. virtual ~nsDisplayOuterSVG() {
  462. MOZ_COUNT_DTOR(nsDisplayOuterSVG);
  463. }
  464. #endif
  465. virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
  466. HitTestState* aState,
  467. nsTArray<nsIFrame*> *aOutFrames) override;
  468. virtual void Paint(nsDisplayListBuilder* aBuilder,
  469. nsRenderingContext* aCtx) override;
  470. virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
  471. const nsDisplayItemGeometry* aGeometry,
  472. nsRegion* aInvalidRegion) override;
  473. nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
  474. {
  475. return new nsDisplayItemGenericImageGeometry(this, aBuilder);
  476. }
  477. NS_DISPLAY_DECL_NAME("SVGOuterSVG", TYPE_SVG_OUTER_SVG)
  478. };
  479. void
  480. nsDisplayOuterSVG::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
  481. HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
  482. {
  483. nsSVGOuterSVGFrame *outerSVGFrame = static_cast<nsSVGOuterSVGFrame*>(mFrame);
  484. nsPoint refFrameToContentBox =
  485. ToReferenceFrame() + outerSVGFrame->GetContentRectRelativeToSelf().TopLeft();
  486. nsPoint pointRelativeToContentBox =
  487. nsPoint(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2) -
  488. refFrameToContentBox;
  489. gfxPoint svgViewportRelativePoint =
  490. gfxPoint(pointRelativeToContentBox.x, pointRelativeToContentBox.y) /
  491. outerSVGFrame->PresContext()->AppUnitsPerCSSPixel();
  492. nsSVGOuterSVGAnonChildFrame *anonKid =
  493. static_cast<nsSVGOuterSVGAnonChildFrame*>(
  494. outerSVGFrame->PrincipalChildList().FirstChild());
  495. nsIFrame* frame =
  496. nsSVGUtils::HitTestChildren(anonKid, svgViewportRelativePoint);
  497. if (frame) {
  498. aOutFrames->AppendElement(frame);
  499. }
  500. }
  501. void
  502. nsDisplayOuterSVG::Paint(nsDisplayListBuilder* aBuilder,
  503. nsRenderingContext* aContext)
  504. {
  505. #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
  506. PRTime start = PR_Now();
  507. #endif
  508. // Create an SVGAutoRenderState so we can call SetPaintingToWindow on it.
  509. SVGAutoRenderState state(aContext->GetDrawTarget());
  510. if (aBuilder->IsPaintingToWindow()) {
  511. state.SetPaintingToWindow(true);
  512. }
  513. nsRect viewportRect =
  514. mFrame->GetContentRectRelativeToSelf() + ToReferenceFrame();
  515. nsRect clipRect = mVisibleRect.Intersect(viewportRect);
  516. uint32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
  517. nsIntRect contentAreaDirtyRect =
  518. (clipRect - viewportRect.TopLeft()).
  519. ToOutsidePixels(appUnitsPerDevPixel);
  520. gfxPoint devPixelOffset =
  521. nsLayoutUtils::PointToGfxPoint(viewportRect.TopLeft(), appUnitsPerDevPixel);
  522. aContext->ThebesContext()->Save();
  523. // We include the offset of our frame and a scale from device pixels to user
  524. // units (i.e. CSS px) in the matrix that we pass to our children):
  525. gfxMatrix tm = nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(mFrame) *
  526. gfxMatrix::Translation(devPixelOffset);
  527. DrawResult result =
  528. nsSVGUtils::PaintFrameWithEffects(mFrame, *aContext->ThebesContext(), tm,
  529. &contentAreaDirtyRect);
  530. nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
  531. aContext->ThebesContext()->Restore();
  532. #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
  533. PRTime end = PR_Now();
  534. printf("SVG Paint Timing: %f ms\n", (end-start)/1000.0);
  535. #endif
  536. }
  537. nsRegion
  538. nsSVGOuterSVGFrame::FindInvalidatedForeignObjectFrameChildren(nsIFrame* aFrame)
  539. {
  540. nsRegion result;
  541. if (mForeignObjectHash && mForeignObjectHash->Count()) {
  542. for (auto it = mForeignObjectHash->Iter(); !it.Done(); it.Next()) {
  543. result.Or(result, it.Get()->GetKey()->GetInvalidRegion());
  544. }
  545. }
  546. return result;
  547. }
  548. void
  549. nsDisplayOuterSVG::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
  550. const nsDisplayItemGeometry* aGeometry,
  551. nsRegion* aInvalidRegion)
  552. {
  553. nsSVGOuterSVGFrame *frame = static_cast<nsSVGOuterSVGFrame*>(mFrame);
  554. frame->InvalidateSVG(frame->FindInvalidatedForeignObjectFrameChildren(frame));
  555. nsRegion result = frame->GetInvalidRegion();
  556. result.MoveBy(ToReferenceFrame());
  557. frame->ClearInvalidRegion();
  558. nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
  559. aInvalidRegion->Or(*aInvalidRegion, result);
  560. auto geometry =
  561. static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
  562. if (aBuilder->ShouldSyncDecodeImages() &&
  563. geometry->ShouldInvalidateToSyncDecodeImages()) {
  564. bool snap;
  565. aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
  566. }
  567. }
  568. nsresult
  569. nsSVGOuterSVGFrame::AttributeChanged(int32_t aNameSpaceID,
  570. nsIAtom* aAttribute,
  571. int32_t aModType)
  572. {
  573. if (aNameSpaceID == kNameSpaceID_None &&
  574. !(GetStateBits() & (NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_NONDISPLAY))) {
  575. if (aAttribute == nsGkAtoms::viewBox ||
  576. aAttribute == nsGkAtoms::preserveAspectRatio ||
  577. aAttribute == nsGkAtoms::transform) {
  578. // make sure our cached transform matrix gets (lazily) updated
  579. mCanvasTM = nullptr;
  580. nsSVGUtils::NotifyChildrenOfSVGChange(PrincipalChildList().FirstChild(),
  581. aAttribute == nsGkAtoms::viewBox ?
  582. TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
  583. if (aAttribute != nsGkAtoms::transform) {
  584. static_cast<SVGSVGElement*>(mContent)->ChildrenOnlyTransformChanged();
  585. }
  586. } else if (aAttribute == nsGkAtoms::width ||
  587. aAttribute == nsGkAtoms::height) {
  588. // Don't call ChildrenOnlyTransformChanged() here, since we call it
  589. // under Reflow if the width/height actually changed.
  590. nsIFrame* embeddingFrame;
  591. if (IsRootOfReplacedElementSubDoc(&embeddingFrame) && embeddingFrame) {
  592. if (DependsOnIntrinsicSize(embeddingFrame)) {
  593. // Tell embeddingFrame's presShell it needs to be reflowed (which takes
  594. // care of reflowing us too).
  595. embeddingFrame->PresContext()->PresShell()->
  596. FrameNeedsReflow(embeddingFrame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  597. }
  598. // else our width and height is overridden - don't reflow anything
  599. } else {
  600. // We are not embedded by reference, so our 'width' and 'height'
  601. // attributes are not overridden - we need to reflow.
  602. PresContext()->PresShell()->
  603. FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  604. }
  605. }
  606. }
  607. return NS_OK;
  608. }
  609. //----------------------------------------------------------------------
  610. // painting
  611. void
  612. nsSVGOuterSVGFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  613. const nsDisplayListSet& aLists)
  614. {
  615. if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
  616. return;
  617. }
  618. DisplayBorderBackgroundOutline(aBuilder, aLists);
  619. // Per-spec, we always clip root-<svg> even when 'overflow' has its initial
  620. // value of 'visible'. See also the "visual overflow" comments in Reflow.
  621. DisplayListClipState::AutoSaveRestore autoSR(aBuilder);
  622. if (mIsRootContent ||
  623. StyleDisplay()->IsScrollableOverflow()) {
  624. autoSR.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
  625. }
  626. if ((aBuilder->IsForEventDelivery() &&
  627. NS_SVGDisplayListHitTestingEnabled()) ||
  628. (!aBuilder->IsForEventDelivery() &&
  629. NS_SVGDisplayListPaintingEnabled())) {
  630. nsDisplayList *contentList = aLists.Content();
  631. nsDisplayListSet set(contentList, contentList, contentList,
  632. contentList, contentList, contentList);
  633. BuildDisplayListForNonBlockChildren(aBuilder, set);
  634. } else if (IsVisibleForPainting(aBuilder) || !aBuilder->IsForPainting()) {
  635. aLists.Content()->AppendNewToTop(
  636. new (aBuilder) nsDisplayOuterSVG(aBuilder, this));
  637. }
  638. }
  639. nsSplittableType
  640. nsSVGOuterSVGFrame::GetSplittableType() const
  641. {
  642. return NS_FRAME_NOT_SPLITTABLE;
  643. }
  644. nsIAtom *
  645. nsSVGOuterSVGFrame::GetType() const
  646. {
  647. return nsGkAtoms::svgOuterSVGFrame;
  648. }
  649. //----------------------------------------------------------------------
  650. // nsISVGSVGFrame methods:
  651. void
  652. nsSVGOuterSVGFrame::NotifyViewportOrTransformChanged(uint32_t aFlags)
  653. {
  654. MOZ_ASSERT(aFlags &&
  655. !(aFlags & ~(COORD_CONTEXT_CHANGED | TRANSFORM_CHANGED |
  656. FULL_ZOOM_CHANGED)),
  657. "Unexpected aFlags value");
  658. // No point in doing anything when were not init'ed yet:
  659. if (!mViewportInitialized) {
  660. return;
  661. }
  662. SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
  663. if (aFlags & COORD_CONTEXT_CHANGED) {
  664. if (content->HasViewBoxRect()) {
  665. // Percentage lengths on children resolve against the viewBox rect so we
  666. // don't need to notify them of the viewport change, but the viewBox
  667. // transform will have changed, so we need to notify them of that instead.
  668. aFlags = TRANSFORM_CHANGED;
  669. }
  670. else if (content->ShouldSynthesizeViewBox()) {
  671. // In the case of a synthesized viewBox, the synthetic viewBox's rect
  672. // changes as the viewport changes. As a result we need to maintain the
  673. // COORD_CONTEXT_CHANGED flag.
  674. aFlags |= TRANSFORM_CHANGED;
  675. }
  676. else if (mCanvasTM && mCanvasTM->IsSingular()) {
  677. // A width/height of zero will result in us having a singular mCanvasTM
  678. // even when we don't have a viewBox. So we also want to recompute our
  679. // mCanvasTM for this width/height change even though we don't have a
  680. // viewBox.
  681. aFlags |= TRANSFORM_CHANGED;
  682. }
  683. }
  684. bool haveNonFulLZoomTransformChange = (aFlags & TRANSFORM_CHANGED);
  685. if (aFlags & FULL_ZOOM_CHANGED) {
  686. // Convert FULL_ZOOM_CHANGED to TRANSFORM_CHANGED:
  687. aFlags = (aFlags & ~FULL_ZOOM_CHANGED) | TRANSFORM_CHANGED;
  688. }
  689. if (aFlags & TRANSFORM_CHANGED) {
  690. // Make sure our canvas transform matrix gets (lazily) recalculated:
  691. mCanvasTM = nullptr;
  692. if (haveNonFulLZoomTransformChange &&
  693. !(mState & NS_FRAME_IS_NONDISPLAY)) {
  694. uint32_t flags = (mState & NS_FRAME_IN_REFLOW) ?
  695. SVGSVGElement::eDuringReflow : 0;
  696. content->ChildrenOnlyTransformChanged(flags);
  697. }
  698. }
  699. nsSVGUtils::NotifyChildrenOfSVGChange(PrincipalChildList().FirstChild(), aFlags);
  700. }
  701. //----------------------------------------------------------------------
  702. // nsISVGChildFrame methods:
  703. DrawResult
  704. nsSVGOuterSVGFrame::PaintSVG(gfxContext& aContext,
  705. const gfxMatrix& aTransform,
  706. const nsIntRect* aDirtyRect)
  707. {
  708. NS_ASSERTION(PrincipalChildList().FirstChild()->GetType() ==
  709. nsGkAtoms::svgOuterSVGAnonChildFrame &&
  710. !PrincipalChildList().FirstChild()->GetNextSibling(),
  711. "We should have a single, anonymous, child");
  712. nsSVGOuterSVGAnonChildFrame *anonKid =
  713. static_cast<nsSVGOuterSVGAnonChildFrame*>(PrincipalChildList().FirstChild());
  714. return anonKid->PaintSVG(aContext, aTransform, aDirtyRect);
  715. }
  716. SVGBBox
  717. nsSVGOuterSVGFrame::GetBBoxContribution(const gfx::Matrix &aToBBoxUserspace,
  718. uint32_t aFlags)
  719. {
  720. NS_ASSERTION(PrincipalChildList().FirstChild()->GetType() ==
  721. nsGkAtoms::svgOuterSVGAnonChildFrame &&
  722. !PrincipalChildList().FirstChild()->GetNextSibling(),
  723. "We should have a single, anonymous, child");
  724. // We must defer to our child so that we don't include our
  725. // content->PrependLocalTransformsTo() transforms.
  726. nsSVGOuterSVGAnonChildFrame *anonKid =
  727. static_cast<nsSVGOuterSVGAnonChildFrame*>(PrincipalChildList().FirstChild());
  728. return anonKid->GetBBoxContribution(aToBBoxUserspace, aFlags);
  729. }
  730. //----------------------------------------------------------------------
  731. // nsSVGContainerFrame methods:
  732. gfxMatrix
  733. nsSVGOuterSVGFrame::GetCanvasTM()
  734. {
  735. if (!mCanvasTM) {
  736. SVGSVGElement *content = static_cast<SVGSVGElement*>(mContent);
  737. float devPxPerCSSPx =
  738. 1.0f / PresContext()->AppUnitsToFloatCSSPixels(
  739. PresContext()->AppUnitsPerDevPixel());
  740. gfxMatrix tm = content->PrependLocalTransformsTo(
  741. gfxMatrix::Scaling(devPxPerCSSPx, devPxPerCSSPx));
  742. mCanvasTM = new gfxMatrix(tm);
  743. }
  744. return *mCanvasTM;
  745. }
  746. //----------------------------------------------------------------------
  747. // Implementation helpers
  748. bool
  749. nsSVGOuterSVGFrame::IsRootOfReplacedElementSubDoc(nsIFrame **aEmbeddingFrame)
  750. {
  751. if (!mContent->GetParent()) {
  752. // Our content is the document element
  753. nsCOMPtr<nsIDocShell> docShell = PresContext()->GetDocShell();
  754. nsCOMPtr<nsPIDOMWindowOuter> window;
  755. if (docShell) {
  756. window = docShell->GetWindow();
  757. }
  758. if (window) {
  759. nsCOMPtr<nsIDOMElement> frameElement = window->GetFrameElement();
  760. nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(frameElement);
  761. nsCOMPtr<nsIDOMHTMLIFrameElement> iframeElement =
  762. do_QueryInterface(frameElement);
  763. if (olc || iframeElement) {
  764. // Our document is inside an HTML 'object', 'embed', 'applet'
  765. // or 'iframe' element
  766. if (aEmbeddingFrame) {
  767. nsCOMPtr<nsIContent> element = do_QueryInterface(frameElement);
  768. *aEmbeddingFrame = element->GetPrimaryFrame();
  769. NS_ASSERTION(*aEmbeddingFrame, "Yikes, no embedding frame!");
  770. }
  771. return true;
  772. }
  773. }
  774. }
  775. if (aEmbeddingFrame) {
  776. *aEmbeddingFrame = nullptr;
  777. }
  778. return false;
  779. }
  780. bool
  781. nsSVGOuterSVGFrame::IsRootOfImage()
  782. {
  783. if (!mContent->GetParent()) {
  784. // Our content is the document element
  785. nsIDocument* doc = mContent->GetUncomposedDoc();
  786. if (doc && doc->IsBeingUsedAsImage()) {
  787. // Our document is being used as an image
  788. return true;
  789. }
  790. }
  791. return false;
  792. }
  793. bool
  794. nsSVGOuterSVGFrame::VerticalScrollbarNotNeeded() const
  795. {
  796. nsSVGLength2 &height = static_cast<SVGSVGElement*>(mContent)->
  797. mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
  798. return height.IsPercentage() && height.GetBaseValInSpecifiedUnits() <= 100;
  799. }
  800. //----------------------------------------------------------------------
  801. // Implementation of nsSVGOuterSVGAnonChildFrame
  802. nsContainerFrame*
  803. NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell,
  804. nsStyleContext* aContext)
  805. {
  806. return new (aPresShell) nsSVGOuterSVGAnonChildFrame(aContext);
  807. }
  808. NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGAnonChildFrame)
  809. #ifdef DEBUG
  810. void
  811. nsSVGOuterSVGAnonChildFrame::Init(nsIContent* aContent,
  812. nsContainerFrame* aParent,
  813. nsIFrame* aPrevInFlow)
  814. {
  815. MOZ_ASSERT(aParent->GetType() == nsGkAtoms::svgOuterSVGFrame,
  816. "Unexpected parent");
  817. nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
  818. }
  819. #endif
  820. nsIAtom *
  821. nsSVGOuterSVGAnonChildFrame::GetType() const
  822. {
  823. return nsGkAtoms::svgOuterSVGAnonChildFrame;
  824. }
  825. static Matrix
  826. ComputeOuterSVGAnonChildFrameTransform(const nsSVGOuterSVGAnonChildFrame* aFrame)
  827. {
  828. // Our elements 'transform' attribute is applied to our nsSVGOuterSVGFrame
  829. // parent, and the element's children-only transforms are applied to us, the
  830. // anonymous child frame. Since we are the child frame, we apply the
  831. // children-only transforms as if they are our own transform.
  832. SVGSVGElement* content = static_cast<SVGSVGElement*>(aFrame->GetContent());
  833. if (!content->HasChildrenOnlyTransform()) {
  834. return Matrix();
  835. }
  836. // Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here.
  837. gfxMatrix ownMatrix =
  838. content->PrependLocalTransformsTo(gfxMatrix(), eChildToUserSpace);
  839. if (ownMatrix.HasNonTranslation()) {
  840. // viewBox, currentScale and currentTranslate should only produce a
  841. // rectilinear transform.
  842. MOZ_ASSERT(ownMatrix.IsRectilinear(),
  843. "Non-rectilinear transform will break the following logic");
  844. // The nsDisplayTransform code will apply this transform to our frame,
  845. // including to our frame position. We don't want our frame position to
  846. // be scaled though, so we need to correct for that in the transform.
  847. CSSPoint pos = CSSPixel::FromAppUnits(aFrame->GetPosition());
  848. CSSPoint scaledPos = CSSPoint(ownMatrix._11 * pos.x, ownMatrix._22 * pos.y);
  849. CSSPoint deltaPos = scaledPos - pos;
  850. ownMatrix *= gfxMatrix::Translation(-deltaPos.x, -deltaPos.y);
  851. }
  852. return gfx::ToMatrix(ownMatrix);
  853. }
  854. // We want this frame to be a reference frame. An easy way to achieve that is
  855. // to always return true from this method, even for identity transforms.
  856. // This frame being a reference frame ensures that the offset between this
  857. // <svg> element and the parent reference frame is completely absorbed by the
  858. // nsDisplayTransform that's created for this frame, and that this offset does
  859. // not affect our descendants' transforms. Consequently, if the <svg> element
  860. // moves, e.g. during scrolling, the transform matrices of our contents are
  861. // unaffected. This simplifies invalidation.
  862. bool
  863. nsSVGOuterSVGAnonChildFrame::IsSVGTransformed(Matrix* aOwnTransform,
  864. Matrix* aFromParentTransform) const
  865. {
  866. if (aOwnTransform) {
  867. *aOwnTransform = ComputeOuterSVGAnonChildFrameTransform(this);
  868. }
  869. return true;
  870. }