layout/svg/nsSVGForeignObjectFrame.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial