layout/svg/nsSVGSwitchFrame.cpp

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

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

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

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 // Keep in (case-insensitive) order:
     7 #include "gfxRect.h"
     8 #include "nsSVGEffects.h"
     9 #include "nsSVGGFrame.h"
    10 #include "mozilla/dom/SVGSwitchElement.h"
    11 #include "nsSVGUtils.h"
    13 class nsRenderingContext;
    15 using namespace mozilla::gfx;
    17 typedef nsSVGGFrame nsSVGSwitchFrameBase;
    19 class nsSVGSwitchFrame : public nsSVGSwitchFrameBase
    20 {
    21   friend nsIFrame*
    22   NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
    23 protected:
    24   nsSVGSwitchFrame(nsStyleContext* aContext) :
    25     nsSVGSwitchFrameBase(aContext) {}
    27 public:
    28   NS_DECL_FRAMEARENA_HELPERS
    30 #ifdef DEBUG
    31   virtual void Init(nsIContent*      aContent,
    32                     nsIFrame*        aParent,
    33                     nsIFrame*        aPrevInFlow) MOZ_OVERRIDE;
    34 #endif
    36   /**
    37    * Get the "type" of the frame
    38    *
    39    * @see nsGkAtoms::svgSwitchFrame
    40    */
    41   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
    43 #ifdef DEBUG_FRAME_DUMP
    44   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE
    45   {
    46     return MakeFrameName(NS_LITERAL_STRING("SVGSwitch"), aResult);
    47   }
    48 #endif
    50   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    51                                 const nsRect&           aDirtyRect,
    52                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
    54   // nsISVGChildFrame interface:
    55   virtual nsresult PaintSVG(nsRenderingContext* aContext,
    56                             const nsIntRect *aDirtyRect,
    57                             nsIFrame* aTransformRoot) MOZ_OVERRIDE;
    58   nsIFrame* GetFrameForPoint(const nsPoint &aPoint) MOZ_OVERRIDE;
    59   nsRect GetCoveredRegion() MOZ_OVERRIDE;
    60   virtual void ReflowSVG() MOZ_OVERRIDE;
    61   virtual SVGBBox GetBBoxContribution(const Matrix &aToBBoxUserspace,
    62                                       uint32_t aFlags) MOZ_OVERRIDE;
    64 private:
    65   nsIFrame *GetActiveChildFrame();
    66 };
    68 //----------------------------------------------------------------------
    69 // Implementation
    71 nsIFrame*
    72 NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    73 {  
    74   return new (aPresShell) nsSVGSwitchFrame(aContext);
    75 }
    77 NS_IMPL_FRAMEARENA_HELPERS(nsSVGSwitchFrame)
    79 #ifdef DEBUG
    80 void
    81 nsSVGSwitchFrame::Init(nsIContent* aContent,
    82                        nsIFrame* aParent,
    83                        nsIFrame* aPrevInFlow)
    84 {
    85   NS_ASSERTION(aContent->IsSVG(nsGkAtoms::svgSwitch),
    86                "Content is not an SVG switch");
    88   nsSVGSwitchFrameBase::Init(aContent, aParent, aPrevInFlow);
    89 }
    90 #endif /* DEBUG */
    92 nsIAtom *
    93 nsSVGSwitchFrame::GetType() const
    94 {
    95   return nsGkAtoms::svgSwitchFrame;
    96 }
    98 void
    99 nsSVGSwitchFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   100                                    const nsRect&           aDirtyRect,
   101                                    const nsDisplayListSet& aLists)
   102 {
   103   nsIFrame* kid = GetActiveChildFrame();
   104   if (kid) {
   105     BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   106   }
   107 }
   109 nsresult
   110 nsSVGSwitchFrame::PaintSVG(nsRenderingContext* aContext,
   111                            const nsIntRect *aDirtyRect,
   112                            nsIFrame* aTransformRoot)
   113 {
   114   NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
   115                (mState & NS_FRAME_IS_NONDISPLAY),
   116                "If display lists are enabled, only painting of non-display "
   117                "SVG should take this code path");
   119   if (StyleDisplay()->mOpacity == 0.0)
   120     return NS_OK;
   122   nsIFrame *kid = GetActiveChildFrame();
   123   if (kid) {
   124     nsSVGUtils::PaintFrameWithEffects(aContext, aDirtyRect, kid, aTransformRoot);
   125   }
   126   return NS_OK;
   127 }
   130 nsIFrame*
   131 nsSVGSwitchFrame::GetFrameForPoint(const nsPoint &aPoint)
   132 {
   133   NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
   134                (mState & NS_FRAME_IS_NONDISPLAY),
   135                "If display lists are enabled, only hit-testing of non-display "
   136                "SVG should take this code path");
   138   nsIFrame *kid = GetActiveChildFrame();
   139   nsISVGChildFrame* svgFrame = do_QueryFrame(kid);
   140   if (svgFrame) {
   141     return svgFrame->GetFrameForPoint(aPoint);
   142   }
   144   return nullptr;
   145 }
   147 nsRect
   148 nsSVGSwitchFrame::GetCoveredRegion()
   149 {
   150   nsRect rect;
   152   nsIFrame *kid = GetActiveChildFrame();
   153   nsISVGChildFrame* child = do_QueryFrame(kid);
   154   if (child) {
   155     rect = child->GetCoveredRegion();
   156   }
   157   return rect;
   158 }
   160 void
   161 nsSVGSwitchFrame::ReflowSVG()
   162 {
   163   NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
   164                "This call is probably a wasteful mistake");
   166   NS_ABORT_IF_FALSE(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
   167                     "ReflowSVG mechanism not designed for this");
   169   if (!nsSVGUtils::NeedsReflowSVG(this)) {
   170     return;
   171   }
   173   // If the NS_FRAME_FIRST_REFLOW bit has been removed from our parent frame,
   174   // then our outer-<svg> has previously had its initial reflow. In that case
   175   // we need to make sure that that bit has been removed from ourself _before_
   176   // recursing over our children to ensure that they know too. Otherwise, we
   177   // need to remove it _after_ recursing over our children so that they know
   178   // the initial reflow is currently underway.
   180   bool isFirstReflow = (mState & NS_FRAME_FIRST_REFLOW);
   182   bool outerSVGHasHadFirstReflow =
   183     (GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) == 0;
   185   if (outerSVGHasHadFirstReflow) {
   186     mState &= ~NS_FRAME_FIRST_REFLOW; // tell our children
   187   }
   189   nsOverflowAreas overflowRects;
   191   nsIFrame *child = GetActiveChildFrame();
   192   nsISVGChildFrame* svgChild = do_QueryFrame(child);
   193   if (svgChild) {
   194     NS_ABORT_IF_FALSE(!(child->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
   195                       "Check for this explicitly in the |if|, then");
   196     svgChild->ReflowSVG();
   198     // We build up our child frame overflows here instead of using
   199     // nsLayoutUtils::UnionChildOverflow since SVG frame's all use the same
   200     // frame list, and we're iterating over that list now anyway.
   201     ConsiderChildOverflow(overflowRects, child);
   202   }
   204   if (isFirstReflow) {
   205     // Make sure we have our filter property (if any) before calling
   206     // FinishAndStoreOverflow (subsequent filter changes are handled off
   207     // nsChangeHint_UpdateEffects):
   208     nsSVGEffects::UpdateEffects(this);
   209   }
   211   FinishAndStoreOverflow(overflowRects, mRect.Size());
   213   // Remove state bits after FinishAndStoreOverflow so that it doesn't
   214   // invalidate on first reflow:
   215   mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
   216               NS_FRAME_HAS_DIRTY_CHILDREN);
   217 }
   219 SVGBBox
   220 nsSVGSwitchFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
   221                                       uint32_t aFlags)
   222 {
   223   nsIFrame* kid = GetActiveChildFrame();
   224   nsISVGChildFrame* svgKid = do_QueryFrame(kid);
   225   if (svgKid) {
   226     nsIContent *content = kid->GetContent();
   227     gfxMatrix transform = ThebesMatrix(aToBBoxUserspace);
   228     if (content->IsSVG()) {
   229       transform = static_cast<nsSVGElement*>(content)->
   230                     PrependLocalTransformsTo(transform);
   231     }
   232     return svgKid->GetBBoxContribution(ToMatrix(transform), aFlags);
   233   }
   234   return SVGBBox();
   235 }
   237 nsIFrame *
   238 nsSVGSwitchFrame::GetActiveChildFrame()
   239 {
   240   nsIContent *activeChild =
   241     static_cast<mozilla::dom::SVGSwitchElement*>(mContent)->GetActiveChild();
   243   if (activeChild) {
   244     for (nsIFrame* kid = mFrames.FirstChild(); kid;
   245          kid = kid->GetNextSibling()) {
   247       if (activeChild == kid->GetContent()) {
   248         return kid;
   249       }
   250     }
   251   }
   252   return nullptr;
   253 }

mercurial