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.

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

mercurial