KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > bridge > PaintServer


1 /*
2
3    Copyright 2001-2004 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.bridge;
19
20 import java.awt.BasicStroke JavaDoc;
21 import java.awt.Color JavaDoc;
22 import java.awt.Paint JavaDoc;
23 import java.awt.Shape JavaDoc;
24 import java.awt.Stroke JavaDoc;
25
26 import org.apache.batik.css.engine.SVGCSSEngine;
27 import org.apache.batik.css.engine.value.ListValue;
28 import org.apache.batik.css.engine.value.Value;
29 import org.apache.batik.css.engine.value.svg.ICCColor;
30 import org.apache.batik.ext.awt.color.ICCColorSpaceExt;
31 import org.apache.batik.gvt.CompositeShapePainter;
32 import org.apache.batik.gvt.FillShapePainter;
33 import org.apache.batik.gvt.GraphicsNode;
34 import org.apache.batik.gvt.Marker;
35 import org.apache.batik.gvt.MarkerShapePainter;
36 import org.apache.batik.gvt.ShapeNode;
37 import org.apache.batik.gvt.ShapePainter;
38 import org.apache.batik.gvt.StrokeShapePainter;
39 import org.apache.batik.util.CSSConstants;
40 import org.apache.batik.util.SVGConstants;
41 import org.w3c.dom.Element JavaDoc;
42 import org.w3c.dom.css.CSSPrimitiveValue;
43 import org.w3c.dom.css.CSSValue;
44
45 /**
46  * A collection of utility methods to deliver <tt>java.awt.Paint</tt>,
47  * <tt>java.awt.Stroke</tt> objects that could be used to paint a
48  * shape. This class also provides additional methods the deliver SVG
49  * Paint using the ShapePainter interface.
50  *
51  * @author <a HREF="mailto:tkormann@apache.org">Thierry Kormann</a>
52  * @version $Id: PaintServer.java,v 1.17 2005/03/27 08:58:30 cam Exp $
53  */

54 public abstract class PaintServer
55     implements SVGConstants, CSSConstants, ErrorConstants {
56
57     /**
58      * No instance of this class is required.
59      */

60     protected PaintServer() {}
61
62
63     /////////////////////////////////////////////////////////////////////////
64
// 'marker-start', 'marker-mid', 'marker-end' delegates to the PaintServer
65
/////////////////////////////////////////////////////////////////////////
66

67     /**
68      * Returns a <tt>ShapePainter</tt> defined on the specified
69      * element and for the specified shape node.
70      *
71      * @param e the element with the marker CSS properties
72      * @param node the shape node
73      * @param ctx the bridge context
74      */

75     public static ShapePainter convertMarkers(Element JavaDoc e,
76                                               ShapeNode node,
77                                               BridgeContext ctx) {
78         Value v;
79         v = CSSUtilities.getComputedStyle(e, SVGCSSEngine.MARKER_START_INDEX);
80         Marker startMarker = convertMarker(e, v, ctx);
81         v = CSSUtilities.getComputedStyle(e, SVGCSSEngine.MARKER_MID_INDEX);
82         Marker midMarker = convertMarker(e, v, ctx);
83         v = CSSUtilities.getComputedStyle(e, SVGCSSEngine.MARKER_END_INDEX);
84         Marker endMarker = convertMarker(e, v, ctx);
85
86         if (startMarker != null || midMarker != null || endMarker != null) {
87             MarkerShapePainter p = new MarkerShapePainter(node.getShape());
88             p.setStartMarker(startMarker);
89             p.setMiddleMarker(midMarker);
90             p.setEndMarker(endMarker);
91             return p;
92         } else {
93             return null;
94         }
95     }
96
97     /////////////////////////////////////////////////////////////////////////
98
// org.apache.batik.gvt.Marker
99
/////////////////////////////////////////////////////////////////////////
100

101     /**
102      * Returns a <tt>Marker</tt> defined on the specified element by
103      * the specified value, and for the specified shape node.
104      *
105      * @param e the painted element
106      * @param v the CSS value describing the marker to construct
107      * @param ctx the bridge context
108      */

109     public static Marker convertMarker(Element JavaDoc e,
110                                        Value v,
111                                        BridgeContext ctx) {
112
113         if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
114             return null; // 'none'
115
} else {
116             String JavaDoc uri = v.getStringValue();
117             Element JavaDoc markerElement = ctx.getReferencedElement(e, uri);
118             Bridge bridge = ctx.getBridge(markerElement);
119             if (bridge == null || !(bridge instanceof MarkerBridge)) {
120                 throw new BridgeException(e, ERR_CSS_URI_BAD_TARGET,
121                                           new Object JavaDoc[] {uri});
122             }
123             return ((MarkerBridge)bridge).createMarker(ctx, markerElement, e);
124         }
125     }
126
127     /////////////////////////////////////////////////////////////////////////
128
// 'stroke', 'fill' ... converts to ShapePainter
129
/////////////////////////////////////////////////////////////////////////
130

