LCOV - code coverage report
Current view: top level - layout/svg - nsSVGOuterSVGFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 214 408 52.5 %
Date: 2017-07-14 16:53:18 Functions: 22 42 52.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13