Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / svg / base / src / nsSVGGeometryFrame.cpp
blob278d0f564a7b3313be5bbd3a1441b67b3d44ae0a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is the Mozilla SVG project.
17 * The Initial Developer of the Original Code is IBM Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2006
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either of the GNU General Public License Version 2 or later (the "GPL"),
25 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "nsPresContext.h"
38 #include "nsSVGUtils.h"
39 #include "nsSVGGeometryFrame.h"
40 #include "nsSVGPaintServerFrame.h"
41 #include "nsContentUtils.h"
42 #include "gfxContext.h"
43 #include "nsSVGEffects.h"
45 //----------------------------------------------------------------------
46 // nsIFrame methods
48 NS_IMETHODIMP
49 nsSVGGeometryFrame::Init(nsIContent* aContent,
50 nsIFrame* aParent,
51 nsIFrame* aPrevInFlow)
53 AddStateBits((aParent->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) |
54 NS_STATE_SVG_PROPAGATE_TRANSFORM);
55 nsresult rv = nsSVGGeometryFrameBase::Init(aContent, aParent, aPrevInFlow);
56 return rv;
59 //----------------------------------------------------------------------
61 nsSVGPaintServerFrame *
62 nsSVGGeometryFrame::GetPaintServer(const nsStyleSVGPaint *aPaint,
63 nsIAtom *aType)
65 if (aPaint->mType != eStyleSVGPaintType_Server)
66 return nsnull;
68 nsSVGPaintingProperty *property =
69 nsSVGEffects::GetPaintingProperty(aPaint->mPaint.mPaintServer, this, aType);
70 if (!property)
71 return nsnull;
72 nsIFrame *result = property->GetReferencedFrame();
73 if (!result)
74 return nsnull;
76 nsIAtom *type = result->GetType();
77 if (type != nsGkAtoms::svgLinearGradientFrame &&
78 type != nsGkAtoms::svgRadialGradientFrame &&
79 type != nsGkAtoms::svgPatternFrame)
80 return nsnull;
82 return static_cast<nsSVGPaintServerFrame*>(result);
85 float
86 nsSVGGeometryFrame::GetStrokeWidth()
88 nsSVGElement *ctx = static_cast<nsSVGElement*>
89 (GetType() == nsGkAtoms::svgGlyphFrame ?
90 mContent->GetParent() : mContent);
92 return
93 nsSVGUtils::CoordToFloat(PresContext(),
94 ctx,
95 GetStyleSVG()->mStrokeWidth);
98 nsresult
99 nsSVGGeometryFrame::GetStrokeDashArray(gfxFloat **aDashes, PRUint32 *aCount)
101 nsSVGElement *ctx = static_cast<nsSVGElement*>
102 (GetType() == nsGkAtoms::svgGlyphFrame ?
103 mContent->GetParent() : mContent);
104 *aDashes = nsnull;
105 *aCount = 0;
107 PRUint32 count = GetStyleSVG()->mStrokeDasharrayLength;
108 gfxFloat *dashes = nsnull;
110 if (count) {
111 const nsStyleCoord *dasharray = GetStyleSVG()->mStrokeDasharray;
112 nsPresContext *presContext = PresContext();
113 gfxFloat totalLength = 0.0f;
115 dashes = new gfxFloat[count];
116 if (dashes) {
117 for (PRUint32 i = 0; i < count; i++) {
118 dashes[i] =
119 nsSVGUtils::CoordToFloat(presContext,
120 ctx,
121 dasharray[i]);
122 if (dashes[i] < 0.0f) {
123 delete [] dashes;
124 return NS_OK;
126 totalLength += dashes[i];
128 } else {
129 return NS_ERROR_OUT_OF_MEMORY;
132 if (totalLength == 0.0f) {
133 delete [] dashes;
134 return NS_OK;
137 *aDashes = dashes;
138 *aCount = count;
141 return NS_OK;
144 float
145 nsSVGGeometryFrame::GetStrokeDashoffset()
147 nsSVGElement *ctx = static_cast<nsSVGElement*>
148 (GetType() == nsGkAtoms::svgGlyphFrame ?
149 mContent->GetParent() : mContent);
151 return
152 nsSVGUtils::CoordToFloat(PresContext(),
153 ctx,
154 GetStyleSVG()->mStrokeDashoffset);
157 PRUint16
158 nsSVGGeometryFrame::GetClipRule()
160 return GetStyleSVG()->mClipRule;
163 PRBool
164 nsSVGGeometryFrame::IsClipChild()
166 nsIContent *node = mContent;
168 do {
169 // Return false if we find a non-svg ancestor. Non-SVG elements are not
170 // allowed inside an SVG clipPath element.
171 if (node->GetNameSpaceID() != kNameSpaceID_SVG) {
172 break;
174 if (node->NodeInfo()->Equals(nsGkAtoms::clipPath, kNameSpaceID_SVG)) {
175 return PR_TRUE;
177 node = node->GetParent();
178 } while (node);
180 return PR_FALSE;
183 static void
184 SetupCairoColor(gfxContext *aContext, nscolor aRGB, float aOpacity)
186 aContext->SetColor(gfxRGBA(NS_GET_R(aRGB)/255.0,
187 NS_GET_G(aRGB)/255.0,
188 NS_GET_B(aRGB)/255.0,
189 NS_GET_A(aRGB)/255.0 * aOpacity));
192 float
193 nsSVGGeometryFrame::MaybeOptimizeOpacity(float aOpacity)
195 if (nsSVGUtils::CanOptimizeOpacity(this)) {
196 aOpacity *= GetStyleDisplay()->mOpacity;
198 return aOpacity;
201 PRBool
202 nsSVGGeometryFrame::SetupCairoFill(gfxContext *aContext)
204 const nsStyleSVG* style = GetStyleSVG();
205 if (style->mFill.mType == eStyleSVGPaintType_None)
206 return PR_FALSE;
208 if (style->mFillRule == NS_STYLE_FILL_RULE_EVENODD)
209 aContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
210 else
211 aContext->SetFillRule(gfxContext::FILL_RULE_WINDING);
213 float opacity = MaybeOptimizeOpacity(style->mFillOpacity);
215 nsSVGPaintServerFrame *ps =
216 GetPaintServer(&style->mFill, nsGkAtoms::fill);
217 if (ps && ps->SetupPaintServer(aContext, this, opacity))
218 return PR_TRUE;
220 // On failure, use the fallback colour in case we have an
221 // objectBoundingBox where the width or height of the object is zero.
222 // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
223 if (style->mFill.mType == eStyleSVGPaintType_Server) {
224 SetupCairoColor(aContext,
225 GetStyleSVG()->mFill.mFallbackColor,
226 opacity);
227 } else
228 SetupCairoColor(aContext,
229 GetStyleSVG()->mFill.mPaint.mColor,
230 opacity);
232 return PR_TRUE;
235 PRBool
236 nsSVGGeometryFrame::SetupCairoStrokeGeometry(gfxContext *aContext)
238 const nsStyleSVG* style = GetStyleSVG();
239 if (style->mStroke.mType == eStyleSVGPaintType_None)
240 return PR_FALSE;
242 float width = GetStrokeWidth();
243 if (width <= 0)
244 return PR_FALSE;
245 aContext->SetLineWidth(width);
247 switch (style->mStrokeLinecap) {
248 case NS_STYLE_STROKE_LINECAP_BUTT:
249 aContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
250 break;
251 case NS_STYLE_STROKE_LINECAP_ROUND:
252 aContext->SetLineCap(gfxContext::LINE_CAP_ROUND);
253 break;
254 case NS_STYLE_STROKE_LINECAP_SQUARE:
255 aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE);
256 break;
259 aContext->SetMiterLimit(style->mStrokeMiterlimit);
261 switch (style->mStrokeLinejoin) {
262 case NS_STYLE_STROKE_LINEJOIN_MITER:
263 aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER);
264 break;
265 case NS_STYLE_STROKE_LINEJOIN_ROUND:
266 aContext->SetLineJoin(gfxContext::LINE_JOIN_ROUND);
267 break;
268 case NS_STYLE_STROKE_LINEJOIN_BEVEL:
269 aContext->SetLineJoin(gfxContext::LINE_JOIN_BEVEL);
270 break;
273 return PR_TRUE;
276 PRBool
277 nsSVGGeometryFrame::SetupCairoStrokeHitGeometry(gfxContext *aContext)
279 if (!SetupCairoStrokeGeometry(aContext))
280 return PR_FALSE;
282 gfxFloat *dashArray;
283 PRUint32 count;
284 GetStrokeDashArray(&dashArray, &count);
285 if (count > 0) {
286 aContext->SetDash(dashArray, count, GetStrokeDashoffset());
287 delete [] dashArray;
289 return PR_TRUE;
292 PRBool
293 nsSVGGeometryFrame::SetupCairoStroke(gfxContext *aContext)
295 if (!SetupCairoStrokeHitGeometry(aContext))
296 return PR_FALSE;
298 const nsStyleSVG* style = GetStyleSVG();
299 float opacity = MaybeOptimizeOpacity(style->mStrokeOpacity);
301 nsSVGPaintServerFrame *ps =
302 GetPaintServer(&style->mStroke, nsGkAtoms::stroke);
303 if (ps && ps->SetupPaintServer(aContext, this, opacity))
304 return PR_TRUE;
306 // On failure, use the fallback colour in case we have an
307 // objectBoundingBox where the width or height of the object is zero.
308 // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
309 if (style->mStroke.mType == eStyleSVGPaintType_Server) {
310 SetupCairoColor(aContext,
311 GetStyleSVG()->mStroke.mFallbackColor,
312 opacity);
313 } else
314 SetupCairoColor(aContext,
315 GetStyleSVG()->mStroke.mPaint.mColor,
316 opacity);
318 return PR_TRUE;