131     /**
132      * Returns a <tt>ShapePainter</tt> defined on the specified element and
133      * for the specified shape node, and using the specified bridge
134      * context.
135      *
136      * @param e the element interested in a shape painter
137      * @param node the shape node
138      * @param ctx the bridge context
139      */

140     public static ShapePainter convertFillAndStroke(Element JavaDoc e,
141                                                     ShapeNode node,
142                                                     BridgeContext ctx) {
143         Shape JavaDoc shape = node.getShape();
144         if (shape == null) return null;
145
146         Paint JavaDoc fillPaint = convertFillPaint (e, node, ctx);
147         FillShapePainter fp = new FillShapePainter(shape);
148         fp.setPaint(fillPaint);
149
150         Stroke JavaDoc stroke = convertStroke (e);
151         if (stroke == null)
152             return fp;
153
154         Paint JavaDoc strokePaint = convertStrokePaint(e, node, ctx);
155         StrokeShapePainter sp = new StrokeShapePainter(shape);
156         sp.setStroke(stroke);
157         sp.setPaint(strokePaint);
158
159         CompositeShapePainter cp = new CompositeShapePainter(shape);
160         cp.addShapePainter(fp);
161         cp.addShapePainter(sp);
162         return cp;
163     }
164
165
166     public static ShapePainter convertStrokePainter(Element JavaDoc e,
167                                                     ShapeNode node,
168                                                     BridgeContext ctx) {
169         Shape JavaDoc shape = node.getShape();
170         if (shape == null) return null;
171
172         Stroke JavaDoc stroke = convertStroke(e);
173         if (stroke == null)
174             return null;
175
176         Paint JavaDoc strokePaint = convertStrokePaint(e, node, ctx);
177         StrokeShapePainter sp = new StrokeShapePainter(shape);
178         sp.setStroke(stroke);
179         sp.setPaint(strokePaint);
180         return sp;
181     }
182
183     /////////////////////////////////////////////////////////////////////////
184
// java.awt.Paint
185
/////////////////////////////////////////////////////////////////////////
186

187     /**
188      * Converts for the specified element, its stroke paint properties
189      * to a Paint object.
190      *
191      * @param strokedElement the element interested in a Paint
192      * @param strokedNode the graphics node to stroke
193      * @param ctx the bridge context
194      */

195     public static Paint JavaDoc convertStrokePaint(Element JavaDoc strokedElement,
196                                            GraphicsNode strokedNode,
197                                            BridgeContext ctx) {
198         Value v = CSSUtilities.getComputedStyle
199             (strokedElement, SVGCSSEngine.STROKE_OPACITY_INDEX);
200         float opacity = convertOpacity(v);
201         v = CSSUtilities.getComputedStyle
202             (strokedElement, SVGCSSEngine.STROKE_INDEX);
203
204         return convertPaint(strokedElement,
205                             strokedNode,
206                             v,
207                             opacity,
208                             ctx);
209     }
210
211     /**
212      * Converts for the specified element, its fill paint properties
213      * to a Paint object.
214      *
215      * @param filledElement the element interested in a Paint
216      * @param filledNode the graphics node to fill
217      * @param ctx the bridge context
218      */

219     public static Paint JavaDoc convertFillPaint(Element JavaDoc filledElement,
220                                          GraphicsNode filledNode,
221                                          BridgeContext ctx) {
222         Value v = CSSUtilities.getComputedStyle
223             (filledElement, SVGCSSEngine.FILL_OPACITY_INDEX);
224         float opacity = convertOpacity(v);
225         v = CSSUtilities.getComputedStyle
226             (filledElement, SVGCSSEngine.FILL_INDEX);
227
228         return convertPaint(filledElement,
229                             filledNode,
230                             v,
231                             opacity,
232                             ctx);
233     }
234
235     /**
236      * Converts a Paint definition to a concrete <tt>java.awt.Paint</tt>
237      * instance according to the specified parameters.
238      *
239      * @param paintedElement the element interested in a Paint
240      * @param paintedNode the graphics node to paint (objectBoundingBox)
241      * @param paintDef the paint definition
242      * @param opacity the opacity to consider for the Paint
243      * @param ctx the bridge context
244      */

