LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGOuterSVGFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 296 3 1.0 %
Date: 2012-06-02 Functions: 44 3 6.8 %

       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 "nsSVGOuterSVGFrame.h"
      40                 : #include "nsIDOMSVGSVGElement.h"
      41                 : #include "nsSVGSVGElement.h"
      42                 : #include "nsSVGTextFrame.h"
      43                 : #include "nsSVGForeignObjectFrame.h"
      44                 : #include "DOMSVGTests.h"
      45                 : #include "nsDisplayList.h"
      46                 : #include "nsStubMutationObserver.h"
      47                 : #include "gfxContext.h"
      48                 : #include "gfxMatrix.h"
      49                 : #include "gfxRect.h"
      50                 : #include "nsIContentViewer.h"
      51                 : #include "nsIDocShell.h"
      52                 : #include "nsIDOMDocument.h"
      53                 : #include "nsIDOMWindow.h"
      54                 : #include "nsPIDOMWindow.h"
      55                 : #include "nsIObjectLoadingContent.h"
      56                 : #include "nsIInterfaceRequestorUtils.h"
      57                 : 
      58                 : namespace dom = mozilla::dom;
      59                 : 
      60                 : class nsSVGMutationObserver : public nsStubMutationObserver
      61            1464 : {
      62                 : public:
      63                 :   // nsIMutationObserver interface
      64                 :   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
      65                 : 
      66                 :   // nsISupports interface:
      67                 :   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
      68                 : private:
      69               0 :   NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
      70               0 :   NS_IMETHOD_(nsrefcnt) Release() { return 1; }
      71                 : 
      72                 :   static void UpdateTextFragmentTrees(nsIFrame *aFrame);
      73                 : };
      74                 : 
      75                 : //----------------------------------------------------------------------
      76                 : // nsISupports methods
      77                 : 
      78               0 : NS_INTERFACE_MAP_BEGIN(nsSVGMutationObserver)
      79               0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
      80               0 : NS_INTERFACE_MAP_END
      81                 : 
      82            1464 : static nsSVGMutationObserver sSVGMutationObserver;
      83                 : 
      84                 : //----------------------------------------------------------------------
      85                 : // nsIMutationObserver methods
      86                 : 
      87                 : void
      88               0 : nsSVGMutationObserver::AttributeChanged(nsIDocument* aDocument,
      89                 :                                         dom::Element* aElement,
      90                 :                                         PRInt32 aNameSpaceID,
      91                 :                                         nsIAtom* aAttribute,
      92                 :                                         PRInt32 aModType)
      93                 : {
      94               0 :   if (aNameSpaceID != kNameSpaceID_XML || aAttribute != nsGkAtoms::space) {
      95               0 :     return;
      96                 :   }
      97                 : 
      98               0 :   nsIFrame* frame = aElement->GetPrimaryFrame();
      99               0 :   if (!frame) {
     100               0 :     return;
     101                 :   }
     102                 : 
     103                 :   // is the content a child of a text element
     104               0 :   nsSVGTextContainerFrame* containerFrame = do_QueryFrame(frame);
     105               0 :   if (containerFrame) {
     106               0 :     containerFrame->NotifyGlyphMetricsChange();
     107               0 :     return;
     108                 :   }
     109                 :   // if not, are there text elements amongst its descendents
     110               0 :   UpdateTextFragmentTrees(frame);
     111                 : }
     112                 : 
     113                 : //----------------------------------------------------------------------
     114                 : // Implementation helpers
     115                 : 
     116                 : void
     117               0 : nsSVGMutationObserver::UpdateTextFragmentTrees(nsIFrame *aFrame)
     118                 : {
     119               0 :   nsIFrame* kid = aFrame->GetFirstPrincipalChild();
     120               0 :   while (kid) {
     121               0 :     if (kid->GetType() == nsGkAtoms::svgTextFrame) {
     122               0 :       nsSVGTextFrame* textFrame = static_cast<nsSVGTextFrame*>(kid);
     123               0 :       textFrame->NotifyGlyphMetricsChange();
     124                 :     } else {
     125               0 :       UpdateTextFragmentTrees(kid);
     126                 :     }
     127               0 :     kid = kid->GetNextSibling();
     128                 :   }
     129               0 : }
     130                 : 
     131                 : //----------------------------------------------------------------------
     132                 : // Implementation
     133                 : 
     134                 : nsIFrame*
     135               0 : NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     136                 : {  
     137               0 :   return new (aPresShell) nsSVGOuterSVGFrame(aContext);
     138                 : }
     139                 : 
     140               0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGFrame)
     141                 : 
     142               0 : nsSVGOuterSVGFrame::nsSVGOuterSVGFrame(nsStyleContext* aContext)
     143                 :     : nsSVGOuterSVGFrameBase(aContext)
     144                 :     , mRedrawSuspendCount(0)
     145                 :     , mFullZoom(0)
     146                 :     , mViewportInitialized(false)
     147                 : #ifdef XP_MACOSX
     148                 :     , mEnableBitmapFallback(false)
     149                 : #endif
     150               0 :     , mIsRootContent(false)
     151                 : {
     152               0 : }
     153                 : 
     154                 : NS_IMETHODIMP
     155               0 : nsSVGOuterSVGFrame::Init(nsIContent* aContent,
     156                 :                          nsIFrame* aParent,
     157                 :                          nsIFrame* aPrevInFlow)
     158                 : {
     159                 : #ifdef DEBUG
     160               0 :   nsCOMPtr<nsIDOMSVGSVGElement> svgElement = do_QueryInterface(aContent);
     161               0 :   NS_ASSERTION(svgElement, "Content is not an SVG 'svg' element!");
     162                 : #endif
     163                 : 
     164               0 :   AddStateBits(NS_STATE_IS_OUTER_SVG);
     165                 : 
     166                 :   // Check for conditional processing attributes here rather than in
     167                 :   // nsCSSFrameConstructor::FindSVGData because we want to avoid
     168                 :   // simply giving failing outer <svg> elements an nsSVGContainerFrame.
     169               0 :   nsSVGSVGElement *svg = static_cast<nsSVGSVGElement*>(aContent);
     170               0 :   if (!svg->PassesConditionalProcessingTests()) {
     171               0 :     AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
     172                 :   }
     173                 : 
     174               0 :   nsresult rv = nsSVGOuterSVGFrameBase::Init(aContent, aParent, aPrevInFlow);
     175                 : 
     176               0 :   nsIDocument* doc = mContent->GetCurrentDoc();
     177               0 :   if (doc) {
     178                 :     // we only care about our content's zoom and pan values if it's the root element
     179               0 :     if (doc->GetRootElement() == mContent) {
     180               0 :       mIsRootContent = true;
     181                 :     }
     182                 :     // sSVGMutationObserver has the same lifetime as the document so does
     183                 :     // not need to be removed
     184               0 :     doc->AddMutationObserverUnlessExists(&sSVGMutationObserver);
     185                 :   }
     186                 : 
     187               0 :   SuspendRedraw();  // UnsuspendRedraw is in DidReflow
     188                 : 
     189               0 :   return rv;
     190                 : }
     191                 : 
     192                 : //----------------------------------------------------------------------
     193                 : // nsQueryFrame methods
     194                 : 
     195               0 : NS_QUERYFRAME_HEAD(nsSVGOuterSVGFrame)
     196               0 :   NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
     197               0 : NS_QUERYFRAME_TAIL_INHERITING(nsSVGOuterSVGFrameBase)
     198                 : 
     199                 : //----------------------------------------------------------------------
     200                 : // nsIFrame methods
     201                 :   
     202                 : //----------------------------------------------------------------------
     203                 : // reflowing
     204                 : 
     205                 : /* virtual */ nscoord
     206               0 : nsSVGOuterSVGFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
     207                 : {
     208                 :   nscoord result;
     209               0 :   DISPLAY_MIN_WIDTH(this, result);
     210                 : 
     211               0 :   result = nscoord(0);
     212                 : 
     213               0 :   return result;
     214                 : }
     215                 : 
     216                 : /* virtual */ nscoord
     217               0 : nsSVGOuterSVGFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
     218                 : {
     219                 :   nscoord result;
     220               0 :   DISPLAY_PREF_WIDTH(this, result);
     221                 : 
     222               0 :   nsSVGSVGElement *svg = static_cast<nsSVGSVGElement*>(mContent);
     223               0 :   nsSVGLength2 &width = svg->mLengthAttributes[nsSVGSVGElement::WIDTH];
     224                 : 
     225               0 :   if (width.IsPercentage()) {
     226                 :     // It looks like our containing block's width may depend on our width. In
     227                 :     // that case our behavior is undefined according to CSS 2.1 section 10.3.2,
     228                 :     // so return zero.
     229               0 :     result = nscoord(0);
     230                 :   } else {
     231               0 :     result = nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(svg));
     232               0 :     if (result < 0) {
     233               0 :       result = nscoord(0);
     234                 :     }
     235                 :   }
     236                 : 
     237               0 :   return result;
     238                 : }
     239                 : 
     240                 : /* virtual */ nsIFrame::IntrinsicSize
     241               0 : nsSVGOuterSVGFrame::GetIntrinsicSize()
     242                 : {
     243                 :   // XXXjwatt Note that here we want to return the CSS width/height if they're
     244                 :   // specified and we're embedded inside an nsIObjectLoadingContent.
     245                 : 
     246               0 :   IntrinsicSize intrinsicSize;
     247                 : 
     248               0 :   nsSVGSVGElement *content = static_cast<nsSVGSVGElement*>(mContent);
     249               0 :   nsSVGLength2 &width  = content->mLengthAttributes[nsSVGSVGElement::WIDTH];
     250               0 :   nsSVGLength2 &height = content->mLengthAttributes[nsSVGSVGElement::HEIGHT];
     251                 : 
     252               0 :   if (!width.IsPercentage()) {
     253               0 :     nscoord val = nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(content));
     254               0 :     if (val < 0) val = 0;
     255               0 :     intrinsicSize.width.SetCoordValue(val);
     256                 :   }
     257                 : 
     258               0 :   if (!height.IsPercentage()) {
     259               0 :     nscoord val = nsPresContext::CSSPixelsToAppUnits(height.GetAnimValue(content));
     260               0 :     if (val < 0) val = 0;
     261               0 :     intrinsicSize.height.SetCoordValue(val);
     262                 :   }
     263                 : 
     264                 :   return intrinsicSize;
     265                 : }
     266                 : 
     267                 : /* virtual */ nsSize
     268               0 : nsSVGOuterSVGFrame::GetIntrinsicRatio()
     269                 : {
     270                 :   // We only have an intrinsic size/ratio if our width and height attributes
     271                 :   // are both specified and set to non-percentage values, or we have a viewBox
     272                 :   // rect: http://www.w3.org/TR/SVGMobile12/coords.html#IntrinsicSizing
     273                 : 
     274               0 :   nsSVGSVGElement *content = static_cast<nsSVGSVGElement*>(mContent);
     275               0 :   nsSVGLength2 &width  = content->mLengthAttributes[nsSVGSVGElement::WIDTH];
     276               0 :   nsSVGLength2 &height = content->mLengthAttributes[nsSVGSVGElement::HEIGHT];
     277                 : 
     278               0 :   if (!width.IsPercentage() && !height.IsPercentage()) {
     279                 :     nsSize ratio(NSToCoordRoundWithClamp(width.GetAnimValue(content)),
     280               0 :                  NSToCoordRoundWithClamp(height.GetAnimValue(content)));
     281               0 :     if (ratio.width < 0) {
     282               0 :       ratio.width = 0;
     283                 :     }
     284               0 :     if (ratio.height < 0) {
     285               0 :       ratio.height = 0;
     286                 :     }
     287               0 :     return ratio;
     288                 :   }
     289                 : 
     290               0 :   if (content->mViewBox.IsValid()) {
     291               0 :     const nsSVGViewBoxRect viewbox = content->mViewBox.GetAnimValue();
     292               0 :     float viewBoxWidth = viewbox.width;
     293               0 :     float viewBoxHeight = viewbox.height;
     294                 : 
     295               0 :     if (viewBoxWidth < 0.0f) {
     296               0 :       viewBoxWidth = 0.0f;
     297                 :     }
     298               0 :     if (viewBoxHeight < 0.0f) {
     299               0 :       viewBoxHeight = 0.0f;
     300                 :     }
     301                 :     return nsSize(NSToCoordRoundWithClamp(viewBoxWidth),
     302               0 :                   NSToCoordRoundWithClamp(viewBoxHeight));
     303                 :   }
     304                 : 
     305               0 :   return nsSVGOuterSVGFrameBase::GetIntrinsicRatio();
     306                 : }
     307                 : 
     308                 : /* virtual */ nsSize
     309               0 : nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext,
     310                 :                                 nsSize aCBSize, nscoord aAvailableWidth,
     311                 :                                 nsSize aMargin, nsSize aBorder, nsSize aPadding,
     312                 :                                 bool aShrinkWrap)
     313                 : {
     314               0 :   nsSVGSVGElement* content = static_cast<nsSVGSVGElement*>(mContent);
     315                 : 
     316               0 :   IntrinsicSize intrinsicSize = GetIntrinsicSize();
     317                 : 
     318               0 :   if (!mContent->GetParent()) {
     319               0 :     if (IsRootOfImage() || IsRootOfReplacedElementSubDoc()) {
     320                 :       // The embedding element has done the replaced element sizing,
     321                 :       // using our intrinsic dimensions as necessary. We just need to
     322                 :       // fill the viewport.
     323               0 :       return aCBSize;
     324                 :     } else {
     325                 :       // We're the root of a browsing context, so we need to honor
     326                 :       // widths and heights in percentages.  (GetIntrinsicSize() doesn't
     327                 :       // report these since there's no such thing as a percentage
     328                 :       // intrinsic size.)
     329                 :       nsSVGLength2 &width =
     330               0 :         content->mLengthAttributes[nsSVGSVGElement::WIDTH];
     331               0 :       if (width.IsPercentage()) {
     332               0 :         NS_ABORT_IF_FALSE(intrinsicSize.width.GetUnit() == eStyleUnit_None,
     333                 :                           "GetIntrinsicSize should have reported no "
     334                 :                           "intrinsic width");
     335               0 :         float val = width.GetAnimValInSpecifiedUnits() / 100.0f;
     336               0 :         if (val < 0.0f) val = 0.0f;
     337               0 :         intrinsicSize.width.SetCoordValue(val * aCBSize.width);
     338                 :       }
     339                 : 
     340                 :       nsSVGLength2 &height =
     341               0 :         content->mLengthAttributes[nsSVGSVGElement::HEIGHT];
     342               0 :       NS_ASSERTION(aCBSize.height != NS_AUTOHEIGHT,
     343                 :                    "root should not have auto-height containing block");
     344               0 :       if (height.IsPercentage()) {
     345               0 :         NS_ABORT_IF_FALSE(intrinsicSize.height.GetUnit() == eStyleUnit_None,
     346                 :                           "GetIntrinsicSize should have reported no "
     347                 :                           "intrinsic height");
     348               0 :         float val = height.GetAnimValInSpecifiedUnits() / 100.0f;
     349               0 :         if (val < 0.0f) val = 0.0f;
     350               0 :         intrinsicSize.height.SetCoordValue(val * aCBSize.height);
     351                 :       }
     352               0 :       NS_ABORT_IF_FALSE(intrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
     353                 :                         intrinsicSize.width.GetUnit() == eStyleUnit_Coord,
     354                 :                         "We should have just handled the only situation where"
     355                 :                         "we lack an intrinsic height or width.");
     356                 :     }
     357                 :   }
     358                 : 
     359                 :   return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
     360                 :                             aRenderingContext, this,
     361               0 :                             intrinsicSize, GetIntrinsicRatio(), aCBSize,
     362               0 :                             aMargin, aBorder, aPadding);
     363                 : }
     364                 : 
     365                 : NS_IMETHODIMP
     366               0 : nsSVGOuterSVGFrame::Reflow(nsPresContext*           aPresContext,
     367                 :                            nsHTMLReflowMetrics&     aDesiredSize,
     368                 :                            const nsHTMLReflowState& aReflowState,
     369                 :                            nsReflowStatus&          aStatus)
     370                 : {
     371               0 :   DO_GLOBAL_REFLOW_COUNT("nsSVGOuterSVGFrame");
     372               0 :   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
     373               0 :   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     374                 :                   ("enter nsSVGOuterSVGFrame::Reflow: availSize=%d,%d",
     375                 :                   aReflowState.availableWidth, aReflowState.availableHeight));
     376                 : 
     377               0 :   NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
     378                 : 
     379               0 :   aStatus = NS_FRAME_COMPLETE;
     380                 : 
     381               0 :   aDesiredSize.width  = aReflowState.ComputedWidth() +
     382               0 :                           aReflowState.mComputedBorderPadding.LeftRight();
     383               0 :   aDesiredSize.height = aReflowState.ComputedHeight() +
     384               0 :                           aReflowState.mComputedBorderPadding.TopBottom();
     385                 : 
     386               0 :   NS_ASSERTION(!GetPrevInFlow(), "SVG can't currently be broken across pages.");
     387                 : 
     388                 :   // Make sure we scroll if we're too big:
     389                 :   // XXX Use the bounding box of our descendants? (See bug 353460 comment 14.)
     390               0 :   aDesiredSize.SetOverflowAreasToDesiredBounds();
     391               0 :   FinishAndStoreOverflow(&aDesiredSize);
     392                 : 
     393                 :   // If our SVG viewport has changed, update our content and notify.
     394                 :   // http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
     395                 : 
     396                 :   svgFloatSize newViewportSize(
     397                 :     nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedWidth()),
     398               0 :     nsPresContext::AppUnitsToFloatCSSPixels(aReflowState.ComputedHeight()));
     399                 : 
     400               0 :   nsSVGSVGElement *svgElem = static_cast<nsSVGSVGElement*>(mContent);
     401                 : 
     402               0 :   if (newViewportSize != svgElem->GetViewportSize() ||
     403               0 :       mFullZoom != PresContext()->GetFullZoom()) {
     404               0 :     svgElem->SetViewportSize(newViewportSize);
     405               0 :     mViewportInitialized = true;
     406               0 :     mFullZoom = PresContext()->GetFullZoom();
     407               0 :     NotifyViewportChange();
     408                 :   }
     409                 : 
     410               0 :   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     411                 :                   ("exit nsSVGOuterSVGFrame::Reflow: size=%d,%d",
     412                 :                   aDesiredSize.width, aDesiredSize.height));
     413               0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
     414               0 :   return NS_OK;
     415                 : }
     416                 : 
     417                 : static PLDHashOperator
     418               0 : ReflowForeignObject(nsVoidPtrHashKey *aEntry, void* aUserArg)
     419                 : {
     420                 :   static_cast<nsSVGForeignObjectFrame*>
     421               0 :     (const_cast<void*>(aEntry->GetKey()))->MaybeReflowFromOuterSVGFrame();
     422               0 :   return PL_DHASH_NEXT;
     423                 : }
     424                 : 
     425                 : NS_IMETHODIMP
     426               0 : nsSVGOuterSVGFrame::DidReflow(nsPresContext*   aPresContext,
     427                 :                               const nsHTMLReflowState*  aReflowState,
     428                 :                               nsDidReflowStatus aStatus)
     429                 : {
     430               0 :   bool firstReflow = (GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
     431                 : 
     432               0 :   nsresult rv = nsSVGOuterSVGFrameBase::DidReflow(aPresContext,aReflowState,aStatus);
     433                 : 
     434               0 :   if (firstReflow) {
     435                 :     // call InitialUpdate() on all frames:
     436               0 :     nsIFrame* kid = mFrames.FirstChild();
     437               0 :     while (kid) {
     438               0 :       nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
     439               0 :       if (SVGFrame) {
     440               0 :         SVGFrame->InitialUpdate(); 
     441                 :       }
     442               0 :       kid = kid->GetNextSibling();
     443                 :     }
     444                 :     
     445               0 :     UnsuspendRedraw(); // For the SuspendRedraw in InitSVG
     446                 :   } else {
     447                 :     // Now that all viewport establishing descendants have their correct size,
     448                 :     // tell our foreignObject descendants to reflow their children.
     449               0 :     if (mForeignObjectHash.IsInitialized()) {
     450                 : #ifdef DEBUG
     451                 :       PRUint32 count =
     452                 : #endif
     453               0 :         mForeignObjectHash.EnumerateEntries(ReflowForeignObject, nsnull);
     454               0 :       NS_ASSERTION(count == mForeignObjectHash.Count(),
     455                 :                    "We didn't reflow all our nsSVGForeignObjectFrames!");
     456                 :     }
     457                 :   }
     458                 :   
     459               0 :   return rv;
     460                 : }
     461                 : 
     462                 : //----------------------------------------------------------------------
     463                 : // container methods
     464                 : 
     465                 : class nsDisplaySVG : public nsDisplayItem {
     466                 : public:
     467               0 :   nsDisplaySVG(nsDisplayListBuilder* aBuilder,
     468                 :                nsSVGOuterSVGFrame* aFrame) :
     469               0 :     nsDisplayItem(aBuilder, aFrame) {
     470               0 :     MOZ_COUNT_CTOR(nsDisplaySVG);
     471               0 :   }
     472                 : #ifdef NS_BUILD_REFCNT_LOGGING
     473               0 :   virtual ~nsDisplaySVG() {
     474               0 :     MOZ_COUNT_DTOR(nsDisplaySVG);
     475               0 :   }
     476                 : #endif
     477                 : 
     478                 :   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
     479                 :                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
     480                 :   virtual void Paint(nsDisplayListBuilder* aBuilder,
     481                 :                      nsRenderingContext* aCtx);
     482               0 :   NS_DISPLAY_DECL_NAME("SVGEventReceiver", TYPE_SVG_EVENT_RECEIVER)
     483                 : };
     484                 : 
     485                 : void
     486               0 : nsDisplaySVG::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
     487                 :                       HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
     488                 : {
     489               0 :   nsSVGOuterSVGFrame *outerSVGFrame = static_cast<nsSVGOuterSVGFrame*>(mFrame);
     490               0 :   nsRect rectAtOrigin = aRect - ToReferenceFrame();
     491               0 :   nsRect thisRect(nsPoint(0,0), outerSVGFrame->GetSize());
     492               0 :   if (!thisRect.Intersects(rectAtOrigin))
     493                 :     return;
     494                 : 
     495                 :   nsPoint rectCenter(rectAtOrigin.x + rectAtOrigin.width / 2,
     496               0 :                      rectAtOrigin.y + rectAtOrigin.height / 2);
     497                 : 
     498                 :   nsIFrame* frame = nsSVGUtils::HitTestChildren(
     499                 :     outerSVGFrame, rectCenter + outerSVGFrame->GetPosition() -
     500               0 :                    outerSVGFrame->GetContentRect().TopLeft());
     501               0 :   if (frame) {
     502               0 :     aOutFrames->AppendElement(frame);
     503                 :   }
     504                 : }
     505                 : 
     506                 : void
     507               0 : nsDisplaySVG::Paint(nsDisplayListBuilder* aBuilder,
     508                 :                     nsRenderingContext* aContext)
     509                 : {
     510               0 :   nsSVGOuterSVGFrame *frame = static_cast<nsSVGOuterSVGFrame*>(mFrame);
     511                 : 
     512               0 :   if (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
     513               0 :     return;
     514                 : 
     515                 : #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
     516                 :   PRTime start = PR_Now();
     517                 : #endif
     518                 : 
     519               0 :   aContext->PushState();
     520                 : 
     521                 : #ifdef XP_MACOSX
     522                 :   if (frame->BitmapFallbackEnabled()) {
     523                 :     // nquartz fallback paths, which svg tends to trigger, need
     524                 :     // a non-window context target
     525                 :     aContext->ThebesContext()->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
     526                 :   }
     527                 : #endif
     528                 : 
     529               0 :   frame->Paint(aBuilder, aContext, mVisibleRect, ToReferenceFrame());
     530                 : 
     531                 : #ifdef XP_MACOSX
     532                 :   if (frame->BitmapFallbackEnabled()) {
     533                 :     // show the surface we pushed earlier for fallbacks
     534                 :     aContext->ThebesContext()->PopGroupToSource();
     535                 :     aContext->ThebesContext()->Paint();
     536                 :   }
     537                 : 
     538                 :   if (aContext->ThebesContext()->HasError() && !frame->BitmapFallbackEnabled()) {
     539                 :     frame->SetBitmapFallbackEnabled(true);
     540                 :     // It's not really clear what area to invalidate here. We might have
     541                 :     // stuffed up rendering for the entire window in this paint pass,
     542                 :     // so we can't just invalidate our own rect. Invalidate everything
     543                 :     // in sight.
     544                 :     // This won't work for printing, by the way, but failure to print the
     545                 :     // odd document is probably no worse than printing horribly for all
     546                 :     // documents. Better to fix things so we don't need fallback.
     547                 :     nsIFrame* ancestor = frame;
     548                 :     PRUint32 flags = 0;
     549                 :     while (true) {
     550                 :       nsIFrame* next = nsLayoutUtils::GetCrossDocParentFrame(ancestor);
     551                 :       if (!next)
     552                 :         break;
     553                 :       if (ancestor->GetParent() != next) {
     554                 :         // We're crossing a document boundary. Logically, the invalidation is
     555                 :         // being triggered by a subdocument of the root document. This will
     556                 :         // prevent an untrusted root document being told about invalidation
     557                 :         // that happened because a child was using SVG...
     558                 :         flags |= nsIFrame::INVALIDATE_CROSS_DOC;
     559                 :       }
     560                 :       ancestor = next;
     561                 :     }
     562                 :     ancestor->InvalidateWithFlags(nsRect(nsPoint(0, 0), ancestor->GetSize()), flags);
     563                 :   }
     564                 : #endif
     565                 : 
     566               0 :   aContext->PopState();
     567                 : 
     568                 : #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
     569                 :   PRTime end = PR_Now();
     570                 :   printf("SVG Paint Timing: %f ms\n", (end-start)/1000.0);
     571                 : #endif
     572                 : }
     573                 : 
     574                 : // helper
     575                 : static inline bool
     576               0 : DependsOnIntrinsicSize(const nsIFrame* aEmbeddingFrame)
     577                 : {
     578               0 :   const nsStylePosition *pos = aEmbeddingFrame->GetStylePosition();
     579               0 :   const nsStyleCoord &width = pos->mWidth;
     580               0 :   const nsStyleCoord &height = pos->mHeight;
     581                 : 
     582                 :   // XXX it would be nice to know if the size of aEmbeddingFrame's containing
     583                 :   // block depends on aEmbeddingFrame, then we'd know if we can return false
     584                 :   // for eStyleUnit_Percent too.
     585               0 :   return !width.ConvertsToLength() ||
     586               0 :          !height.ConvertsToLength();
     587                 : }
     588                 : 
     589                 : NS_IMETHODIMP
     590               0 : nsSVGOuterSVGFrame::AttributeChanged(PRInt32  aNameSpaceID,
     591                 :                                      nsIAtom* aAttribute,
     592                 :                                      PRInt32  aModType)
     593                 : {
     594               0 :   if (aNameSpaceID == kNameSpaceID_None &&
     595               0 :       !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     596               0 :     if (aAttribute == nsGkAtoms::viewBox ||
     597                 :         aAttribute == nsGkAtoms::preserveAspectRatio ||
     598                 :         aAttribute == nsGkAtoms::transform) {
     599                 : 
     600                 :       // make sure our cached transform matrix gets (lazily) updated
     601               0 :       mCanvasTM = nsnull;
     602                 : 
     603                 :       nsSVGUtils::NotifyChildrenOfSVGChange(
     604                 :           this, aAttribute == nsGkAtoms::viewBox ?
     605               0 :                   TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED : TRANSFORM_CHANGED);
     606                 : 
     607               0 :     } else if (aAttribute == nsGkAtoms::width ||
     608                 :                aAttribute == nsGkAtoms::height) {
     609                 : 
     610                 :         nsIFrame* embeddingFrame;
     611               0 :         if (IsRootOfReplacedElementSubDoc(&embeddingFrame) && embeddingFrame) {
     612               0 :           if (DependsOnIntrinsicSize(embeddingFrame)) {
     613                 :             // Tell embeddingFrame's presShell it needs to be reflowed (which takes
     614                 :             // care of reflowing us too).
     615               0 :             embeddingFrame->PresContext()->PresShell()->
     616               0 :               FrameNeedsReflow(embeddingFrame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     617                 :           }
     618                 :           // else our width and height is overridden - don't reflow anything
     619                 :         } else {
     620                 :           // We are not embedded by reference, so our 'width' and 'height'
     621                 :           // attributes are not overridden - we need to reflow.
     622               0 :           PresContext()->PresShell()->
     623               0 :             FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     624                 :         }
     625                 :     }
     626                 :   }
     627                 : 
     628               0 :   return NS_OK;
     629                 : }
     630                 : 
     631                 : //----------------------------------------------------------------------
     632                 : // painting
     633                 : 
     634                 : NS_IMETHODIMP
     635               0 : nsSVGOuterSVGFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     636                 :                                      const nsRect&           aDirtyRect,
     637                 :                                      const nsDisplayListSet& aLists)
     638                 : {
     639               0 :   nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
     640               0 :   NS_ENSURE_SUCCESS(rv, rv);
     641                 : 
     642                 :   return aLists.Content()->AppendNewToTop(
     643               0 :       new (aBuilder) nsDisplaySVG(aBuilder, this));
     644                 : }
     645                 : 
     646                 : void
     647               0 : nsSVGOuterSVGFrame::Paint(const nsDisplayListBuilder* aBuilder,
     648                 :                           nsRenderingContext* aContext,
     649                 :                           const nsRect& aDirtyRect, nsPoint aPt)
     650                 : {
     651               0 :   nsRect viewportRect = GetContentRect();
     652               0 :   nsPoint viewportOffset = aPt + viewportRect.TopLeft() - GetPosition();
     653               0 :   viewportRect.MoveTo(viewportOffset);
     654                 : 
     655               0 :   nsRect clipRect;
     656               0 :   clipRect.IntersectRect(aDirtyRect, viewportRect);
     657               0 :   aContext->IntersectClip(clipRect);
     658               0 :   aContext->Translate(viewportRect.TopLeft());
     659               0 :   nsRect dirtyRect = clipRect - viewportOffset;
     660                 : 
     661               0 :   nsIntRect dirtyPxRect = dirtyRect.ToOutsidePixels(PresContext()->AppUnitsPerDevPixel());
     662                 : 
     663                 :   // Create an SVGAutoRenderState so we can call SetPaintingToWindow on
     664                 :   // it, but don't change the render mode:
     665               0 :   SVGAutoRenderState state(aContext, SVGAutoRenderState::GetRenderMode(aContext));
     666                 : 
     667               0 :   if (aBuilder->IsPaintingToWindow()) {
     668               0 :     state.SetPaintingToWindow(true);
     669                 :   }
     670                 : 
     671               0 :   nsSVGUtils::PaintFrameWithEffects(aContext, &dirtyPxRect, this);
     672               0 : }
     673                 : 
     674                 : nsSplittableType
     675               0 : nsSVGOuterSVGFrame::GetSplittableType() const
     676                 : {
     677               0 :   return NS_FRAME_NOT_SPLITTABLE;
     678                 : }
     679                 : 
     680                 : nsIAtom *
     681               0 : nsSVGOuterSVGFrame::GetType() const
     682                 : {
     683               0 :   return nsGkAtoms::svgOuterSVGFrame;
     684                 : }
     685                 : 
     686                 : //----------------------------------------------------------------------
     687                 : // nsISVGSVGFrame methods:
     688                 : 
     689                 : void
     690               0 : nsSVGOuterSVGFrame::SuspendRedraw()
     691                 : {
     692               0 :   if (++mRedrawSuspendCount != 1)
     693               0 :     return;
     694                 : 
     695               0 :   nsSVGUtils::NotifyRedrawSuspended(this);
     696                 : }
     697                 : 
     698                 : void
     699               0 : nsSVGOuterSVGFrame::UnsuspendRedraw()
     700                 : {
     701                 :   NS_ASSERTION(mRedrawSuspendCount >=0, "unbalanced suspend count!");
     702                 : 
     703               0 :   if (--mRedrawSuspendCount > 0)
     704               0 :     return;
     705                 : 
     706               0 :   nsSVGUtils::NotifyRedrawUnsuspended(this);
     707                 : }
     708                 : 
     709                 : void
     710               0 : nsSVGOuterSVGFrame::NotifyViewportChange()
     711                 : {
     712                 :   // no point in doing anything when were not init'ed yet:
     713               0 :   if (!mViewportInitialized) {
     714               0 :     return;
     715                 :   }
     716                 : 
     717               0 :   PRUint32 flags = COORD_CONTEXT_CHANGED;
     718                 : 
     719                 :   // viewport changes only affect our transform if we have a viewBox attribute
     720                 : #if 1
     721                 :   {
     722                 : #else
     723                 :   // XXX this caused reftest failures (bug 413960)
     724                 :   if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
     725                 : #endif
     726                 :     // make sure canvas transform matrix gets (lazily) recalculated:
     727               0 :     mCanvasTM = nsnull;
     728                 : 
     729               0 :     flags |= TRANSFORM_CHANGED;
     730                 :   }
     731                 : 
     732                 :   // inform children
     733               0 :   nsSVGUtils::NotifyChildrenOfSVGChange(this, flags);
     734                 : }
     735                 : 
     736                 : //----------------------------------------------------------------------
     737                 : // nsSVGContainerFrame methods:
     738                 : 
     739                 : gfxMatrix
     740               0 : nsSVGOuterSVGFrame::GetCanvasTM()
     741                 : {
     742               0 :   if (!mCanvasTM) {
     743               0 :     nsSVGSVGElement *content = static_cast<nsSVGSVGElement*>(mContent);
     744                 : 
     745                 :     float devPxPerCSSPx =
     746               0 :       1.0f / PresContext()->AppUnitsToFloatCSSPixels(
     747               0 :                                 PresContext()->AppUnitsPerDevPixel());
     748                 : 
     749               0 :     gfxMatrix viewBoxTM = content->GetViewBoxTransform();
     750                 : 
     751               0 :     gfxMatrix zoomPanTM;
     752               0 :     if (mIsRootContent) {
     753               0 :       const nsSVGTranslatePoint& translate = content->GetCurrentTranslate();
     754               0 :       zoomPanTM.Translate(gfxPoint(translate.GetX(), translate.GetY()));
     755               0 :       zoomPanTM.Scale(content->GetCurrentScale(), content->GetCurrentScale());
     756                 :     }
     757                 : 
     758               0 :     gfxMatrix TM = viewBoxTM * zoomPanTM * gfxMatrix().Scale(devPxPerCSSPx, devPxPerCSSPx);
     759               0 :     mCanvasTM = new gfxMatrix(TM);
     760                 :   }
     761               0 :   return *mCanvasTM;
     762                 : }
     763                 : 
     764                 : //----------------------------------------------------------------------
     765                 : // Implementation helpers
     766                 : 
     767                 : void
     768               0 : nsSVGOuterSVGFrame::RegisterForeignObject(nsSVGForeignObjectFrame* aFrame)
     769                 : {
     770               0 :   NS_ASSERTION(aFrame, "Who on earth is calling us?!");
     771                 : 
     772               0 :   if (!mForeignObjectHash.IsInitialized()) {
     773               0 :     if (!mForeignObjectHash.Init()) {
     774               0 :       NS_ERROR("Failed to initialize foreignObject hash.");
     775               0 :       return;
     776                 :     }
     777                 :   }
     778                 : 
     779               0 :   NS_ASSERTION(!mForeignObjectHash.GetEntry(aFrame),
     780                 :                "nsSVGForeignObjectFrame already registered!");
     781                 : 
     782               0 :   mForeignObjectHash.PutEntry(aFrame);
     783                 : 
     784               0 :   NS_ASSERTION(mForeignObjectHash.GetEntry(aFrame),
     785                 :                "Failed to register nsSVGForeignObjectFrame!");
     786                 : }
     787                 : 
     788                 : void
     789               0 : nsSVGOuterSVGFrame::UnregisterForeignObject(nsSVGForeignObjectFrame* aFrame)
     790                 : {
     791               0 :   NS_ASSERTION(aFrame, "Who on earth is calling us?!");
     792               0 :   NS_ASSERTION(mForeignObjectHash.GetEntry(aFrame),
     793                 :                "nsSVGForeignObjectFrame not in registry!");
     794               0 :   return mForeignObjectHash.RemoveEntry(aFrame);
     795                 : }
     796                 : 
     797                 : bool
     798               0 : nsSVGOuterSVGFrame::IsRootOfReplacedElementSubDoc(nsIFrame **aEmbeddingFrame)
     799                 : {
     800               0 :   if (!mContent->GetParent()) {
     801                 :     // Our content is the document element
     802               0 :     nsCOMPtr<nsISupports> container = PresContext()->GetContainer();
     803               0 :     nsCOMPtr<nsIDOMWindow> window = do_GetInterface(container);
     804               0 :     if (window) {
     805               0 :       nsCOMPtr<nsIDOMElement> frameElement;
     806               0 :       window->GetFrameElement(getter_AddRefs(frameElement));
     807               0 :       nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(frameElement);
     808               0 :       if (olc) {
     809                 :         // Our document is inside an HTML 'object', 'embed' or 'applet' element
     810               0 :         if (aEmbeddingFrame) {
     811               0 :           nsCOMPtr<nsIContent> element = do_QueryInterface(frameElement);
     812                 :           *aEmbeddingFrame =
     813               0 :             static_cast<nsGenericElement*>(element.get())->GetPrimaryFrame();
     814               0 :           NS_ASSERTION(*aEmbeddingFrame, "Yikes, no embedding frame!");
     815                 :         }
     816               0 :         return true;
     817                 :       }
     818                 :     }
     819                 :   }
     820               0 :   if (aEmbeddingFrame) {
     821               0 :     *aEmbeddingFrame = nsnull;
     822                 :   }
     823               0 :   return false;
     824                 : }
     825                 : 
     826                 : bool
     827               0 : nsSVGOuterSVGFrame::IsRootOfImage()
     828                 : {
     829               0 :   if (!mContent->GetParent()) {
     830                 :     // Our content is the document element
     831               0 :     nsIDocument* doc = mContent->GetCurrentDoc();
     832               0 :     if (doc && doc->IsBeingUsedAsImage()) {
     833                 :       // Our document is being used as an image
     834               0 :       return true;
     835                 :     }
     836                 :   }
     837                 : 
     838               0 :   return false;
     839            4392 : }

Generated by: LCOV version 1.7