layout/svg/nsSVGMarkerFrame.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 // Main header first:
michael@0 7 #include "nsSVGMarkerFrame.h"
michael@0 8
michael@0 9 // Keep others in (case-insensitive) order:
michael@0 10 #include "gfxContext.h"
michael@0 11 #include "nsRenderingContext.h"
michael@0 12 #include "nsSVGEffects.h"
michael@0 13 #include "mozilla/dom/SVGMarkerElement.h"
michael@0 14 #include "nsSVGPathGeometryElement.h"
michael@0 15 #include "nsSVGPathGeometryFrame.h"
michael@0 16
michael@0 17 using namespace mozilla::dom;
michael@0 18 using namespace mozilla::gfx;
michael@0 19
michael@0 20 nsIFrame*
michael@0 21 NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 22 {
michael@0 23 return new (aPresShell) nsSVGMarkerFrame(aContext);
michael@0 24 }
michael@0 25
michael@0 26 NS_IMPL_FRAMEARENA_HELPERS(nsSVGMarkerFrame)
michael@0 27
michael@0 28 //----------------------------------------------------------------------
michael@0 29 // nsIFrame methods:
michael@0 30
michael@0 31 nsresult
michael@0 32 nsSVGMarkerFrame::AttributeChanged(int32_t aNameSpaceID,
michael@0 33 nsIAtom* aAttribute,
michael@0 34 int32_t aModType)
michael@0 35 {
michael@0 36 if (aNameSpaceID == kNameSpaceID_None &&
michael@0 37 (aAttribute == nsGkAtoms::markerUnits ||
michael@0 38 aAttribute == nsGkAtoms::refX ||
michael@0 39 aAttribute == nsGkAtoms::refY ||
michael@0 40 aAttribute == nsGkAtoms::markerWidth ||
michael@0 41 aAttribute == nsGkAtoms::markerHeight ||
michael@0 42 aAttribute == nsGkAtoms::orient ||
michael@0 43 aAttribute == nsGkAtoms::preserveAspectRatio ||
michael@0 44 aAttribute == nsGkAtoms::viewBox)) {
michael@0 45 nsSVGEffects::InvalidateDirectRenderingObservers(this);
michael@0 46 }
michael@0 47
michael@0 48 return nsSVGMarkerFrameBase::AttributeChanged(aNameSpaceID,
michael@0 49 aAttribute, aModType);
michael@0 50 }
michael@0 51
michael@0 52 #ifdef DEBUG
michael@0 53 void
michael@0 54 nsSVGMarkerFrame::Init(nsIContent* aContent,
michael@0 55 nsIFrame* aParent,
michael@0 56 nsIFrame* aPrevInFlow)
michael@0 57 {
michael@0 58 NS_ASSERTION(aContent->IsSVG(nsGkAtoms::marker), "Content is not an SVG marker");
michael@0 59
michael@0 60 nsSVGMarkerFrameBase::Init(aContent, aParent, aPrevInFlow);
michael@0 61 }
michael@0 62 #endif /* DEBUG */
michael@0 63
michael@0 64 nsIAtom *
michael@0 65 nsSVGMarkerFrame::GetType() const
michael@0 66 {
michael@0 67 return nsGkAtoms::svgMarkerFrame;
michael@0 68 }
michael@0 69
michael@0 70 //----------------------------------------------------------------------
michael@0 71 // nsSVGContainerFrame methods:
michael@0 72
michael@0 73 gfxMatrix
michael@0 74 nsSVGMarkerFrame::GetCanvasTM(uint32_t aFor, nsIFrame* aTransformRoot)
michael@0 75 {
michael@0 76 NS_ASSERTION(mMarkedFrame, "null nsSVGPathGeometry frame");
michael@0 77
michael@0 78 if (mInUse2) {
michael@0 79 // We're going to be bailing drawing the marker, so return an identity.
michael@0 80 return gfxMatrix();
michael@0 81 }
michael@0 82
michael@0 83 SVGMarkerElement *content = static_cast<SVGMarkerElement*>(mContent);
michael@0 84
michael@0 85 mInUse2 = true;
michael@0 86 gfxMatrix markedTM = mMarkedFrame->GetCanvasTM(aFor, aTransformRoot);
michael@0 87 mInUse2 = false;
michael@0 88
michael@0 89 Matrix markerTM = content->GetMarkerTransform(mStrokeWidth, mX, mY,
michael@0 90 mAutoAngle, mIsStart);
michael@0 91 Matrix viewBoxTM = content->GetViewBoxTransform();
michael@0 92
michael@0 93 return ThebesMatrix(viewBoxTM * markerTM) * markedTM;
michael@0 94 }
michael@0 95
michael@0 96 static nsIFrame*
michael@0 97 GetAnonymousChildFrame(nsIFrame* aFrame)
michael@0 98 {
michael@0 99 nsIFrame* kid = aFrame->GetFirstPrincipalChild();
michael@0 100 MOZ_ASSERT(kid && kid->GetType() == nsGkAtoms::svgMarkerAnonChildFrame,
michael@0 101 "expected to find anonymous child of marker frame");
michael@0 102 return kid;
michael@0 103 }
michael@0 104
michael@0 105 nsresult
michael@0 106 nsSVGMarkerFrame::PaintMark(nsRenderingContext *aContext,
michael@0 107 nsSVGPathGeometryFrame *aMarkedFrame,
michael@0 108 nsSVGMark *aMark, float aStrokeWidth)
michael@0 109 {
michael@0 110 // If the flag is set when we get here, it means this marker frame
michael@0 111 // has already been used painting the current mark, and the document
michael@0 112 // has a marker reference loop.
michael@0 113 if (mInUse)
michael@0 114 return NS_OK;
michael@0 115
michael@0 116 AutoMarkerReferencer markerRef(this, aMarkedFrame);
michael@0 117
michael@0 118 SVGMarkerElement *marker = static_cast<SVGMarkerElement*>(mContent);
michael@0 119 if (!marker->HasValidDimensions()) {
michael@0 120 return NS_OK;
michael@0 121 }
michael@0 122
michael@0 123 const nsSVGViewBoxRect viewBox = marker->GetViewBoxRect();
michael@0 124
michael@0 125 if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
michael@0 126 // We must disable rendering if the viewBox width or height are zero.
michael@0 127 return NS_OK;
michael@0 128 }
michael@0 129
michael@0 130 mStrokeWidth = aStrokeWidth;
michael@0 131 mX = aMark->x;
michael@0 132 mY = aMark->y;
michael@0 133 mAutoAngle = aMark->angle;
michael@0 134 mIsStart = aMark->type == nsSVGMark::eStart;
michael@0 135
michael@0 136 gfxContext *gfx = aContext->ThebesContext();
michael@0 137
michael@0 138 if (StyleDisplay()->IsScrollableOverflow()) {
michael@0 139 gfx->Save();
michael@0 140 gfxRect clipRect =
michael@0 141 nsSVGUtils::GetClipRectForFrame(this, viewBox.x, viewBox.y,
michael@0 142 viewBox.width, viewBox.height);
michael@0 143 nsSVGUtils::SetClipRect(gfx, GetCanvasTM(nsISVGChildFrame::FOR_PAINTING),
michael@0 144 clipRect);
michael@0 145 }
michael@0 146
michael@0 147 nsIFrame* kid = GetAnonymousChildFrame(this);
michael@0 148 nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
michael@0 149 // The CTM of each frame referencing us may be different.
michael@0 150 SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
michael@0 151 nsSVGUtils::PaintFrameWithEffects(aContext, nullptr, kid);
michael@0 152
michael@0 153 if (StyleDisplay()->IsScrollableOverflow())
michael@0 154 gfx->Restore();
michael@0 155
michael@0 156 return NS_OK;
michael@0 157 }
michael@0 158
michael@0 159 SVGBBox
michael@0 160 nsSVGMarkerFrame::GetMarkBBoxContribution(const Matrix &aToBBoxUserspace,
michael@0 161 uint32_t aFlags,
michael@0 162 nsSVGPathGeometryFrame *aMarkedFrame,
michael@0 163 const nsSVGMark *aMark,
michael@0 164 float aStrokeWidth)
michael@0 165 {
michael@0 166 SVGBBox bbox;
michael@0 167
michael@0 168 // If the flag is set when we get here, it means this marker frame
michael@0 169 // has already been used in calculating the current mark bbox, and
michael@0 170 // the document has a marker reference loop.
michael@0 171 if (mInUse)
michael@0 172 return bbox;
michael@0 173
michael@0 174 AutoMarkerReferencer markerRef(this, aMarkedFrame);
michael@0 175
michael@0 176 SVGMarkerElement *content = static_cast<SVGMarkerElement*>(mContent);
michael@0 177 if (!content->HasValidDimensions()) {
michael@0 178 return bbox;
michael@0 179 }
michael@0 180
michael@0 181 const nsSVGViewBoxRect viewBox = content->GetViewBoxRect();
michael@0 182
michael@0 183 if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
michael@0 184 return bbox;
michael@0 185 }
michael@0 186
michael@0 187 mStrokeWidth = aStrokeWidth;
michael@0 188 mX = aMark->x;
michael@0 189 mY = aMark->y;
michael@0 190 mAutoAngle = aMark->angle;
michael@0 191 mIsStart = aMark->type == nsSVGMark::eStart;
michael@0 192
michael@0 193 Matrix markerTM =
michael@0 194 content->GetMarkerTransform(mStrokeWidth, mX, mY, mAutoAngle, mIsStart);
michael@0 195 Matrix viewBoxTM = content->GetViewBoxTransform();
michael@0 196
michael@0 197 Matrix tm = viewBoxTM * markerTM * aToBBoxUserspace;
michael@0 198
michael@0 199 nsISVGChildFrame* child = do_QueryFrame(GetAnonymousChildFrame(this));
michael@0 200 // When we're being called to obtain the invalidation area, we need to
michael@0 201 // pass down all the flags so that stroke is included. However, once DOM
michael@0 202 // getBBox() accepts flags, maybe we should strip some of those here?
michael@0 203
michael@0 204 // We need to include zero width/height vertical/horizontal lines, so we have
michael@0 205 // to use UnionEdges.
michael@0 206 bbox.UnionEdges(child->GetBBoxContribution(tm, aFlags));
michael@0 207
michael@0 208 return bbox;
michael@0 209 }
michael@0 210
michael@0 211 void
michael@0 212 nsSVGMarkerFrame::SetParentCoordCtxProvider(SVGSVGElement *aContext)
michael@0 213 {
michael@0 214 SVGMarkerElement *marker = static_cast<SVGMarkerElement*>(mContent);
michael@0 215 marker->SetParentCoordCtxProvider(aContext);
michael@0 216 }
michael@0 217
michael@0 218 //----------------------------------------------------------------------
michael@0 219 // helper class
michael@0 220
michael@0 221 nsSVGMarkerFrame::AutoMarkerReferencer::AutoMarkerReferencer(
michael@0 222 nsSVGMarkerFrame *aFrame,
michael@0 223 nsSVGPathGeometryFrame *aMarkedFrame
michael@0 224 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
michael@0 225 : mFrame(aFrame)
michael@0 226 {
michael@0 227 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 228 mFrame->mInUse = true;
michael@0 229 mFrame->mMarkedFrame = aMarkedFrame;
michael@0 230
michael@0 231 SVGSVGElement *ctx =
michael@0 232 static_cast<nsSVGElement*>(aMarkedFrame->GetContent())->GetCtx();
michael@0 233 mFrame->SetParentCoordCtxProvider(ctx);
michael@0 234 }
michael@0 235
michael@0 236 nsSVGMarkerFrame::AutoMarkerReferencer::~AutoMarkerReferencer()
michael@0 237 {
michael@0 238 mFrame->SetParentCoordCtxProvider(nullptr);
michael@0 239
michael@0 240 mFrame->mMarkedFrame = nullptr;
michael@0 241 mFrame->mInUse = false;
michael@0 242 }
michael@0 243
michael@0 244 //----------------------------------------------------------------------
michael@0 245 // Implementation of nsSVGMarkerAnonChildFrame
michael@0 246
michael@0 247 nsIFrame*
michael@0 248 NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell,
michael@0 249 nsStyleContext* aContext)
michael@0 250 {
michael@0 251 return new (aPresShell) nsSVGMarkerAnonChildFrame(aContext);
michael@0 252 }
michael@0 253
michael@0 254 NS_IMPL_FRAMEARENA_HELPERS(nsSVGMarkerAnonChildFrame)
michael@0 255
michael@0 256 #ifdef DEBUG
michael@0 257 void
michael@0 258 nsSVGMarkerAnonChildFrame::Init(nsIContent* aContent,
michael@0 259 nsIFrame* aParent,
michael@0 260 nsIFrame* aPrevInFlow)
michael@0 261 {
michael@0 262 NS_ABORT_IF_FALSE(aParent->GetType() == nsGkAtoms::svgMarkerFrame,
michael@0 263 "Unexpected parent");
michael@0 264 nsSVGMarkerAnonChildFrameBase::Init(aContent, aParent, aPrevInFlow);
michael@0 265 }
michael@0 266 #endif
michael@0 267
michael@0 268 nsIAtom *
michael@0 269 nsSVGMarkerAnonChildFrame::GetType() const
michael@0 270 {
michael@0 271 return nsGkAtoms::svgMarkerAnonChildFrame;
michael@0 272 }

mercurial