LCOV - code coverage report
Current view: top level - layout/svg - nsSVGForeignObjectFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 104 249 41.8 %
Date: 2017-07-14 16:53:18 Functions: 11 20 55.0 %
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 "nsSVGForeignObjectFrame.h"
       8             : 
       9             : // Keep others in (case-insensitive) order:
      10             : #include "DrawResult.h"
      11             : #include "gfxContext.h"
      12             : #include "nsDisplayList.h"
      13             : #include "nsGkAtoms.h"
      14             : #include "nsNameSpaceManager.h"
      15             : #include "nsLayoutUtils.h"
      16             : #include "nsRegion.h"
      17             : #include "nsSVGContainerFrame.h"
      18             : #include "nsSVGEffects.h"
      19             : #include "mozilla/dom/SVGForeignObjectElement.h"
      20             : #include "nsSVGIntegrationUtils.h"
      21             : #include "nsSVGOuterSVGFrame.h"
      22             : #include "nsSVGUtils.h"
      23             : #include "mozilla/AutoRestore.h"
      24             : 
      25             : using namespace mozilla;
      26             : using namespace mozilla::dom;
      27             : using namespace mozilla::image;
      28             : 
      29             : //----------------------------------------------------------------------
      30             : // Implementation
      31             : 
      32             : nsContainerFrame*
      33           2 : NS_NewSVGForeignObjectFrame(nsIPresShell   *aPresShell,
      34             :                             nsStyleContext *aContext)
      35             : {
      36           2 :   return new (aPresShell) nsSVGForeignObjectFrame(aContext);
      37             : }
      38             : 
      39           2 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
      40             : 
      41           2 : nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
      42             :   : nsContainerFrame(aContext, kClassID)
      43           2 :   , mInReflow(false)
      44             : {
      45           2 :   AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED |
      46           2 :                NS_FRAME_SVG_LAYOUT);
      47           2 : }
      48             : 
      49             : //----------------------------------------------------------------------
      50             : // nsIFrame methods
      51             : 
      52          16 : NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
      53          12 :   NS_QUERYFRAME_ENTRY(nsSVGDisplayableFrame)
      54           4 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
      55             : 
      56             : void
      57           2 : nsSVGForeignObjectFrame::Init(nsIContent*       aContent,
      58             :                               nsContainerFrame* aParent,
      59             :                               nsIFrame*         aPrevInFlow)
      60             : {
      61           2 :   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::foreignObject),
      62             :                "Content is not an SVG foreignObject!");
      63             : 
      64           2 :   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
      65           2 :   AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
      66           2 :   AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER |
      67           2 :                NS_FRAME_FONT_INFLATION_FLOW_ROOT);
      68           2 :   if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
      69           2 :     nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
      70             :   }
      71           2 : }
      72             : 
      73           0 : void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
      74             : {
      75             :   // Only unregister if we registered in the first place:
      76           0 :   if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
      77           0 :       nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
      78             :   }
      79           0 :   nsContainerFrame::DestroyFrom(aDestructRoot);
      80           0 : }
      81             : 
      82             : nsresult
      83           0 : nsSVGForeignObjectFrame::AttributeChanged(int32_t  aNameSpaceID,
      84             :                                           nsIAtom *aAttribute,
      85             :                                           int32_t  aModType)
      86             : {
      87           0 :   if (aNameSpaceID == kNameSpaceID_None) {
      88           0 :     if (aAttribute == nsGkAtoms::width ||
      89           0 :         aAttribute == nsGkAtoms::height) {
      90           0 :       nsLayoutUtils::PostRestyleEvent(
      91           0 :         mContent->AsElement(), nsRestyleHint(0),
      92           0 :         nsChangeHint_InvalidateRenderingObservers);
      93           0 :       nsSVGUtils::ScheduleReflowSVG(this);
      94             :       // XXXjwatt: why mark intrinsic widths dirty? can't we just use eResize?
      95           0 :       RequestReflow(nsIPresShell::eStyleChange);
      96           0 :     } else if (aAttribute == nsGkAtoms::x ||
      97           0 :                aAttribute == nsGkAtoms::y) {
      98             :       // make sure our cached transform matrix gets (lazily) updated
      99           0 :       mCanvasTM = nullptr;
     100           0 :       nsLayoutUtils::PostRestyleEvent(
     101           0 :         mContent->AsElement(), nsRestyleHint(0),
     102           0 :         nsChangeHint_InvalidateRenderingObservers);
     103           0 :       nsSVGUtils::ScheduleReflowSVG(this);
     104           0 :     } else if (aAttribute == nsGkAtoms::transform) {
     105             :       // We don't invalidate for transform changes (the layers code does that).
     106             :       // Also note that SVGTransformableElement::GetAttributeChangeHint will
     107             :       // return nsChangeHint_UpdateOverflow for "transform" attribute changes
     108             :       // and cause DoApplyRenderingChangeToTree to make the SchedulePaint call.
     109           0 :       mCanvasTM = nullptr;
     110           0 :     } else if (aAttribute == nsGkAtoms::viewBox ||
     111           0 :                aAttribute == nsGkAtoms::preserveAspectRatio) {
     112           0 :       nsLayoutUtils::PostRestyleEvent(
     113           0 :         mContent->AsElement(), nsRestyleHint(0),
     114           0 :         nsChangeHint_InvalidateRenderingObservers);
     115             :     }
     116             :   }
     117             : 
     118           0 :   return NS_OK;
     119             : }
     120             : 
     121             : void
     122           0 : nsSVGForeignObjectFrame::Reflow(nsPresContext*           aPresContext,
     123             :                                 ReflowOutput&     aDesiredSize,
     124             :                                 const ReflowInput& aReflowInput,
     125             :                                 nsReflowStatus&          aStatus)
     126             : {
     127           0 :   MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
     128             :              "Should not have been called");
     129             : 
     130             :   // Only InvalidateAndScheduleBoundsUpdate marks us with NS_FRAME_IS_DIRTY,
     131             :   // so if that bit is still set we still have a resize pending. If we hit
     132             :   // this assertion, then we should get the presShell to skip reflow roots
     133             :   // that have a dirty parent since a reflow is going to come via the
     134             :   // reflow root's parent anyway.
     135           0 :   NS_ASSERTION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
     136             :                "Reflowing while a resize is pending is wasteful");
     137             : 
     138             :   // ReflowSVG makes sure mRect is up to date before we're called.
     139             : 
     140           0 :   NS_ASSERTION(!aReflowInput.mParentReflowInput,
     141             :                "should only get reflow from being reflow root");
     142           0 :   NS_ASSERTION(aReflowInput.ComputedWidth() == GetSize().width &&
     143             :                aReflowInput.ComputedHeight() == GetSize().height,
     144             :                "reflow roots should be reflowed at existing size and "
     145             :                "svg.css should ensure we have no padding/border/margin");
     146             : 
     147           0 :   DoReflow();
     148             : 
     149           0 :   WritingMode wm = aReflowInput.GetWritingMode();
     150             :   LogicalSize finalSize(wm, aReflowInput.ComputedISize(),
     151           0 :                         aReflowInput.ComputedBSize());
     152           0 :   aDesiredSize.SetSize(wm, finalSize);
     153           0 :   aDesiredSize.SetOverflowAreasToDesiredBounds();
     154           0 :   aStatus.Reset();
     155           0 : }
     156             : 
     157             : void
     158           2 : nsSVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     159             :                                           const nsRect&           aDirtyRect,
     160             :                                           const nsDisplayListSet& aLists)
     161             : {
     162           2 :   if (!static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
     163           0 :     return;
     164             :   }
     165           2 :   DisplayOutline(aBuilder, aLists);
     166           2 :   BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
     167             : }
     168             : 
     169             : bool
     170          30 : nsSVGForeignObjectFrame::IsSVGTransformed(Matrix *aOwnTransform,
     171             :                                           Matrix *aFromParentTransform) const
     172             : {
     173          30 :   bool foundTransform = false;
     174             : 
     175             :   // Check if our parent has children-only transforms:
     176          30 :   nsIFrame *parent = GetParent();
     177          60 :   if (parent &&
     178          30 :       parent->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
     179             :     foundTransform = static_cast<nsSVGContainerFrame*>(parent)->
     180          30 :                        HasChildrenOnlyTransform(aFromParentTransform);
     181             :   }
     182             : 
     183          30 :   nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
     184             :   nsSVGAnimatedTransformList* transformList =
     185          30 :     content->GetAnimatedTransformList();
     186          60 :   if ((transformList && transformList->HasTransform()) ||
     187          30 :       content->GetAnimateMotionTransform()) {
     188           0 :     if (aOwnTransform) {
     189           0 :       *aOwnTransform = gfx::ToMatrix(content->PrependLocalTransformsTo(
     190           0 :                                        gfxMatrix(),
     191           0 :                                        eUserSpaceToParent));
     192             :     }
     193           0 :     foundTransform = true;
     194             :   }
     195          30 :   return foundTransform;
     196             : }
     197             : 
     198             : void
     199           0 : nsSVGForeignObjectFrame::PaintSVG(gfxContext& aContext,
     200             :                                   const gfxMatrix& aTransform,
     201             :                                   imgDrawingParams& aImgParams,
     202             :                                   const nsIntRect* aDirtyRect)
     203             : {
     204           0 :   NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
     205             :                (mState & NS_FRAME_IS_NONDISPLAY),
     206             :                "If display lists are enabled, only painting of non-display "
     207             :                "SVG should take this code path");
     208             : 
     209           0 :   if (IsDisabled()) {
     210           0 :     return;
     211             :   }
     212             : 
     213           0 :   nsIFrame* kid = PrincipalChildList().FirstChild();
     214           0 :   if (!kid) {
     215           0 :     return;
     216             :   }
     217             : 
     218           0 :   if (aTransform.IsSingular()) {
     219           0 :     NS_WARNING("Can't render foreignObject element!");
     220           0 :     return;
     221             :   }
     222             : 
     223           0 :   nsRect kidDirtyRect = kid->GetVisualOverflowRect();
     224             : 
     225             :   /* Check if we need to draw anything. */
     226           0 :   if (aDirtyRect) {
     227           0 :     NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
     228             :                  (mState & NS_FRAME_IS_NONDISPLAY),
     229             :                  "Display lists handle dirty rect intersection test");
     230             :     // Transform the dirty rect into app units in our userspace.
     231           0 :     gfxMatrix invmatrix = aTransform;
     232           0 :     DebugOnly<bool> ok = invmatrix.Invert();
     233           0 :     NS_ASSERTION(ok, "inverse of non-singular matrix should be non-singular");
     234             : 
     235           0 :     gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
     236           0 :                                      aDirtyRect->width, aDirtyRect->height);
     237           0 :     transDirtyRect = invmatrix.TransformBounds(transDirtyRect);
     238             : 
     239             :     kidDirtyRect.IntersectRect(kidDirtyRect,
     240           0 :       nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect,
     241           0 :                        PresContext()->AppUnitsPerCSSPixel()));
     242             : 
     243             :     // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect,
     244             :     // not with kidDirtyRect. I.e.
     245             :     // int32_t appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
     246             :     // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)
     247           0 :     if (kidDirtyRect.IsEmpty())
     248           0 :       return;
     249             :   }
     250             : 
     251           0 :   aContext.Save();
     252             : 
     253           0 :   if (StyleDisplay()->IsScrollableOverflow()) {
     254             :     float x, y, width, height;
     255           0 :     static_cast<nsSVGElement*>(mContent)->
     256           0 :       GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
     257             : 
     258             :     gfxRect clipRect =
     259           0 :       nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
     260           0 :     nsSVGUtils::SetClipRect(&aContext, aTransform, clipRect);
     261             :   }
     262             : 
     263             :   // SVG paints in CSS px, but normally frames paint in dev pixels. Here we
     264             :   // multiply a CSS-px-to-dev-pixel factor onto aTransform so our children
     265             :   // paint correctly.
     266           0 :   float cssPxPerDevPx = PresContext()->
     267           0 :     AppUnitsToFloatCSSPixels(PresContext()->AppUnitsPerDevPixel());
     268           0 :   gfxMatrix canvasTMForChildren = aTransform;
     269           0 :   canvasTMForChildren.PreScale(cssPxPerDevPx, cssPxPerDevPx);
     270             : 
     271           0 :   aContext.Multiply(canvasTMForChildren);
     272             : 
     273             :   using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
     274           0 :   PaintFrameFlags flags = PaintFrameFlags::PAINT_IN_TRANSFORM;
     275           0 :   if (SVGAutoRenderState::IsPaintingToWindow(aContext.GetDrawTarget())) {
     276           0 :     flags |= PaintFrameFlags::PAINT_TO_WINDOW;
     277             :   }
     278           0 :   if (aImgParams.imageFlags & imgIContainer::FLAG_SYNC_DECODE) {
     279           0 :     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
     280             :   }
     281           0 :   Unused << nsLayoutUtils::PaintFrame(&aContext, kid, nsRegion(kidDirtyRect),
     282             :                                       NS_RGBA(0,0,0,0),
     283             :                                       nsDisplayListBuilderMode::PAINTING,
     284             :                                       flags);
     285             : 
     286           0 :   aContext.Restore();
     287             : }
     288             : 
     289             : nsIFrame*
     290           0 : nsSVGForeignObjectFrame::GetFrameForPoint(const gfxPoint& aPoint)
     291             : {
     292           0 :   NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
     293             :                (mState & NS_FRAME_IS_NONDISPLAY),
     294             :                "If display lists are enabled, only hit-testing of a "
     295             :                "clipPath's contents should take this code path");
     296             : 
     297           0 :   if (IsDisabled() || (GetStateBits() & NS_FRAME_IS_NONDISPLAY))
     298           0 :     return nullptr;
     299             : 
     300           0 :   nsIFrame* kid = PrincipalChildList().FirstChild();
     301           0 :   if (!kid)
     302           0 :     return nullptr;
     303             : 
     304             :   float x, y, width, height;
     305           0 :   static_cast<nsSVGElement*>(mContent)->
     306           0 :     GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
     307             : 
     308           0 :   if (!gfxRect(x, y, width, height).Contains(aPoint) ||
     309           0 :       !nsSVGUtils::HitTestClip(this, aPoint)) {
     310           0 :     return nullptr;
     311             :   }
     312             : 
     313             :   // Convert the point to app units relative to the top-left corner of the
     314             :   // viewport that's established by the foreignObject element:
     315             : 
     316           0 :   gfxPoint pt = (aPoint + gfxPoint(x, y)) * nsPresContext::AppUnitsPerCSSPixel();
     317           0 :   nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
     318             : 
     319           0 :   return nsLayoutUtils::GetFrameForPoint(kid, point);
     320             : }
     321             : 
     322             : void
     323           4 : nsSVGForeignObjectFrame::ReflowSVG()
     324             : {
     325           4 :   NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
     326             :                "This call is probably a wasteful mistake");
     327             : 
     328           4 :   MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
     329             :              "ReflowSVG mechanism not designed for this");
     330             : 
     331           4 :   if (!nsSVGUtils::NeedsReflowSVG(this)) {
     332           0 :     return;
     333             :   }
     334             : 
     335             :   // We update mRect before the DoReflow call so that DoReflow uses the
     336             :   // correct dimensions:
     337             : 
     338             :   float x, y, w, h;
     339           4 :   static_cast<SVGForeignObjectElement*>(mContent)->
     340           4 :     GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
     341             : 
     342             :   // If mRect's width or height are negative, reflow blows up! We must clamp!
     343           4 :   if (w < 0.0f) w = 0.0f;
     344           4 :   if (h < 0.0f) h = 0.0f;
     345             : 
     346           8 :   mRect = nsLayoutUtils::RoundGfxRectToAppRect(
     347           8 :                            gfxRect(x, y, w, h),
     348           4 :                            PresContext()->AppUnitsPerCSSPixel());
     349             : 
     350             :   // Fully mark our kid dirty so that it gets resized if necessary
     351             :   // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case):
     352           4 :   nsIFrame* kid = PrincipalChildList().FirstChild();
     353           4 :   kid->AddStateBits(NS_FRAME_IS_DIRTY);
     354             : 
     355             :   // Make sure to not allow interrupts if we're not being reflown as a root:
     356           8 :   nsPresContext::InterruptPreventer noInterrupts(PresContext());
     357             : 
     358           4 :   DoReflow();
     359             : 
     360           4 :   if (mState & NS_FRAME_FIRST_REFLOW) {
     361             :     // Make sure we have our filter property (if any) before calling
     362             :     // FinishAndStoreOverflow (subsequent filter changes are handled off
     363             :     // nsChangeHint_UpdateEffects):
     364           2 :     nsSVGEffects::UpdateEffects(this);
     365             :   }
     366             : 
     367             :   // If we have a filter, we need to invalidate ourselves because filter
     368             :   // output can change even if none of our descendants need repainting.
     369           4 :   if (StyleEffects()->HasFilters()) {
     370           0 :     InvalidateFrame();
     371             :   }
     372             : 
     373             :   // TODO: once we support |overflow:visible| on foreignObject, then we will
     374             :   // need to take account of our descendants here.
     375           8 :   nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
     376           8 :   nsOverflowAreas overflowAreas(overflow, overflow);
     377           4 :   FinishAndStoreOverflow(overflowAreas, mRect.Size());
     378             : 
     379             :   // Now unset the various reflow bits:
     380             :   mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
     381           4 :               NS_FRAME_HAS_DIRTY_CHILDREN);
     382             : }
     383             : 
     384             : void
     385           2 : nsSVGForeignObjectFrame::NotifySVGChanged(uint32_t aFlags)
     386             : {
     387           2 :   MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
     388             :              "Invalidation logic may need adjusting");
     389             : 
     390           2 :   bool needNewBounds = false; // i.e. mRect or visual overflow rect
     391           2 :   bool needReflow = false;
     392           2 :   bool needNewCanvasTM = false;
     393             : 
     394           2 :   if (aFlags & COORD_CONTEXT_CHANGED) {
     395             :     SVGForeignObjectElement *fO =
     396           2 :       static_cast<SVGForeignObjectElement*>(mContent);
     397             :     // Coordinate context changes affect mCanvasTM if we have a
     398             :     // percentage 'x' or 'y'
     399           4 :     if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_X].IsPercentage() ||
     400           2 :         fO->mLengthAttributes[SVGForeignObjectElement::ATTR_Y].IsPercentage()) {
     401           0 :       needNewBounds = true;
     402           0 :       needNewCanvasTM = true;
     403             :     }
     404             :     // Our coordinate context's width/height has changed. If we have a
     405             :     // percentage width/height our dimensions will change so we must reflow.
     406           4 :     if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_WIDTH].IsPercentage() ||
     407           2 :         fO->mLengthAttributes[SVGForeignObjectElement::ATTR_HEIGHT].IsPercentage()) {
     408           0 :       needNewBounds = true;
     409           0 :       needReflow = true;
     410             :     }
     411             :   }
     412             : 
     413           2 :   if (aFlags & TRANSFORM_CHANGED) {
     414           2 :     if (mCanvasTM && mCanvasTM->IsSingular()) {
     415           0 :       needNewBounds = true; // old bounds are bogus
     416             :     }
     417           2 :     needNewCanvasTM = true;
     418             :     // In an ideal world we would reflow when our CTM changes. This is because
     419             :     // glyph metrics do not necessarily scale uniformly with change in scale
     420             :     // and, as a result, CTM changes may require text to break at different
     421             :     // points. The problem would be how to keep performance acceptable when
     422             :     // e.g. the transform of an ancestor is animated.
     423             :     // We also seem to get some sort of infinite loop post bug 421584 if we
     424             :     // reflow.
     425             :   }
     426             : 
     427           2 :   if (needNewBounds) {
     428             :     // Ancestor changes can't affect how we render from the perspective of
     429             :     // any rendering observers that we may have, so we don't need to
     430             :     // invalidate them. We also don't need to invalidate ourself, since our
     431             :     // changed ancestor will have invalidated its entire area, which includes
     432             :     // our area.
     433           0 :     nsSVGUtils::ScheduleReflowSVG(this);
     434             :   }
     435             : 
     436             :   // If we're called while the PresShell is handling reflow events then we
     437             :   // must have been called as a result of the NotifyViewportChange() call in
     438             :   // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
     439             :   // at this point (i.e. during reflow) because it could confuse the
     440             :   // PresShell and prevent it from reflowing us properly in future. Besides
     441             :   // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
     442             :   // synchronously, so there's no need.
     443           2 :   if (needReflow && !PresContext()->PresShell()->IsReflowLocked()) {
     444           0 :     RequestReflow(nsIPresShell::eResize);
     445             :   }
     446             : 
     447           2 :   if (needNewCanvasTM) {
     448             :     // Do this after calling InvalidateAndScheduleBoundsUpdate in case we
     449             :     // change the code and it needs to use it.
     450           2 :     mCanvasTM = nullptr;
     451             :   }
     452           2 : }
     453             : 
     454             : SVGBBox
     455           2 : nsSVGForeignObjectFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
     456             :                                              uint32_t aFlags)
     457             : {
     458             :   SVGForeignObjectElement *content =
     459           2 :     static_cast<SVGForeignObjectElement*>(mContent);
     460             : 
     461             :   float x, y, w, h;
     462           2 :   content->GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
     463             : 
     464           2 :   if (w < 0.0f) w = 0.0f;
     465           2 :   if (h < 0.0f) h = 0.0f;
     466             : 
     467           2 :   if (aToBBoxUserspace.IsSingular()) {
     468             :     // XXX ReportToConsole
     469           0 :     return SVGBBox();
     470             :   }
     471           2 :   return aToBBoxUserspace.TransformBounds(gfx::Rect(0.0, 0.0, w, h));
     472             : }
     473             : 
     474             : //----------------------------------------------------------------------
     475             : 
     476             : gfxMatrix
     477           0 : nsSVGForeignObjectFrame::GetCanvasTM()
     478             : {
     479           0 :   if (!mCanvasTM) {
     480           0 :     NS_ASSERTION(GetParent(), "null parent");
     481             : 
     482           0 :     nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(GetParent());
     483             :     SVGForeignObjectElement *content =
     484           0 :       static_cast<SVGForeignObjectElement*>(mContent);
     485             : 
     486           0 :     gfxMatrix tm = content->PrependLocalTransformsTo(parent->GetCanvasTM());
     487             : 
     488           0 :     mCanvasTM = new gfxMatrix(tm);
     489             :   }
     490           0 :   return *mCanvasTM;
     491             : }
     492             : 
     493             : //----------------------------------------------------------------------
     494             : // Implementation helpers
     495             : 
     496           0 : void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType)
     497             : {
     498           0 :   if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
     499             :     // If we haven't had a ReflowSVG() yet, nothing to do.
     500           0 :     return;
     501             : 
     502           0 :   nsIFrame* kid = PrincipalChildList().FirstChild();
     503           0 :   if (!kid)
     504           0 :     return;
     505             : 
     506           0 :   PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
     507             : }
     508             : 
     509             : void
     510           4 : nsSVGForeignObjectFrame::DoReflow()
     511             : {
     512           4 :   MarkInReflow();
     513             :   // Skip reflow if we're zero-sized, unless this is our first reflow.
     514           4 :   if (IsDisabled() &&
     515           0 :       !(GetStateBits() & NS_FRAME_FIRST_REFLOW))
     516           0 :     return;
     517             : 
     518           4 :   nsPresContext *presContext = PresContext();
     519           4 :   nsIFrame* kid = PrincipalChildList().FirstChild();
     520           4 :   if (!kid)
     521           0 :     return;
     522             : 
     523             :   // initiate a synchronous reflow here and now:
     524             :   RefPtr<gfxContext> renderingContext =
     525           8 :     presContext->PresShell()->CreateReferenceRenderingContext();
     526             : 
     527           4 :   mInReflow = true;
     528             : 
     529           4 :   WritingMode wm = kid->GetWritingMode();
     530             :   ReflowInput reflowInput(presContext, kid,
     531             :                                 renderingContext,
     532           8 :                                 LogicalSize(wm, ISize(wm),
     533           4 :                                             NS_UNCONSTRAINEDSIZE));
     534           8 :   ReflowOutput desiredSize(reflowInput);
     535           4 :   nsReflowStatus status;
     536             : 
     537             :   // We don't use mRect.height above because that tells the child to do
     538             :   // page/column breaking at that height.
     539           4 :   NS_ASSERTION(reflowInput.ComputedPhysicalBorderPadding() == nsMargin(0, 0, 0, 0) &&
     540             :                reflowInput.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
     541             :                "style system should ensure that :-moz-svg-foreign-content "
     542             :                "does not get styled");
     543           4 :   NS_ASSERTION(reflowInput.ComputedISize() == ISize(wm),
     544             :                "reflow state made child wrong size");
     545           4 :   reflowInput.SetComputedBSize(BSize(wm));
     546             : 
     547           4 :   ReflowChild(kid, presContext, desiredSize, reflowInput, 0, 0,
     548           4 :               NS_FRAME_NO_MOVE_FRAME, status);
     549           4 :   NS_ASSERTION(mRect.width == desiredSize.Width() &&
     550             :                mRect.height == desiredSize.Height(), "unexpected size");
     551             :   FinishReflowChild(kid, presContext, desiredSize, &reflowInput, 0, 0,
     552           4 :                     NS_FRAME_NO_MOVE_FRAME);
     553             : 
     554           4 :   mInReflow = false;
     555             : }
     556             : 
     557             : nsRect
     558           0 : nsSVGForeignObjectFrame::GetInvalidRegion()
     559             : {
     560           0 :   MOZ_ASSERT(!NS_SVGDisplayListPaintingEnabled(),
     561             :              "Only called by nsDisplayOuterSVG code");
     562             : 
     563           0 :   nsIFrame* kid = PrincipalChildList().FirstChild();
     564           0 :   if (kid->HasInvalidFrameInSubtree()) {
     565           0 :     gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height);
     566           0 :     r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
     567           0 :     nsRect rect = nsSVGUtils::ToCanvasBounds(r, GetCanvasTM(), PresContext());
     568           0 :     rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect);
     569           0 :     return rect;
     570             :   }
     571           0 :   return nsRect();
     572             : }
     573             : 
     574             : void
     575           0 : nsSVGForeignObjectFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
     576             : {
     577           0 :   MOZ_ASSERT(PrincipalChildList().FirstChild(), "Must have our anon box");
     578           0 :   aResult.AppendElement(OwnedAnonBox(PrincipalChildList().FirstChild()));
     579           0 : }

Generated by: LCOV version 1.13