245     public static Paint JavaDoc convertPaint(Element JavaDoc paintedElement,
246                                         GraphicsNode paintedNode,
247                                         Value paintDef,
248                                         float opacity,
249                                         BridgeContext ctx) {
250         if (paintDef.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
251             switch (paintDef.getPrimitiveType()) {
252             case CSSPrimitiveValue.CSS_IDENT:
253                 return null; // none
254

255             case CSSPrimitiveValue.CSS_RGBCOLOR:
256                 return convertColor(paintDef, opacity);
257
258             case CSSPrimitiveValue.CSS_URI:
259                 return convertURIPaint(paintedElement,
260                                        paintedNode,
261                                        paintDef,
262                                        opacity,
263                                        ctx);
264
265             default:
266                 throw new Error JavaDoc(); // can't be reached
267
}
268         } else { // List
269
Value v = paintDef.item(0);
270             switch (v.getPrimitiveType()) {
271             case CSSPrimitiveValue.CSS_RGBCOLOR:
272                 return convertRGBICCColor(paintedElement, v,
273                                           (ICCColor)paintDef.item(1),
274                                           opacity, ctx);
275
276             case CSSPrimitiveValue.CSS_URI: {
277                 Paint JavaDoc result = silentConvertURIPaint(paintedElement,
278                                                      paintedNode,
279                                                      v, opacity, ctx);
280                 if (result != null) return result;
281
282                 v = paintDef.item(1);
283                 switch (v.getPrimitiveType()) {
284                 case CSSPrimitiveValue.CSS_IDENT:
285                     return null; // none
286

287                 case CSSPrimitiveValue.CSS_RGBCOLOR:
288                     if (paintDef.getLength() == 2) {
289                         return convertColor(v, opacity);
290                     } else {
291                         return convertRGBICCColor(paintedElement, v,
292                                                   (ICCColor)paintDef.item(2),
293                                                   opacity, ctx);
294                     }
295                 default:
296                     throw new Error JavaDoc(); // can't be reached
297
}
298             }
299             default:
300                 // can't be reached
301
throw new Error JavaDoc("Unallowed Value: " + v.getPrimitiveType());
302             }
303         }
304     }
305
306     /**
307      * Converts a Paint specified by URI without sending any error.
308      * if a problem occured while processing the URI, it just returns
309      * null (same effect as 'none')
310      *
311      * @param paintedElement the element interested in a Paint
312      * @param paintedNode the graphics node to paint (objectBoundingBox)
313      * @param paintDef the paint definition
314      * @param opacity the opacity to consider for the Paint
315      * @param ctx the bridge context
316      * @return the paint object or null when impossible
317      */

318     public static Paint JavaDoc silentConvertURIPaint(Element JavaDoc paintedElement,
319                                               GraphicsNode paintedNode,
320                                               Value paintDef,
321                                               float opacity,
322                                               BridgeContext ctx) {
323         Paint JavaDoc paint = null;
324         try {
325             paint = convertURIPaint(paintedElement, paintedNode,
326                                     paintDef, opacity, ctx);
327         } catch (BridgeException ex) {
328         }
329         return paint;
330     }
331
332     /**
333      * Converts a Paint specified as a URI.
334      *
335      * @param paintedElement the element interested in a Paint
336      * @param paintedNode the graphics node to paint (objectBoundingBox)
337      * @param paintDef the paint definition
338      * @param opacity the opacity to consider for the Paint
339      * @param ctx the bridge context
340      */

341     public static Paint JavaDoc convertURIPaint(Element JavaDoc paintedElement,
342                                         GraphicsNode paintedNode,
343                                         Value paintDef,
344                                         float opacity,
345                                         BridgeContext ctx) {
346
347         String JavaDoc uri = paintDef.getStringValue();
348         Element JavaDoc paintElement = ctx.getReferencedElement(paintedElement, uri);
349
350         Bridge bridge = ctx.getBridge(paintElement);
351         if (bridge == null || !(bridge instanceof PaintBridge)) {
352             throw new BridgeException(paintedElement, ERR_CSS_URI_BAD_TARGET,
353                                       new Object JavaDoc[] {uri});
354         }
355         return ((PaintBridge)bridge).createPaint(ctx,
356                                                  paintElement,
357                                                  paintedElement,
358                                                  paintedNode,
359                                                  opacity);
360     }
361
362     /**
363      * Returns a Color object that corresponds to the input Paint's
364      * ICC color value or an RGB color if the related color profile
365      * could not be used or loaded for any reason.
366      *
367      * @param paintedElement the element using the color
368      * @param colorDef the color definition
369      * @param iccColor the ICC color definition
370      * @param opacity the opacity
371      * @param ctx the bridge context to use
372      */

