LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGForeignObjectFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 266 0 0.0 %
Date: 2012-06-02 Functions: 31 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla SVG project.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Crocodile Clips Ltd..
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsSVGForeignObjectFrame.h"
      40                 : 
      41                 : #include "nsIDOMSVGForeignObjectElem.h"
      42                 : #include "nsIDOMSVGSVGElement.h"
      43                 : #include "nsSVGOuterSVGFrame.h"
      44                 : #include "nsRegion.h"
      45                 : #include "nsGkAtoms.h"
      46                 : #include "nsLayoutUtils.h"
      47                 : #include "nsSVGUtils.h"
      48                 : #include "nsIURI.h"
      49                 : #include "nsSVGRect.h"
      50                 : #include "nsINameSpaceManager.h"
      51                 : #include "nsSVGForeignObjectElement.h"
      52                 : #include "nsSVGContainerFrame.h"
      53                 : #include "gfxContext.h"
      54                 : #include "gfxMatrix.h"
      55                 : 
      56                 : //----------------------------------------------------------------------
      57                 : // Implementation
      58                 : 
      59                 : nsIFrame*
      60               0 : NS_NewSVGForeignObjectFrame(nsIPresShell   *aPresShell,
      61                 :                             nsStyleContext *aContext)
      62                 : {
      63               0 :   return new (aPresShell) nsSVGForeignObjectFrame(aContext);
      64                 : }
      65                 : 
      66               0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
      67                 : 
      68               0 : nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
      69                 :   : nsSVGForeignObjectFrameBase(aContext),
      70               0 :     mInReflow(false)
      71                 : {
      72               0 :   AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED);
      73               0 : }
      74                 : 
      75                 : //----------------------------------------------------------------------
      76                 : // nsIFrame methods
      77                 : 
      78               0 : NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
      79               0 :   NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
      80               0 : NS_QUERYFRAME_TAIL_INHERITING(nsSVGForeignObjectFrameBase)
      81                 : 
      82                 : NS_IMETHODIMP
      83               0 : nsSVGForeignObjectFrame::Init(nsIContent* aContent,
      84                 :                               nsIFrame*   aParent,
      85                 :                               nsIFrame*   aPrevInFlow)
      86                 : {
      87                 : #ifdef DEBUG
      88               0 :   nsCOMPtr<nsIDOMSVGForeignObjectElement> foreignObject = do_QueryInterface(aContent);
      89               0 :   NS_ASSERTION(foreignObject, "Content is not an SVG foreignObject!");
      90                 : #endif
      91                 : 
      92               0 :   nsresult rv = nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
      93               0 :   AddStateBits(aParent->GetStateBits() &
      94                 :                (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD |
      95               0 :                 NS_STATE_SVG_REDRAW_SUSPENDED));
      96               0 :   if (NS_SUCCEEDED(rv)) {
      97               0 :     nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
      98                 :   }
      99               0 :   return rv;
     100                 : }
     101                 : 
     102               0 : void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
     103                 : {
     104               0 :   nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
     105               0 :   nsSVGForeignObjectFrameBase::DestroyFrom(aDestructRoot);
     106               0 : }
     107                 : 
     108                 : nsIAtom *
     109               0 : nsSVGForeignObjectFrame::GetType() const
     110                 : {
     111               0 :   return nsGkAtoms::svgForeignObjectFrame;
     112                 : }
     113                 : 
     114                 : NS_IMETHODIMP
     115               0 : nsSVGForeignObjectFrame::AttributeChanged(PRInt32  aNameSpaceID,
     116                 :                                           nsIAtom *aAttribute,
     117                 :                                           PRInt32  aModType)
     118                 : {
     119               0 :   if (aNameSpaceID == kNameSpaceID_None) {
     120               0 :     if (aAttribute == nsGkAtoms::width ||
     121                 :         aAttribute == nsGkAtoms::height) {
     122               0 :       UpdateGraphic(); // update mRect before requesting reflow
     123                 :       // XXXjwatt: why mark intrinsic widths dirty? can't we just use eResize?
     124               0 :       RequestReflow(nsIPresShell::eStyleChange);
     125               0 :     } else if (aAttribute == nsGkAtoms::x ||
     126                 :                aAttribute == nsGkAtoms::y ||
     127                 :                aAttribute == nsGkAtoms::viewBox ||
     128                 :                aAttribute == nsGkAtoms::preserveAspectRatio ||
     129                 :                aAttribute == nsGkAtoms::transform) {
     130                 :       // make sure our cached transform matrix gets (lazily) updated
     131               0 :       mCanvasTM = nsnull;
     132               0 :       UpdateGraphic();
     133                 :     }
     134                 :   }
     135                 : 
     136               0 :   return NS_OK;
     137                 : }
     138                 : 
     139                 : /* virtual */ void
     140               0 : nsSVGForeignObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
     141                 : {
     142               0 :   nsSVGForeignObjectFrameBase::DidSetStyleContext(aOldStyleContext);
     143                 : 
     144                 :   // No need to invalidate before first reflow - that will happen elsewhere.
     145                 :   // Moreover we haven't been initialised properly yet so we may not have the
     146                 :   // right state bits.
     147               0 :   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     148               0 :     UpdateGraphic();
     149                 :   }
     150               0 : }
     151                 : 
     152                 : NS_IMETHODIMP
     153               0 : nsSVGForeignObjectFrame::Reflow(nsPresContext*           aPresContext,
     154                 :                                 nsHTMLReflowMetrics&     aDesiredSize,
     155                 :                                 const nsHTMLReflowState& aReflowState,
     156                 :                                 nsReflowStatus&          aStatus)
     157                 : {
     158                 :   // InitialUpdate and AttributeChanged make sure mRect is up to date before
     159                 :   // we're called (UpdateCoveredRegion sets mRect).
     160                 : 
     161               0 :   NS_ASSERTION(!aReflowState.parentReflowState,
     162                 :                "should only get reflow from being reflow root");
     163               0 :   NS_ASSERTION(aReflowState.ComputedWidth() == GetSize().width &&
     164                 :                aReflowState.ComputedHeight() == GetSize().height,
     165                 :                "reflow roots should be reflowed at existing size and "
     166                 :                "svg.css should ensure we have no padding/border/margin");
     167                 : 
     168               0 :   DoReflow();
     169                 : 
     170               0 :   aDesiredSize.width = aReflowState.ComputedWidth();
     171               0 :   aDesiredSize.height = aReflowState.ComputedHeight();
     172               0 :   aDesiredSize.SetOverflowAreasToDesiredBounds();
     173               0 :   aStatus = NS_FRAME_COMPLETE;
     174                 : 
     175               0 :   return NS_OK;
     176                 : }
     177                 : 
     178                 : void
     179               0 : nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect,
     180                 :                                             nscoord aX, nscoord aY,
     181                 :                                             nsIFrame* aForChild,
     182                 :                                             PRUint32 aFlags)
     183                 : {
     184                 :   // This is called by our descendants when they change.
     185                 : 
     186               0 :   if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
     187               0 :     return;
     188                 : 
     189                 :   nsRegion* region = (aFlags & INVALIDATE_CROSS_DOC)
     190               0 :     ? &mSubDocDirtyRegion : &mSameDocDirtyRegion;
     191               0 :   region->Or(*region, aDamageRect + nsPoint(aX, aY));
     192               0 :   FlushDirtyRegion(aFlags);
     193                 : }
     194                 : 
     195                 : 
     196                 : /**
     197                 :  * Returns the app unit canvas bounds of a userspace rect.
     198                 :  *
     199                 :  * @param aToCanvas Transform from userspace to canvas device space.
     200                 :  */
     201                 : static nsRect
     202               0 : ToCanvasBounds(const gfxRect &aUserspaceRect,
     203                 :                const gfxMatrix &aToCanvas,
     204                 :                const nsPresContext *presContext)
     205                 : {
     206                 :   return nsLayoutUtils::RoundGfxRectToAppRect(
     207                 :                           aToCanvas.TransformBounds(aUserspaceRect),
     208               0 :                           presContext->AppUnitsPerDevPixel());
     209                 : }
     210                 : 
     211                 : NS_IMETHODIMP
     212               0 : nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
     213                 :                                   const nsIntRect *aDirtyRect)
     214                 : {
     215               0 :   if (IsDisabled())
     216               0 :     return NS_OK;
     217                 : 
     218               0 :   nsIFrame* kid = GetFirstPrincipalChild();
     219               0 :   if (!kid)
     220               0 :     return NS_OK;
     221                 : 
     222               0 :   gfxMatrix matrixForChildren = GetCanvasTMForChildren();
     223               0 :   gfxMatrix matrix = GetCanvasTM();
     224                 : 
     225               0 :   if (matrixForChildren.IsSingular()) {
     226               0 :     NS_WARNING("Can't render foreignObject element!");
     227               0 :     return NS_ERROR_FAILURE;
     228                 :   }
     229                 : 
     230               0 :   nsRect kidDirtyRect = kid->GetVisualOverflowRect();
     231                 : 
     232                 :   /* Check if we need to draw anything. */
     233               0 :   if (aDirtyRect) {
     234                 :     // Transform the dirty rect into app units in our userspace.
     235               0 :     gfxMatrix invmatrix = matrix;
     236               0 :     invmatrix.Invert();
     237               0 :     NS_ASSERTION(!invmatrix.IsSingular(),
     238                 :                  "inverse of non-singular matrix should be non-singular");
     239                 : 
     240                 :     gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
     241               0 :                                      aDirtyRect->width, aDirtyRect->height);
     242               0 :     transDirtyRect = invmatrix.TransformBounds(transDirtyRect);
     243                 : 
     244                 :     kidDirtyRect.IntersectRect(kidDirtyRect,
     245                 :       nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect,
     246               0 :                        PresContext()->AppUnitsPerCSSPixel()));
     247                 : 
     248                 :     // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect,
     249                 :     // not with kidDirtyRect. I.e.
     250                 :     // PRInt32 appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
     251                 :     // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)
     252               0 :     if (kidDirtyRect.IsEmpty())
     253               0 :       return NS_OK;
     254                 :   }
     255                 : 
     256               0 :   gfxContext *gfx = aContext->ThebesContext();
     257                 : 
     258               0 :   gfx->Save();
     259                 : 
     260               0 :   if (GetStyleDisplay()->IsScrollableOverflow()) {
     261                 :     float x, y, width, height;
     262                 :     static_cast<nsSVGElement*>(mContent)->
     263               0 :       GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
     264                 : 
     265                 :     gfxRect clipRect =
     266               0 :       nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
     267               0 :     nsSVGUtils::SetClipRect(gfx, matrix, clipRect);
     268                 :   }
     269                 : 
     270               0 :   gfx->Multiply(matrixForChildren);
     271                 : 
     272               0 :   PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM;
     273               0 :   if (SVGAutoRenderState::IsPaintingToWindow(aContext)) {
     274               0 :     flags |= nsLayoutUtils::PAINT_TO_WINDOW;
     275                 :   }
     276               0 :   nsresult rv = nsLayoutUtils::PaintFrame(aContext, kid, nsRegion(kidDirtyRect),
     277               0 :                                           NS_RGBA(0,0,0,0), flags);
     278                 : 
     279               0 :   gfx->Restore();
     280                 : 
     281               0 :   return rv;
     282                 : }
     283                 : 
     284                 : gfx3DMatrix
     285               0 : nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame* aAncestor,
     286                 :                                             nsIFrame **aOutAncestor)
     287                 : {
     288               0 :   NS_PRECONDITION(aOutAncestor, "We need an ancestor to write to!");
     289                 : 
     290                 :   /* Set the ancestor to be the outer frame. */
     291               0 :   *aOutAncestor = nsSVGUtils::GetOuterSVGFrame(this);
     292               0 :   NS_ASSERTION(*aOutAncestor, "How did we end up without an outer frame?");
     293                 : 
     294               0 :   if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) {
     295               0 :     return gfx3DMatrix::From2D(gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
     296                 :   }
     297                 : 
     298                 :   /* Return the matrix back to the root, factoring in the x and y offsets. */
     299               0 :   return gfx3DMatrix::From2D(GetCanvasTMForChildren());
     300                 : }
     301                 :  
     302                 : NS_IMETHODIMP_(nsIFrame*)
     303               0 : nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint)
     304                 : {
     305               0 :   if (IsDisabled() || (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD))
     306               0 :     return nsnull;
     307                 : 
     308               0 :   nsIFrame* kid = GetFirstPrincipalChild();
     309               0 :   if (!kid)
     310               0 :     return nsnull;
     311                 : 
     312                 :   float x, y, width, height;
     313                 :   static_cast<nsSVGElement*>(mContent)->
     314               0 :     GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
     315                 : 
     316               0 :   gfxMatrix tm = GetCanvasTM().Invert();
     317               0 :   if (tm.IsSingular())
     318               0 :     return nsnull;
     319                 :   
     320                 :   // Convert aPoint from app units in canvas space to user space:
     321                 : 
     322               0 :   gfxPoint pt = gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerDevPixel();
     323               0 :   pt = tm.Transform(pt);
     324                 : 
     325               0 :   if (!gfxRect(0.0f, 0.0f, width, height).Contains(pt))
     326               0 :     return nsnull;
     327                 : 
     328                 :   // Convert pt to app units in *local* space:
     329                 : 
     330               0 :   pt = pt * nsPresContext::AppUnitsPerCSSPixel();
     331               0 :   nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
     332                 : 
     333               0 :   nsIFrame *frame = nsLayoutUtils::GetFrameForPoint(kid, point);
     334               0 :   if (frame && nsSVGUtils::HitTestClip(this, aPoint))
     335               0 :     return frame;
     336                 : 
     337               0 :   return nsnull;
     338                 : }
     339                 : 
     340                 : NS_IMETHODIMP_(nsRect)
     341               0 : nsSVGForeignObjectFrame::GetCoveredRegion()
     342                 : {
     343                 :   // See bug 614732 comment 32:
     344                 :   //return nsSVGUtils::TransformFrameRectToOuterSVG(mRect, GetCanvasTM(), PresContext());
     345               0 :   return mCoveredRegion;
     346                 : }
     347                 : 
     348                 : NS_IMETHODIMP
     349               0 : nsSVGForeignObjectFrame::UpdateCoveredRegion()
     350                 : {
     351               0 :   if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
     352               0 :     return NS_ERROR_FAILURE;
     353                 : 
     354                 :   float x, y, w, h;
     355                 :   static_cast<nsSVGForeignObjectElement*>(mContent)->
     356               0 :     GetAnimatedLengthValues(&x, &y, &w, &h, nsnull);
     357                 : 
     358                 :   // If mRect's width or height are negative, reflow blows up! We must clamp!
     359               0 :   if (w < 0.0f) w = 0.0f;
     360               0 :   if (h < 0.0f) h = 0.0f;
     361                 : 
     362                 :   // GetCanvasTM includes the x,y translation
     363                 :   mRect = nsLayoutUtils::RoundGfxRectToAppRect(
     364                 :                            gfxRect(0.0, 0.0, w, h),
     365               0 :                            PresContext()->AppUnitsPerCSSPixel());
     366               0 :   mCoveredRegion = ToCanvasBounds(gfxRect(0.0, 0.0, w, h), GetCanvasTM(), PresContext());
     367                 : 
     368               0 :   return NS_OK;
     369                 : }
     370                 : 
     371                 : NS_IMETHODIMP
     372               0 : nsSVGForeignObjectFrame::InitialUpdate()
     373                 : {
     374               0 :   NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW,
     375                 :                "Yikes! We've been called already! Hopefully we weren't called "
     376                 :                "before our nsSVGOuterSVGFrame's initial Reflow()!!!");
     377                 : 
     378               0 :   UpdateCoveredRegion();
     379                 : 
     380                 :   // Make sure to not allow interrupts if we're not being reflown as a root
     381               0 :   nsPresContext::InterruptPreventer noInterrupts(PresContext());
     382               0 :   DoReflow();
     383                 : 
     384               0 :   NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
     385                 :                "We don't actually participate in reflow");
     386                 :   
     387                 :   // Do unset the various reflow bits, though.
     388                 :   mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
     389               0 :               NS_FRAME_HAS_DIRTY_CHILDREN);
     390                 : 
     391               0 :   return NS_OK;
     392                 : }
     393                 : 
     394                 : void
     395               0 : nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags)
     396                 : {
     397               0 :   NS_ABORT_IF_FALSE(!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS) ||
     398                 :                     (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
     399                 :                     "Must be NS_STATE_SVG_NONDISPLAY_CHILD!");
     400                 : 
     401               0 :   NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
     402                 :                     "Invalidation logic may need adjusting");
     403                 : 
     404               0 :   bool reflow = false;
     405                 : 
     406               0 :   if (aFlags & TRANSFORM_CHANGED) {
     407                 :     // In an ideal world we would reflow when our CTM changes. This is because
     408                 :     // glyph metrics do not necessarily scale uniformly with change in scale
     409                 :     // and, as a result, CTM changes may require text to break at different
     410                 :     // points. The problem would be how to keep performance acceptable when
     411                 :     // e.g. the transform of an ancestor is animated.
     412                 :     // We also seem to get some sort of infinite loop post bug 421584 if we
     413                 :     // reflow.
     414               0 :     mCanvasTM = nsnull;
     415               0 :     if (!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS)) {
     416               0 :       UpdateGraphic();
     417                 :     }
     418                 : 
     419               0 :   } else if (aFlags & COORD_CONTEXT_CHANGED) {
     420                 :     nsSVGForeignObjectElement *fO =
     421               0 :       static_cast<nsSVGForeignObjectElement*>(mContent);
     422                 :     // Coordinate context changes affect mCanvasTM if we have a
     423                 :     // percentage 'x' or 'y'
     424               0 :     if (fO->mLengthAttributes[nsSVGForeignObjectElement::X].IsPercentage() ||
     425               0 :         fO->mLengthAttributes[nsSVGForeignObjectElement::Y].IsPercentage()) {
     426               0 :       mCanvasTM = nsnull;
     427                 :     }
     428                 :     // Our coordinate context's width/height has changed. If we have a
     429                 :     // percentage width/height our dimensions will change so we must reflow.
     430               0 :     if (fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].IsPercentage() ||
     431               0 :         fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].IsPercentage()) {
     432               0 :       reflow = true;
     433                 :     }
     434                 :   }
     435                 : 
     436               0 :   if (reflow) {
     437                 :     // If we're called while the PresShell is handling reflow events then we
     438                 :     // must have been called as a result of the NotifyViewportChange() call in
     439                 :     // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
     440                 :     // at this point (i.e. during reflow) because it could confuse the
     441                 :     // PresShell and prevent it from reflowing us properly in future. Besides
     442                 :     // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
     443                 :     // synchronously, so there's no need.
     444               0 :     if (!PresContext()->PresShell()->IsReflowLocked()) {
     445               0 :       UpdateGraphic(); // update mRect before requesting reflow
     446               0 :       RequestReflow(nsIPresShell::eResize);
     447                 :     }
     448                 :   }
     449               0 : }
     450                 : 
     451                 : void
     452               0 : nsSVGForeignObjectFrame::NotifyRedrawSuspended()
     453                 : {
     454               0 :   AddStateBits(NS_STATE_SVG_REDRAW_SUSPENDED);
     455               0 : }
     456                 : 
     457                 : void
     458               0 : nsSVGForeignObjectFrame::NotifyRedrawUnsuspended()
     459                 : {
     460               0 :   RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED);
     461                 : 
     462               0 :   if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
     463               0 :     if (GetStateBits() & NS_STATE_SVG_DIRTY) {
     464               0 :       UpdateGraphic(); // invalidate our entire area
     465                 :     } else {
     466               0 :       FlushDirtyRegion(0); // only invalidate areas dirtied by our descendants
     467                 :     }
     468                 :   }
     469               0 : }
     470                 : 
     471                 : gfxRect
     472               0 : nsSVGForeignObjectFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace,
     473                 :                                              PRUint32 aFlags)
     474                 : {
     475                 :   nsSVGForeignObjectElement *content =
     476               0 :     static_cast<nsSVGForeignObjectElement*>(mContent);
     477                 : 
     478                 :   float x, y, w, h;
     479               0 :   content->GetAnimatedLengthValues(&x, &y, &w, &h, nsnull);
     480                 : 
     481               0 :   if (w < 0.0f) w = 0.0f;
     482               0 :   if (h < 0.0f) h = 0.0f;
     483                 : 
     484               0 :   if (aToBBoxUserspace.IsSingular()) {
     485                 :     // XXX ReportToConsole
     486               0 :     return gfxRect(0.0, 0.0, 0.0, 0.0);
     487                 :   }
     488               0 :   return aToBBoxUserspace.TransformBounds(gfxRect(0.0, 0.0, w, h));
     489                 : }
     490                 : 
     491                 : //----------------------------------------------------------------------
     492                 : 
     493                 : gfxMatrix
     494               0 : nsSVGForeignObjectFrame::GetCanvasTM()
     495                 : {
     496               0 :   if (!mCanvasTM) {
     497               0 :     NS_ASSERTION(mParent, "null parent");
     498                 : 
     499               0 :     nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(mParent);
     500                 :     nsSVGForeignObjectElement *content =
     501               0 :       static_cast<nsSVGForeignObjectElement*>(mContent);
     502                 : 
     503               0 :     gfxMatrix tm = content->PrependLocalTransformsTo(parent->GetCanvasTM());
     504                 : 
     505               0 :     mCanvasTM = new gfxMatrix(tm);
     506                 :   }
     507               0 :   return *mCanvasTM;
     508                 : }
     509                 : 
     510                 : //----------------------------------------------------------------------
     511                 : // Implementation helpers
     512                 : 
     513                 : gfxMatrix
     514               0 : nsSVGForeignObjectFrame::GetCanvasTMForChildren()
     515                 : {
     516               0 :   float cssPxPerDevPx = PresContext()->
     517               0 :     AppUnitsToFloatCSSPixels(PresContext()->AppUnitsPerDevPixel());
     518                 : 
     519               0 :   return GetCanvasTM().Scale(cssPxPerDevPx, cssPxPerDevPx);
     520                 : }
     521                 : 
     522               0 : void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType)
     523                 : {
     524               0 :   if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
     525                 :     // If we haven't had an InitialUpdate yet, nothing to do.
     526               0 :     return;
     527                 : 
     528               0 :   nsIFrame* kid = GetFirstPrincipalChild();
     529               0 :   if (!kid)
     530               0 :     return;
     531                 : 
     532               0 :   PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
     533                 : }
     534                 : 
     535               0 : void nsSVGForeignObjectFrame::UpdateGraphic()
     536                 : {
     537               0 :   nsSVGUtils::UpdateGraphic(this);
     538                 : 
     539                 :   // We just invalidated our entire area, so clear the caches of areas dirtied
     540                 :   // by our descendants:
     541               0 :   mSameDocDirtyRegion.SetEmpty();
     542               0 :   mSubDocDirtyRegion.SetEmpty();
     543               0 : }
     544                 : 
     545                 : void
     546               0 : nsSVGForeignObjectFrame::MaybeReflowFromOuterSVGFrame()
     547                 : {
     548                 :   // If IsDisabled() is true, then we know that our DoReflow() call will return
     549                 :   // early, leaving us with a marked-dirty but not-reflowed kid. That'd be bad;
     550                 :   // it'd mean that all future calls to this method would be doomed to take the
     551                 :   // NS_FRAME_IS_DIRTY early-return below. To avoid that problem, we need to
     552                 :   // bail out *before* we mark our kid as dirty.
     553               0 :   if (IsDisabled()) {
     554               0 :     return;
     555                 :   }
     556                 : 
     557               0 :   nsIFrame* kid = GetFirstPrincipalChild();
     558                 : 
     559                 :   // If we're already scheduled to reflow (if we or our kid is dirty) we don't
     560                 :   // want to reflow now or else our presShell will do extra work trying to
     561                 :   // reflow us a second time. (It will also complain if it finds that a reflow
     562                 :   // root scheduled for reflow isn't dirty).
     563                 : 
     564               0 :   if (kid->GetStateBits() & NS_FRAME_IS_DIRTY) {
     565               0 :     return;
     566                 :   }
     567               0 :   kid->AddStateBits(NS_FRAME_IS_DIRTY); // we must be fully marked dirty
     568               0 :   if (kid->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) {
     569               0 :     return;
     570                 :   }
     571                 : 
     572                 :   // Make sure to not allow interrupts if we're not being reflown as a root
     573               0 :   nsPresContext::InterruptPreventer noInterrupts(PresContext());
     574               0 :   DoReflow();
     575                 : }
     576                 : 
     577                 : void
     578               0 : nsSVGForeignObjectFrame::DoReflow()
     579                 : {
     580               0 :   NS_ASSERTION(!(nsSVGUtils::GetOuterSVGFrame(this)->
     581                 :                              GetStateBits() & NS_FRAME_FIRST_REFLOW),
     582                 :                "Calling InitialUpdate too early - must not call DoReflow!!!");
     583                 : 
     584                 :   // Skip reflow if we're zero-sized, unless this is our first reflow.
     585               0 :   if (IsDisabled() &&
     586               0 :       !(GetStateBits() & NS_FRAME_FIRST_REFLOW))
     587               0 :     return;
     588                 : 
     589               0 :   if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
     590               0 :     return;
     591                 : 
     592               0 :   nsPresContext *presContext = PresContext();
     593               0 :   nsIFrame* kid = GetFirstPrincipalChild();
     594               0 :   if (!kid)
     595               0 :     return;
     596                 : 
     597                 :   // initiate a synchronous reflow here and now:  
     598               0 :   nsIPresShell* presShell = presContext->PresShell();
     599               0 :   NS_ASSERTION(presShell, "null presShell");
     600                 :   nsRefPtr<nsRenderingContext> renderingContext =
     601               0 :     presShell->GetReferenceRenderingContext();
     602               0 :   if (!renderingContext)
     603                 :     return;
     604                 : 
     605                 :   nsSVGForeignObjectElement *fO = static_cast<nsSVGForeignObjectElement*>
     606               0 :                                              (mContent);
     607                 : 
     608                 :   float width =
     609               0 :     fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].GetAnimValue(fO);
     610                 :   float height =
     611               0 :     fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].GetAnimValue(fO);
     612                 : 
     613                 :   // Clamp height & width to be non-negative (to match UpdateCoveredRegion).
     614               0 :   width = NS_MAX(width, 0.0f);
     615               0 :   height = NS_MAX(height, 0.0f);
     616                 : 
     617                 :   nsSize size(nsPresContext::CSSPixelsToAppUnits(width),
     618               0 :               nsPresContext::CSSPixelsToAppUnits(height));
     619                 : 
     620               0 :   mInReflow = true;
     621                 : 
     622                 :   nsHTMLReflowState reflowState(presContext, kid,
     623                 :                                 renderingContext,
     624               0 :                                 nsSize(size.width, NS_UNCONSTRAINEDSIZE));
     625               0 :   nsHTMLReflowMetrics desiredSize;
     626                 :   nsReflowStatus status;
     627                 : 
     628                 :   // We don't use size.height above because that tells the child to do
     629                 :   // page/column breaking at that height.
     630               0 :   NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0, 0, 0, 0) &&
     631                 :                reflowState.mComputedMargin == nsMargin(0, 0, 0, 0),
     632                 :                "style system should ensure that :-moz-svg-foreign-content "
     633                 :                "does not get styled");
     634               0 :   NS_ASSERTION(reflowState.ComputedWidth() == size.width,
     635                 :                "reflow state made child wrong size");
     636               0 :   reflowState.SetComputedHeight(size.height);
     637                 :   
     638                 :   ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0,
     639               0 :               NS_FRAME_NO_MOVE_FRAME, status);
     640               0 :   NS_ASSERTION(size.width == desiredSize.width &&
     641                 :                size.height == desiredSize.height, "unexpected size");
     642                 :   FinishReflowChild(kid, presContext, &reflowState, desiredSize, 0, 0,
     643               0 :                     NS_FRAME_NO_MOVE_FRAME);
     644                 :   
     645               0 :   mInReflow = false;
     646               0 :   FlushDirtyRegion(0);
     647                 : }
     648                 : 
     649                 : void
     650               0 : nsSVGForeignObjectFrame::InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter,
     651                 :     const nsRect& aRect, PRUint32 aFlags)
     652                 : {
     653               0 :   if (aRect.IsEmpty())
     654               0 :     return;
     655                 : 
     656                 :   // Don't invalidate areas outside our bounds:
     657               0 :   nsRect rect = aRect.Intersect(mRect);
     658               0 :   if (rect.IsEmpty())
     659                 :     return;
     660                 : 
     661                 :   // The areas dirtied by children are in app units, relative to this frame.
     662                 :   // We need to convert the rect from app units in our userspace to app units
     663                 :   // relative to our nsSVGOuterSVGFrame's content rect.
     664                 : 
     665               0 :   gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
     666               0 :   r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
     667               0 :   rect = ToCanvasBounds(r, GetCanvasTM(), PresContext());
     668               0 :   rect = nsSVGUtils::FindFilterInvalidation(this, rect);
     669               0 :   aOuter->InvalidateWithFlags(rect, aFlags);
     670                 : }
     671                 : 
     672                 : void
     673               0 : nsSVGForeignObjectFrame::FlushDirtyRegion(PRUint32 aFlags)
     674                 : {
     675               0 :   if ((mSameDocDirtyRegion.IsEmpty() && mSubDocDirtyRegion.IsEmpty()) ||
     676                 :       mInReflow ||
     677               0 :       (GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED))
     678               0 :     return;
     679                 : 
     680               0 :   nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
     681               0 :   if (!outerSVGFrame) {
     682               0 :     NS_ERROR("null outerSVGFrame");
     683               0 :     return;
     684                 :   }
     685                 : 
     686               0 :   InvalidateDirtyRect(outerSVGFrame, mSameDocDirtyRegion.GetBounds(), aFlags);
     687               0 :   InvalidateDirtyRect(outerSVGFrame, mSubDocDirtyRegion.GetBounds(),
     688               0 :                       aFlags | INVALIDATE_CROSS_DOC);
     689                 : 
     690               0 :   mSameDocDirtyRegion.SetEmpty();
     691               0 :   mSubDocDirtyRegion.SetEmpty();
     692                 : }

Generated by: LCOV version 1.7