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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is the Mozilla SVG project.
16 : *
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.
20 : *
21 : * Contributor(s):
22 : *
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.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsPresContext.h"
38 : #include "nsSVGPathElement.h"
39 : #include "nsSVGUtils.h"
40 : #include "nsSVGGeometryFrame.h"
41 : #include "nsSVGPaintServerFrame.h"
42 : #include "nsContentUtils.h"
43 : #include "gfxContext.h"
44 : #include "nsSVGEffects.h"
45 :
46 0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGGeometryFrame)
47 :
48 : //----------------------------------------------------------------------
49 : // nsIFrame methods
50 :
51 : NS_IMETHODIMP
52 0 : nsSVGGeometryFrame::Init(nsIContent* aContent,
53 : nsIFrame* aParent,
54 : nsIFrame* aPrevInFlow)
55 : {
56 0 : AddStateBits(aParent->GetStateBits() &
57 : (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD |
58 0 : NS_STATE_SVG_REDRAW_SUSPENDED));
59 0 : nsresult rv = nsSVGGeometryFrameBase::Init(aContent, aParent, aPrevInFlow);
60 0 : return rv;
61 : }
62 :
63 : //----------------------------------------------------------------------
64 :
65 : nsSVGPaintServerFrame *
66 0 : nsSVGGeometryFrame::GetPaintServer(const nsStyleSVGPaint *aPaint,
67 : const FramePropertyDescriptor *aType)
68 : {
69 0 : if (aPaint->mType != eStyleSVGPaintType_Server)
70 0 : return nsnull;
71 :
72 0 : nsIFrame *frame = mContent->IsNodeOfType(nsINode::eTEXT) ?
73 0 : GetParent() : this;
74 : nsSVGPaintingProperty *property =
75 0 : nsSVGEffects::GetPaintingProperty(aPaint->mPaint.mPaintServer, frame, aType);
76 0 : if (!property)
77 0 : return nsnull;
78 0 : nsIFrame *result = property->GetReferencedFrame();
79 0 : if (!result)
80 0 : return nsnull;
81 :
82 0 : nsIAtom *type = result->GetType();
83 0 : if (type != nsGkAtoms::svgLinearGradientFrame &&
84 : type != nsGkAtoms::svgRadialGradientFrame &&
85 : type != nsGkAtoms::svgPatternFrame)
86 0 : return nsnull;
87 :
88 0 : return static_cast<nsSVGPaintServerFrame*>(result);
89 : }
90 :
91 : float
92 0 : nsSVGGeometryFrame::GetStrokeWidth()
93 : {
94 : nsSVGElement *ctx = static_cast<nsSVGElement*>
95 0 : (mContent->IsNodeOfType(nsINode::eTEXT) ?
96 0 : mContent->GetParent() : mContent);
97 :
98 : return
99 : nsSVGUtils::CoordToFloat(PresContext(),
100 : ctx,
101 0 : GetStyleSVG()->mStrokeWidth);
102 : }
103 :
104 : bool
105 0 : nsSVGGeometryFrame::GetStrokeDashData(FallibleTArray<gfxFloat>& dashes,
106 : gfxFloat *dashOffset)
107 : {
108 0 : PRUint32 count = GetStyleSVG()->mStrokeDasharrayLength;
109 0 : if (!count || !dashes.SetLength(count)) {
110 0 : return false;
111 : }
112 :
113 0 : gfxFloat pathScale = 1.0;
114 :
115 0 : if (mContent->Tag() == nsGkAtoms::path) {
116 : pathScale = static_cast<nsSVGPathElement*>(mContent)->
117 0 : GetPathLengthScale(nsSVGPathElement::eForStroking);
118 0 : if (pathScale <= 0) {
119 0 : return false;
120 : }
121 : }
122 :
123 : nsSVGElement *ctx = static_cast<nsSVGElement*>
124 0 : (mContent->IsNodeOfType(nsINode::eTEXT) ?
125 0 : mContent->GetParent() : mContent);
126 :
127 0 : const nsStyleCoord *dasharray = GetStyleSVG()->mStrokeDasharray;
128 0 : nsPresContext *presContext = PresContext();
129 0 : gfxFloat totalLength = 0.0;
130 :
131 0 : for (PRUint32 i = 0; i < count; i++) {
132 0 : dashes[i] =
133 : nsSVGUtils::CoordToFloat(presContext,
134 : ctx,
135 0 : dasharray[i]) * pathScale;
136 0 : if (dashes[i] < 0.0) {
137 0 : return false;
138 : }
139 0 : totalLength += dashes[i];
140 : }
141 :
142 : *dashOffset = nsSVGUtils::CoordToFloat(presContext,
143 : ctx,
144 0 : GetStyleSVG()->mStrokeDashoffset);
145 :
146 0 : return (totalLength > 0.0);
147 : }
148 :
149 : PRUint16
150 0 : nsSVGGeometryFrame::GetClipRule()
151 : {
152 0 : return GetStyleSVG()->mClipRule;
153 : }
154 :
155 : static void
156 0 : SetupCairoColor(gfxContext *aContext, nscolor aRGB, float aOpacity)
157 : {
158 : aContext->SetColor(gfxRGBA(NS_GET_R(aRGB)/255.0,
159 : NS_GET_G(aRGB)/255.0,
160 : NS_GET_B(aRGB)/255.0,
161 0 : NS_GET_A(aRGB)/255.0 * aOpacity));
162 0 : }
163 :
164 : static void
165 0 : SetupFallbackOrPaintColor(gfxContext *aContext, nsStyleContext *aStyleContext,
166 : nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
167 : float aOpacity)
168 : {
169 : nscolor color;
170 : nsSVGUtils::GetFallbackOrPaintColor(aContext, aStyleContext, aFillOrStroke,
171 0 : &aOpacity, &color);
172 :
173 0 : SetupCairoColor(aContext, color, aOpacity);
174 0 : }
175 :
176 : float
177 0 : nsSVGGeometryFrame::MaybeOptimizeOpacity(float aFillOrStrokeOpacity)
178 : {
179 0 : float opacity = GetStyleDisplay()->mOpacity;
180 0 : if (opacity < 1 && nsSVGUtils::CanOptimizeOpacity(this)) {
181 0 : return aFillOrStrokeOpacity * opacity;
182 : }
183 0 : return aFillOrStrokeOpacity;
184 : }
185 :
186 : bool
187 0 : nsSVGGeometryFrame::SetupCairoFill(gfxContext *aContext)
188 : {
189 0 : const nsStyleSVG* style = GetStyleSVG();
190 0 : if (style->mFill.mType == eStyleSVGPaintType_None)
191 0 : return false;
192 :
193 0 : if (style->mFillRule == NS_STYLE_FILL_RULE_EVENODD)
194 0 : aContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
195 : else
196 0 : aContext->SetFillRule(gfxContext::FILL_RULE_WINDING);
197 :
198 0 : float opacity = MaybeOptimizeOpacity(style->mFillOpacity);
199 :
200 : nsSVGPaintServerFrame *ps =
201 0 : GetPaintServer(&style->mFill, nsSVGEffects::FillProperty());
202 0 : if (ps && ps->SetupPaintServer(aContext, this, opacity))
203 0 : return true;
204 :
205 : // On failure, use the fallback colour in case we have an
206 : // objectBoundingBox where the width or height of the object is zero.
207 : // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
208 : SetupFallbackOrPaintColor(aContext, GetStyleContext(),
209 0 : &nsStyleSVG::mFill, opacity);
210 :
211 0 : return true;
212 : }
213 :
214 : bool
215 0 : nsSVGGeometryFrame::HasStroke()
216 : {
217 0 : const nsStyleSVG *style = GetStyleSVG();
218 : return style->mStroke.mType != eStyleSVGPaintType_None &&
219 : style->mStrokeOpacity > 0 &&
220 0 : GetStrokeWidth() > 0;
221 : }
222 :
223 : void
224 0 : nsSVGGeometryFrame::SetupCairoStrokeGeometry(gfxContext *aContext)
225 : {
226 0 : float width = GetStrokeWidth();
227 0 : if (width <= 0)
228 0 : return;
229 0 : aContext->SetLineWidth(width);
230 :
231 0 : const nsStyleSVG* style = GetStyleSVG();
232 :
233 0 : switch (style->mStrokeLinecap) {
234 : case NS_STYLE_STROKE_LINECAP_BUTT:
235 0 : aContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
236 0 : break;
237 : case NS_STYLE_STROKE_LINECAP_ROUND:
238 0 : aContext->SetLineCap(gfxContext::LINE_CAP_ROUND);
239 0 : break;
240 : case NS_STYLE_STROKE_LINECAP_SQUARE:
241 0 : aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE);
242 0 : break;
243 : }
244 :
245 0 : aContext->SetMiterLimit(style->mStrokeMiterlimit);
246 :
247 0 : switch (style->mStrokeLinejoin) {
248 : case NS_STYLE_STROKE_LINEJOIN_MITER:
249 0 : aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER);
250 0 : break;
251 : case NS_STYLE_STROKE_LINEJOIN_ROUND:
252 0 : aContext->SetLineJoin(gfxContext::LINE_JOIN_ROUND);
253 0 : break;
254 : case NS_STYLE_STROKE_LINEJOIN_BEVEL:
255 0 : aContext->SetLineJoin(gfxContext::LINE_JOIN_BEVEL);
256 0 : break;
257 : }
258 : }
259 :
260 : void
261 0 : nsSVGGeometryFrame::SetupCairoStrokeHitGeometry(gfxContext *aContext)
262 : {
263 0 : SetupCairoStrokeGeometry(aContext);
264 :
265 0 : AutoFallibleTArray<gfxFloat, 10> dashes;
266 : gfxFloat dashOffset;
267 0 : if (GetStrokeDashData(dashes, &dashOffset)) {
268 0 : aContext->SetDash(dashes.Elements(), dashes.Length(), dashOffset);
269 : }
270 0 : }
271 :
272 : bool
273 0 : nsSVGGeometryFrame::SetupCairoStroke(gfxContext *aContext)
274 : {
275 0 : if (!HasStroke()) {
276 0 : return false;
277 : }
278 0 : SetupCairoStrokeHitGeometry(aContext);
279 :
280 0 : const nsStyleSVG* style = GetStyleSVG();
281 0 : float opacity = MaybeOptimizeOpacity(style->mStrokeOpacity);
282 :
283 : nsSVGPaintServerFrame *ps =
284 0 : GetPaintServer(&style->mStroke, nsSVGEffects::StrokeProperty());
285 0 : if (ps && ps->SetupPaintServer(aContext, this, opacity))
286 0 : return true;
287 :
288 : // On failure, use the fallback colour in case we have an
289 : // objectBoundingBox where the width or height of the object is zero.
290 : // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
291 : SetupFallbackOrPaintColor(aContext, GetStyleContext(),
292 0 : &nsStyleSVG::mStroke, opacity);
293 :
294 0 : return true;
295 : }
296 :
297 : PRUint16
298 0 : nsSVGGeometryFrame::GetHitTestFlags()
299 : {
300 0 : PRUint16 flags = 0;
301 :
302 0 : switch(GetStyleVisibility()->mPointerEvents) {
303 : case NS_STYLE_POINTER_EVENTS_NONE:
304 0 : break;
305 : case NS_STYLE_POINTER_EVENTS_AUTO:
306 : case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED:
307 0 : if (GetStyleVisibility()->IsVisible()) {
308 0 : if (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None)
309 0 : flags |= SVG_HIT_TEST_FILL;
310 0 : if (GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None)
311 0 : flags |= SVG_HIT_TEST_STROKE;
312 0 : if (GetStyleSVG()->mStrokeOpacity > 0)
313 0 : flags |= SVG_HIT_TEST_CHECK_MRECT;
314 : }
315 0 : break;
316 : case NS_STYLE_POINTER_EVENTS_VISIBLEFILL:
317 0 : if (GetStyleVisibility()->IsVisible()) {
318 0 : flags |= SVG_HIT_TEST_FILL;
319 : }
320 0 : break;
321 : case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE:
322 0 : if (GetStyleVisibility()->IsVisible()) {
323 0 : flags |= SVG_HIT_TEST_STROKE;
324 : }
325 0 : break;
326 : case NS_STYLE_POINTER_EVENTS_VISIBLE:
327 0 : if (GetStyleVisibility()->IsVisible()) {
328 0 : flags |= SVG_HIT_TEST_FILL | SVG_HIT_TEST_STROKE;
329 : }
330 0 : break;
331 : case NS_STYLE_POINTER_EVENTS_PAINTED:
332 0 : if (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None)
333 0 : flags |= SVG_HIT_TEST_FILL;
334 0 : if (GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None)
335 0 : flags |= SVG_HIT_TEST_STROKE;
336 0 : if (GetStyleSVG()->mStrokeOpacity)
337 0 : flags |= SVG_HIT_TEST_CHECK_MRECT;
338 0 : break;
339 : case NS_STYLE_POINTER_EVENTS_FILL:
340 0 : flags |= SVG_HIT_TEST_FILL;
341 0 : break;
342 : case NS_STYLE_POINTER_EVENTS_STROKE:
343 0 : flags |= SVG_HIT_TEST_STROKE;
344 0 : break;
345 : case NS_STYLE_POINTER_EVENTS_ALL:
346 0 : flags |= SVG_HIT_TEST_FILL | SVG_HIT_TEST_STROKE;
347 0 : break;
348 : default:
349 0 : NS_ERROR("not reached");
350 0 : break;
351 : }
352 :
353 0 : return flags;
354 : }
|