373     public static Color JavaDoc convertRGBICCColor(Element JavaDoc paintedElement,
374                                            Value colorDef,
375                                            ICCColor iccColor,
376                                            float opacity,
377                                            BridgeContext ctx) {
378         Color JavaDoc color = null;
379         if (iccColor != null){
380             color = convertICCColor(paintedElement, iccColor, opacity, ctx);
381         }
382         if (color == null){
383             color = convertColor(colorDef, opacity);
384         }
385         return color;
386     }
387
388     /**
389      * Returns a Color object that corresponds to the input Paint's
390      * ICC color value or null if the related color profile could not
391      * be used or loaded for any reason.
392      *
393      * @param e the element using the color
394      * @param c the ICC color definition
395      * @param opacity the opacity
396      * @param ctx the bridge context to use
397      */

398     public static Color JavaDoc convertICCColor(Element JavaDoc e,
399                                         ICCColor c,
400                                         float opacity,
401                                         BridgeContext ctx){
402         // Get ICC Profile's name
403
String JavaDoc iccProfileName = c.getColorProfile();
404         if (iccProfileName == null){
405             return null;
406         }
407         // Ask the bridge to map the ICC profile name to an ICC_Profile object
408
SVGColorProfileElementBridge profileBridge
409             = (SVGColorProfileElementBridge)
410             ctx.getBridge(SVG_NAMESPACE_URI, SVG_COLOR_PROFILE_TAG);
411         if (profileBridge == null){
412             return null; // no bridge for color profile
413
}
414
415         ICCColorSpaceExt profileCS
416             = profileBridge.createICCColorSpaceExt(ctx, e, iccProfileName);
417         if (profileCS == null){
418             return null; // no profile
419
}
420
421         // Now, convert the colors to an array of floats
422
int n = c.getNumberOfColors();
423         float[] colorValue = new float[n];
424         if (n == 0) {
425             return null;
426         }
427         for (int i = 0; i < n; i++) {
428             colorValue[i] = c.getColor(i);
429         }
430
431         // Convert values to RGB
432
float[] rgb = profileCS.intendedToRGB(colorValue);
433         return new Color JavaDoc(rgb[0], rgb[1], rgb[2], opacity);
434     }
435
436     /**
437      * Converts the given Value and opacity to a Color object.
438      * @param c The CSS color to convert.
439      * @param opacity The opacity value (0 &lt;= o &lt;= 1).
440      */

441     public static Color JavaDoc convertColor(Value c, float opacity) {
442         int r = resolveColorComponent(c.getRed());
443         int g = resolveColorComponent(c.getGreen());
444         int b = resolveColorComponent(c.getBlue());
445         return new Color JavaDoc(r, g, b, Math.round(opacity * 255f));
446     }
447
448     /////////////////////////////////////////////////////////////////////////
449
// java.awt.stroke
450
/////////////////////////////////////////////////////////////////////////
451

452     /**
453      * Converts a <tt>Stroke</tt> object defined on the specified element.
454      *
455      * @param e the element on which the stroke is specified
456      */

457     public static Stroke JavaDoc convertStroke(Element JavaDoc e) {
458         Value v;
459         v = CSSUtilities.getComputedStyle
460             (e, SVGCSSEngine.STROKE_WIDTH_INDEX);
461         float width = v.getFloatValue();
462         if (width == 0.0f)
463             return null; // Stop here no stroke should be painted.
464

465         v = CSSUtilities.getComputedStyle
466             (e, SVGCSSEngine.STROKE_LINECAP_INDEX);
467         int linecap = convertStrokeLinecap(v);
468         v = CSSUtilities.getComputedStyle
469             (e, SVGCSSEngine.STROKE_LINEJOIN_INDEX);
470         int linejoin = convertStrokeLinejoin(v);
471         v = CSSUtilities.getComputedStyle
472             (e, SVGCSSEngine.STROKE_MITERLIMIT_INDEX);
473         float miterlimit = convertStrokeMiterlimit(v);
474         v = CSSUtilities.getComputedStyle
475             (e, SVGCSSEngine.STROKE_DASHARRAY_INDEX);
476         float[] dasharray = convertStrokeDasharray(v);
477
478         float dashoffset = 0;
479         if (dasharray != null) {
480             v = CSSUtilities.getComputedStyle
481                 (e, SVGCSSEngine.STROKE_DASHOFFSET_INDEX);
482             dashoffset = v.getFloatValue();
483
484             // make the dashoffset positive since BasicStroke cannot handle
485
// negative values
486
if ( dashoffset < 0 ) {
487                 float dashpatternlength = 0;
488                 for ( int i=0; i<dasharray.length; i++ ) {
489                     dashpatternlength += dasharray[i];
490                 }
491                 // if the dash pattern consists of an odd number of elements,
492
// the pattern length must be doubled
493
if ( (dasharray.length % 2) != 0 )
494                     dashpatternlength *= 2;
495
496                 if (dashpatternlength ==0) {
497                     dashoffset=0;
498                 } else {
499                     while (dashoffset < 0)
500                         dashoffset += dashpatternlength;
501                 }
502             }
503         }
504         return new BasicStroke JavaDoc(width,
505                                linecap,
506                                linejoin,
507                                miterlimit,
508                                dasharray,
509                                dashoffset);
510     }
511
512     /////////////////////////////////////////////////////////////////////////
513
// Stroke utility methods
514
/////////////////////////////////////////////////////////////////////////
515

