layout/svg/nsSVGUseFrame.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 "nsIAnonymousContentCreator.h"
     8 #include "nsSVGEffects.h"
     9 #include "nsSVGGFrame.h"
    10 #include "mozilla/dom/SVGUseElement.h"
    11 #include "nsContentList.h"
    13 typedef nsSVGGFrame nsSVGUseFrameBase;
    15 using namespace mozilla::dom;
    17 class nsSVGUseFrame : public nsSVGUseFrameBase,
    18                       public nsIAnonymousContentCreator
    19 {
    20   friend nsIFrame*
    21   NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
    23 protected:
    24   nsSVGUseFrame(nsStyleContext* aContext) :
    25     nsSVGUseFrameBase(aContext),
    26     mHasValidDimensions(true)
    27   {}
    29 public:
    30   NS_DECL_QUERYFRAME
    31   NS_DECL_FRAMEARENA_HELPERS
    34   // nsIFrame interface:
    35   virtual void Init(nsIContent*      aContent,
    36                     nsIFrame*        aParent,
    37                     nsIFrame*        aPrevInFlow) MOZ_OVERRIDE;
    39   virtual nsresult  AttributeChanged(int32_t         aNameSpaceID,
    40                                      nsIAtom*        aAttribute,
    41                                      int32_t         aModType) MOZ_OVERRIDE;
    43   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
    45   /**
    46    * Get the "type" of the frame
    47    *
    48    * @see nsGkAtoms::svgUseFrame
    49    */
    50   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
    52   virtual bool IsLeaf() const MOZ_OVERRIDE;
    54 #ifdef DEBUG_FRAME_DUMP
    55   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE
    56   {
    57     return MakeFrameName(NS_LITERAL_STRING("SVGUse"), aResult);
    58   }
    59 #endif
    61   // nsISVGChildFrame interface:
    62   virtual void ReflowSVG() MOZ_OVERRIDE;
    63   virtual void NotifySVGChanged(uint32_t aFlags) MOZ_OVERRIDE;
    65   // nsIAnonymousContentCreator
    66   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) MOZ_OVERRIDE;
    67   virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
    68                                         uint32_t aFilter) MOZ_OVERRIDE;
    70 private:
    71   bool mHasValidDimensions;
    72 };
    74 //----------------------------------------------------------------------
    75 // Implementation
    77 nsIFrame*
    78 NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    79 {
    80   return new (aPresShell) nsSVGUseFrame(aContext);
    81 }
    83 NS_IMPL_FRAMEARENA_HELPERS(nsSVGUseFrame)
    85 nsIAtom *
    86 nsSVGUseFrame::GetType() const
    87 {
    88   return nsGkAtoms::svgUseFrame;
    89 }
    91 //----------------------------------------------------------------------
    92 // nsQueryFrame methods
    94 NS_QUERYFRAME_HEAD(nsSVGUseFrame)
    95   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
    96 NS_QUERYFRAME_TAIL_INHERITING(nsSVGUseFrameBase)
    98 //----------------------------------------------------------------------
    99 // nsIFrame methods:
   101 void
   102 nsSVGUseFrame::Init(nsIContent* aContent,
   103                     nsIFrame* aParent,
   104                     nsIFrame* aPrevInFlow)
   105 {
   106   NS_ASSERTION(aContent->IsSVG(nsGkAtoms::use),
   107                "Content is not an SVG use!");
   109   mHasValidDimensions =
   110     static_cast<SVGUseElement*>(aContent)->HasValidDimensions();
   112   nsSVGUseFrameBase::Init(aContent, aParent, aPrevInFlow);
   113 }
   115 nsresult
   116 nsSVGUseFrame::AttributeChanged(int32_t         aNameSpaceID,
   117                                 nsIAtom*        aAttribute,
   118                                 int32_t         aModType)
   119 {
   120   SVGUseElement *useElement = static_cast<SVGUseElement*>(mContent);
   122   if (aNameSpaceID == kNameSpaceID_None) {
   123     if (aAttribute == nsGkAtoms::x ||
   124         aAttribute == nsGkAtoms::y) {
   125       // make sure our cached transform matrix gets (lazily) updated
   126       mCanvasTM = nullptr;
   127       nsSVGEffects::InvalidateRenderingObservers(this);
   128       nsSVGUtils::ScheduleReflowSVG(this);
   129       nsSVGUtils::NotifyChildrenOfSVGChange(this, TRANSFORM_CHANGED);
   130     } else if (aAttribute == nsGkAtoms::width ||
   131                aAttribute == nsGkAtoms::height) {
   132       bool invalidate = false;
   133       if (mHasValidDimensions != useElement->HasValidDimensions()) {
   134         mHasValidDimensions = !mHasValidDimensions;
   135         invalidate = true;
   136       }
   137       if (useElement->OurWidthAndHeightAreUsed()) {
   138         invalidate = true;
   139         useElement->SyncWidthOrHeight(aAttribute);
   140       }
   141       if (invalidate) {
   142         nsSVGEffects::InvalidateRenderingObservers(this);
   143         nsSVGUtils::ScheduleReflowSVG(this);
   144       }
   145     }
   146   } else if (aNameSpaceID == kNameSpaceID_XLink &&
   147              aAttribute == nsGkAtoms::href) {
   148     // we're changing our nature, clear out the clone information
   149     nsSVGEffects::InvalidateRenderingObservers(this);
   150     nsSVGUtils::ScheduleReflowSVG(this);
   151     useElement->mOriginal = nullptr;
   152     useElement->UnlinkSource();
   153     useElement->TriggerReclone();
   154   }
   156   return nsSVGUseFrameBase::AttributeChanged(aNameSpaceID,
   157                                              aAttribute, aModType);
   158 }
   160 void
   161 nsSVGUseFrame::DestroyFrom(nsIFrame* aDestructRoot)
   162 {
   163   nsRefPtr<SVGUseElement> use = static_cast<SVGUseElement*>(mContent);
   164   nsSVGUseFrameBase::DestroyFrom(aDestructRoot);
   165   use->DestroyAnonymousContent();
   166 }
   168 bool
   169 nsSVGUseFrame::IsLeaf() const
   170 {
   171   return true;
   172 }
   175 //----------------------------------------------------------------------
   176 // nsISVGChildFrame methods
   178 void
   179 nsSVGUseFrame::ReflowSVG()
   180 {
   181   // We only handle x/y offset here, since any width/height that is in force is
   182   // handled by the nsSVGOuterSVGFrame for the anonymous <svg> that will be
   183   // created for that purpose.
   184   float x, y;
   185   static_cast<SVGUseElement*>(mContent)->
   186     GetAnimatedLengthValues(&x, &y, nullptr);
   187   mRect.MoveTo(nsLayoutUtils::RoundGfxRectToAppRect(
   188                  gfxRect(x, y, 0.0, 0.0),
   189                  PresContext()->AppUnitsPerCSSPixel()).TopLeft());
   191   // If we have a filter, we need to invalidate ourselves because filter
   192   // output can change even if none of our descendants need repainting.
   193   if (StyleSVGReset()->HasFilters()) {
   194     InvalidateFrame();
   195   }
   197   nsSVGUseFrameBase::ReflowSVG();
   198 }
   200 void
   201 nsSVGUseFrame::NotifySVGChanged(uint32_t aFlags)
   202 {
   203   if (aFlags & COORD_CONTEXT_CHANGED &&
   204       !(aFlags & TRANSFORM_CHANGED)) {
   205     // Coordinate context changes affect mCanvasTM if we have a
   206     // percentage 'x' or 'y'
   207     SVGUseElement *use = static_cast<SVGUseElement*>(mContent);
   208     if (use->mLengthAttributes[SVGUseElement::ATTR_X].IsPercentage() ||
   209         use->mLengthAttributes[SVGUseElement::ATTR_Y].IsPercentage()) {
   210       aFlags |= TRANSFORM_CHANGED;
   211       // Ancestor changes can't affect how we render from the perspective of
   212       // any rendering observers that we may have, so we don't need to
   213       // invalidate them. We also don't need to invalidate ourself, since our
   214       // changed ancestor will have invalidated its entire area, which includes
   215       // our area.
   216       // For perf reasons we call this before calling NotifySVGChanged() below.
   217       nsSVGUtils::ScheduleReflowSVG(this);
   218     }
   219   }
   221   // We don't remove the TRANSFORM_CHANGED flag here if we have a viewBox or
   222   // non-percentage width/height, since if they're set then they are cloned to
   223   // an anonymous child <svg>, and its nsSVGInnerSVGFrame will do that.
   225   nsSVGUseFrameBase::NotifySVGChanged(aFlags);
   226 }
   228 //----------------------------------------------------------------------
   229 // nsIAnonymousContentCreator methods:
   231 nsresult
   232 nsSVGUseFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
   233 {
   234   SVGUseElement *use = static_cast<SVGUseElement*>(mContent);
   236   nsIContent* clone = use->CreateAnonymousContent();
   237   nsSVGEffects::InvalidateRenderingObservers(this);
   238   if (!clone)
   239     return NS_ERROR_FAILURE;
   240   if (!aElements.AppendElement(clone))
   241     return NS_ERROR_OUT_OF_MEMORY;
   242   return NS_OK;
   243 }
   245 void
   246 nsSVGUseFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
   247                                         uint32_t aFilter)
   248 {
   249   SVGUseElement *use = static_cast<SVGUseElement*>(mContent);
   250   nsIContent* clone = use->GetAnonymousContent();
   251   aElements.MaybeAppendElement(clone);
   252 }

mercurial