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
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.
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 //----------------------------------------------------------------------
49 nsSVGGeometryFrame::Init(nsIContent
* aContent
,
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
);
59 //----------------------------------------------------------------------
61 nsSVGPaintServerFrame
*
62 nsSVGGeometryFrame::GetPaintServer(const nsStyleSVGPaint
*aPaint
,
65 if (aPaint
->mType
!= eStyleSVGPaintType_Server
)
68 nsSVGPaintingProperty
*property
=
69 nsSVGEffects::GetPaintingProperty(aPaint
->mPaint
.mPaintServer
, this, aType
);
72 nsIFrame
*result
= property
->GetReferencedFrame();
76 nsIAtom
*type
= result
->GetType();
77 if (type
!= nsGkAtoms::svgLinearGradientFrame
&&
78 type
!= nsGkAtoms::svgRadialGradientFrame
&&
79 type
!= nsGkAtoms::svgPatternFrame
)
82 return static_cast<nsSVGPaintServerFrame
*>(result
);
86 nsSVGGeometryFrame::GetStrokeWidth()
88 nsSVGElement
*ctx
= static_cast<nsSVGElement
*>
89 (GetType() == nsGkAtoms::svgGlyphFrame
?
90 mContent
->GetParent() : mContent
);
93 nsSVGUtils::CoordToFloat(PresContext(),
95 GetStyleSVG()->mStrokeWidth
);
99 nsSVGGeometryFrame::GetStrokeDashArray(gfxFloat
**aDashes
, PRUint32
*aCount
)
101 nsSVGElement
*ctx
= static_cast<nsSVGElement
*>
102 (GetType() == nsGkAtoms::svgGlyphFrame
?
103 mContent
->GetParent() : mContent
);
107 PRUint32 count
= GetStyleSVG()->mStrokeDasharrayLength
;
108 gfxFloat
*dashes
= nsnull
;
111 const nsStyleCoord
*dasharray
= GetStyleSVG()->mStrokeDasharray
;
112 nsPresContext
*presContext
= PresContext();
113 gfxFloat totalLength
= 0.0f
;
115 dashes
= new gfxFloat
[count
];
117 for (PRUint32 i
= 0; i
< count
; i
++) {
119 nsSVGUtils::CoordToFloat(presContext
,
122 if (dashes
[i
] < 0.0f
) {
126 totalLength
+= dashes
[i
];
129 return NS_ERROR_OUT_OF_MEMORY
;
132 if (totalLength
== 0.0f
) {
145 nsSVGGeometryFrame::GetStrokeDashoffset()
147 nsSVGElement
*ctx
= static_cast<nsSVGElement
*>
148 (GetType() == nsGkAtoms::svgGlyphFrame
?
149 mContent
->GetParent() : mContent
);
152 nsSVGUtils::CoordToFloat(PresContext(),
154 GetStyleSVG()->mStrokeDashoffset
);
158 nsSVGGeometryFrame::GetClipRule()
160 return GetStyleSVG()->mClipRule
;
164 nsSVGGeometryFrame::IsClipChild()
166 nsIContent
*node
= mContent
;
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
) {
174 if (node
->NodeInfo()->Equals(nsGkAtoms::clipPath
, kNameSpaceID_SVG
)) {
177 node
= node
->GetParent();
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
));
193 nsSVGGeometryFrame::MaybeOptimizeOpacity(float aOpacity
)
195 if (nsSVGUtils::CanOptimizeOpacity(this)) {
196 aOpacity
*= GetStyleDisplay()->mOpacity
;
202 nsSVGGeometryFrame::SetupCairoFill(gfxContext
*aContext
)
204 const nsStyleSVG
* style
= GetStyleSVG();
205 if (style
->mFill
.mType
== eStyleSVGPaintType_None
)
208 if (style
->mFillRule
== NS_STYLE_FILL_RULE_EVENODD
)
209 aContext
->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD
);
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
))
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
,
228 SetupCairoColor(aContext
,
229 GetStyleSVG()->mFill
.mPaint
.mColor
,
236 nsSVGGeometryFrame::SetupCairoStrokeGeometry(gfxContext
*aContext
)
238 const nsStyleSVG
* style
= GetStyleSVG();
239 if (style
->mStroke
.mType
== eStyleSVGPaintType_None
)
242 float width
= GetStrokeWidth();
245 aContext
->SetLineWidth(width
);
247 switch (style
->mStrokeLinecap
) {
248 case NS_STYLE_STROKE_LINECAP_BUTT
:
249 aContext
->SetLineCap(gfxContext::LINE_CAP_BUTT
);
251 case NS_STYLE_STROKE_LINECAP_ROUND
:
252 aContext
->SetLineCap(gfxContext::LINE_CAP_ROUND
);
254 case NS_STYLE_STROKE_LINECAP_SQUARE
:
255 aContext
->SetLineCap(gfxContext::LINE_CAP_SQUARE
);
259 aContext
->SetMiterLimit(style
->mStrokeMiterlimit
);
261 switch (style
->mStrokeLinejoin
) {
262 case NS_STYLE_STROKE_LINEJOIN_MITER
:
263 aContext
->SetLineJoin(gfxContext::LINE_JOIN_MITER
);
265 case NS_STYLE_STROKE_LINEJOIN_ROUND
:
266 aContext
->SetLineJoin(gfxContext::LINE_JOIN_ROUND
);
268 case NS_STYLE_STROKE_LINEJOIN_BEVEL
:
269 aContext
->SetLineJoin(gfxContext::LINE_JOIN_BEVEL
);
277 nsSVGGeometryFrame::SetupCairoStrokeHitGeometry(gfxContext
*aContext
)
279 if (!SetupCairoStrokeGeometry(aContext
))
284 GetStrokeDashArray(&dashArray
, &count
);
286 aContext
->SetDash(dashArray
, count
, GetStrokeDashoffset());
293 nsSVGGeometryFrame::SetupCairoStroke(gfxContext
*aContext
)
295 if (!SetupCairoStrokeHitGeometry(aContext
))
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
))
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
,
314 SetupCairoColor(aContext
,
315 GetStyleSVG()->mStroke
.mPaint
.mColor
,