@@ -71,6 +71,7 @@ public abstract class AbstractSvgNodeRenderer implements ISvgNodeRenderer {
71
71
72
72
private boolean doFill = false ;
73
73
private boolean doStroke = false ;
74
+ boolean partOfClipPath ;
74
75
75
76
@ Override
76
77
public void setParent (ISvgNodeRenderer parent ) {
@@ -112,15 +113,38 @@ public final void draw(SvgDrawContext context) {
112
113
}
113
114
}
114
115
115
- preDraw (context );
116
- doDraw (context );
117
- postDraw (context );
116
+ /* If a (non-empty) clipping path exists, drawing operations must be surrounded by q/Q operators
117
+ and may have to be drawn multiple times
118
+ */
119
+ if (!drawInClipPath (context )) {
120
+ preDraw (context );
121
+ doDraw (context );
122
+ postDraw (context );
123
+ }
118
124
119
125
if (attributesAndStyles .containsKey (SvgConstants .Attributes .ID )) {
120
126
context .removeUsedId (attributesAndStyles .get (SvgConstants .Attributes .ID ));
121
127
}
122
128
}
123
129
130
+ private boolean drawInClipPath (SvgDrawContext context ) {
131
+ if (attributesAndStyles .containsKey (SvgConstants .Attributes .CLIP_PATH )) {
132
+ String clipPathName = attributesAndStyles .get (SvgConstants .Attributes .CLIP_PATH );
133
+ ISvgNodeRenderer template = context .getNamedObject (normalizeName (clipPathName ));
134
+ //Clone template to avoid muddying the state
135
+ if (template instanceof ClipPathSvgNodeRenderer ) {
136
+ ClipPathSvgNodeRenderer clipPath = (ClipPathSvgNodeRenderer ) template .createDeepCopy ();
137
+ clipPath .setClippedRenderer (this );
138
+ clipPath .draw (context );
139
+ return !clipPath .getChildren ().isEmpty ();
140
+ }
141
+ }
142
+ return false ;
143
+ }
144
+
145
+ private String normalizeName (String name ) {
146
+ return name .replace ("url(#" , "" ).replace (")" , "" ).trim ();
147
+ }
124
148
125
149
/**
126
150
* Operations to perform before drawing an element.
@@ -132,52 +156,54 @@ void preDraw(SvgDrawContext context) {
132
156
if (this .attributesAndStyles != null ) {
133
157
PdfCanvas currentCanvas = context .getCurrentCanvas ();
134
158
135
- // fill
136
- {
137
- String fillRawValue = getAttribute (SvgConstants .Attributes .FILL );
159
+ if (!partOfClipPath ) {
160
+ // fill
161
+ {
162
+ String fillRawValue = getAttribute (SvgConstants .Attributes .FILL );
138
163
139
- this .doFill = !SvgConstants .Values .NONE .equalsIgnoreCase (fillRawValue );
164
+ this .doFill = !SvgConstants .Values .NONE .equalsIgnoreCase (fillRawValue );
140
165
141
- if (doFill && canElementFill ()) {
142
- Color color = ColorConstants .BLACK ;
166
+ if (doFill && canElementFill ()) {
167
+ Color color = ColorConstants .BLACK ;
143
168
144
- if (fillRawValue != null ) {
145
- color = WebColors .getRGBColor (fillRawValue );
146
- }
169
+ if (fillRawValue != null ) {
170
+ color = WebColors .getRGBColor (fillRawValue );
171
+ }
147
172
148
- currentCanvas .setFillColor (color );
173
+ currentCanvas .setFillColor (color );
174
+ }
149
175
}
150
- }
151
176
152
- // stroke
153
- {
154
- String strokeRawValue = getAttribute (SvgConstants .Attributes .STROKE );
155
- if (!SvgConstants .Values .NONE .equalsIgnoreCase (strokeRawValue )) {
156
- DeviceRgb rgbColor = WebColors .getRGBColor (strokeRawValue );
177
+ // stroke
178
+ {
179
+ String strokeRawValue = getAttribute (SvgConstants .Attributes .STROKE );
180
+ if (!SvgConstants .Values .NONE .equalsIgnoreCase (strokeRawValue )) {
181
+ DeviceRgb rgbColor = WebColors .getRGBColor (strokeRawValue );
157
182
158
- if (strokeRawValue != null && rgbColor != null ) {
159
- currentCanvas .setStrokeColor (rgbColor );
183
+ if (strokeRawValue != null && rgbColor != null ) {
184
+ currentCanvas .setStrokeColor (rgbColor );
160
185
161
- String strokeWidthRawValue = getAttribute (SvgConstants .Attributes .STROKE_WIDTH );
186
+ String strokeWidthRawValue = getAttribute (SvgConstants .Attributes .STROKE_WIDTH );
162
187
163
- float strokeWidth = 1f ;
188
+ float strokeWidth = 1f ;
164
189
165
- if (strokeWidthRawValue != null ) {
166
- strokeWidth = CssUtils .parseAbsoluteLength (strokeWidthRawValue );
167
- }
190
+ if (strokeWidthRawValue != null ) {
191
+ strokeWidth = CssUtils .parseAbsoluteLength (strokeWidthRawValue );
192
+ }
168
193
169
- currentCanvas .setLineWidth (strokeWidth );
170
- doStroke = true ;
194
+ currentCanvas .setLineWidth (strokeWidth );
195
+ doStroke = true ;
196
+ }
171
197
}
172
198
}
173
- }
174
- // opacity
175
- {
176
- String opacityValue = getAttribute ( SvgConstants .Attributes . FILL_OPACITY );
177
- if ( opacityValue != null && ! SvgConstants . Values . NONE . equalsIgnoreCase ( opacityValue )) {
178
- PdfExtGState gs1 = new PdfExtGState ( );
179
- gs1 . setFillOpacity ( Float . valueOf ( opacityValue ) );
180
- currentCanvas . setExtGState ( gs1 );
199
+ // opacity
200
+ {
201
+ String opacityValue = getAttribute ( SvgConstants . Attributes . FILL_OPACITY );
202
+ if ( opacityValue != null && ! SvgConstants .Values . NONE . equalsIgnoreCase ( opacityValue )) {
203
+ PdfExtGState gs1 = new PdfExtGState ();
204
+ gs1 . setFillOpacity ( Float . valueOf ( opacityValue ) );
205
+ currentCanvas . setExtGState ( gs1 );
206
+ }
181
207
}
182
208
}
183
209
}
@@ -227,28 +253,36 @@ void postDraw(SvgDrawContext context) {
227
253
PdfCanvas currentCanvas = context .getCurrentCanvas ();
228
254
229
255
// fill-rule
230
- if (doFill && canElementFill ()) {
231
- String fillRuleRawValue = getAttribute (SvgConstants .Attributes .FILL_RULE );
232
-
233
- if (SvgConstants .Values .FILL_RULE_EVEN_ODD .equalsIgnoreCase (fillRuleRawValue )) {
234
- // TODO RND-878
235
- if (doStroke ) {
236
- currentCanvas .eoFillStroke ();
237
- } else {
238
- currentCanvas .eoFill ();
239
- }
256
+ if (partOfClipPath ) {
257
+ currentCanvas .closePath ();
258
+ if (SvgConstants .Values .FILL_RULE_EVEN_ODD .equalsIgnoreCase (this .getAttribute (SvgConstants .Attributes .CLIP_RULE ))) {
259
+ currentCanvas .eoClip ();
240
260
} else {
241
- if (doStroke ) {
242
- currentCanvas .fillStroke ();
261
+ currentCanvas .clip ();
262
+ }
263
+ currentCanvas .newPath ();
264
+ } else {
265
+ if (doFill && canElementFill ()) {
266
+ String fillRuleRawValue = getAttribute (SvgConstants .Attributes .FILL_RULE );
267
+
268
+ if (SvgConstants .Values .FILL_RULE_EVEN_ODD .equalsIgnoreCase (fillRuleRawValue )) {
269
+ if (doStroke ) {
270
+ currentCanvas .eoFillStroke ();
271
+ } else {
272
+ currentCanvas .eoFill ();
273
+ }
243
274
} else {
244
- currentCanvas .fill ();
275
+ if (doStroke ) {
276
+ currentCanvas .fillStroke ();
277
+ } else {
278
+ currentCanvas .fill ();
279
+ }
245
280
}
281
+ } else if (doStroke ) {
282
+ currentCanvas .stroke ();
246
283
}
247
- } else if (doStroke ) {
248
- currentCanvas .stroke ();
284
+ currentCanvas .closePath ();
249
285
}
250
-
251
- currentCanvas .closePath ();
252
286
}
253
287
}
254
288
@@ -325,4 +359,7 @@ protected void deepCopyAttributesAndStyles(ISvgNodeRenderer deepCopy){
325
359
}
326
360
}
327
361
362
+ void setPartOfClipPath (boolean value ) {
363
+ partOfClipPath = value ;
364
+ }
328
365
}
0 commit comments