516     /**
517      * Converts the 'stroke-dasharray' property to a list of float
518      * number in user units.
519      *
520      * @param v the CSS value describing the dasharray property
521      */

522     public static float [] convertStrokeDasharray(Value v) {
523         float [] dasharray = null;
524         if (v.getCssValueType() == CSSValue.CSS_VALUE_LIST) {
525             int length = v.getLength();
526             dasharray = new float[length];
527             float sum = 0;
528             for (int i = 0; i < dasharray.length; ++i) {
529                 dasharray[i] = v.item(i).getFloatValue();
530                 sum += dasharray[i];
531             }
532             if (sum == 0) {
533                 /* 11.4 - If the sum of the <length>'s is zero, then
534                  * the stroke is rendered as if a value of none were specified.
535                  */

536                 dasharray = null;
537             }
538         }
539         return dasharray;
540     }
541
542     /**
543      * Converts the 'miterlimit' property to the appropriate float number.
544      * @param v the CSS value describing the miterlimit property
545      */

546     public static float convertStrokeMiterlimit(Value v) {
547         float miterlimit = v.getFloatValue();
548         return (miterlimit < 1f) ? 1f : miterlimit;
549     }
550
551     /**
552      * Converts the 'linecap' property to the appropriate BasicStroke constant.
553      * @param v the CSS value describing the linecap property
554      */

555     public static int convertStrokeLinecap(Value v) {
556         String JavaDoc s = v.getStringValue();
557         switch (s.charAt(0)) {
558         case 'b':
559             return BasicStroke.CAP_BUTT;
560         case 'r':
561             return BasicStroke.CAP_ROUND;
562         case 's':
563             return BasicStroke.CAP_SQUARE;
564         default:
565             throw new Error JavaDoc(); // can't be reached
566
}
567     }
568
569     /**
570      * Converts the 'linejoin' property to the appropriate BasicStroke
571      * constant.
572      * @param v the CSS value describing the linejoin property
573      */

574     public static int convertStrokeLinejoin(Value v) {
575         String JavaDoc s = v.getStringValue();
576         switch (s.charAt(0)) {
577         case 'm':
578             return BasicStroke.JOIN_MITER;
579         case 'r':
580             return BasicStroke.JOIN_ROUND;
581         case 'b':
582             return BasicStroke.JOIN_BEVEL;
583         default:
584             throw new Error JavaDoc(); // can't be reached
585
}
586     }
587
588     /////////////////////////////////////////////////////////////////////////
589
// Paint utility methods
590
/////////////////////////////////////////////////////////////////////////
591

592     /**
593      * Returns the value of one color component (0 <= result <= 255).
594      * @param v the value that defines the color component
595      */

596     public static int resolveColorComponent(Value v) {
597         float f;
598         switch(v.getPrimitiveType()) {
599         case CSSPrimitiveValue.CSS_PERCENTAGE:
600             f = v.getFloatValue();
601             f = (f > 100f) ? 100f : (f < 0f) ? 0f : f;
602             return Math.round(255f * f / 100f);
603         case CSSPrimitiveValue.CSS_NUMBER:
604             f = v.getFloatValue();
605             f = (f > 255f) ? 255f : (f < 0f) ? 0f : f;
606             return Math.round(f);
607         default:
608             throw new Error JavaDoc(); // can't be reached
609
}
610     }
611
612     /**
613      * Returns the opacity represented by the specified CSSValue.
614      * @param v the value that represents the opacity
615      * @return the opacity between 0 and 1
616      */

617     public static float convertOpacity(Value v) {
618         float r = v.getFloatValue();
619         return (r < 0f) ? 0f : (r > 1f) ? 1f : r;
620     }
621 }
622
Popular Tags