LCOV - code coverage report
Current view: top level - layout/svg - nsSVGUseFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 37 89 41.6 %
Date: 2017-07-14 16:53:18 Functions: 9 15 60.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13