KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Copyright 2001-2003 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.geom.AffineTransform JavaDoc;
21 import java.util.StringTokenizer JavaDoc;
22
23 import org.apache.batik.parser.AWTTransformProducer;
24 import org.apache.batik.parser.FragmentIdentifierHandler;
25 import org.apache.batik.parser.FragmentIdentifierParser;
26 import org.apache.batik.parser.ParseException;
27 import org.apache.batik.parser.PreserveAspectRatioParser;
28 import org.apache.batik.util.SVGConstants;
29 import org.w3c.dom.Document JavaDoc;
30 import org.w3c.dom.Element JavaDoc;
31 import org.w3c.dom.Node JavaDoc;
32 import org.w3c.dom.svg.SVGPreserveAspectRatio;
33
34 /**
35  * This class provides convenient methods to handle viewport.
36  *
37  * @author <a HREF="mailto:tkormann@apache.org">Thierry Kormann</a>
38  * @version $Id: ViewBox.java,v 1.13 2005/03/27 08:58:30 cam Exp $
39  */

40 public abstract class ViewBox implements SVGConstants, ErrorConstants {
41
42     /**
43      * No instance of this class is required.
44      */

45     protected ViewBox() { }
46
47     /**
48      * Parses the specified reference (from a URI) and returns the appropriate
49      * transform.
50      *
51      * @param ref the reference of the URI that may specify additional attribute
52      * values such as the viewBox, preserveAspectRatio or a transform
53      * @param e the element interested in its view transform
54      * @param w the width of the effective viewport
55      * @param h The height of the effective viewport
56      * @exception BridgeException if an error occured while computing the
57      * preserveAspectRatio transform
58      */

59     public static AffineTransform JavaDoc getViewTransform(String JavaDoc ref,
60                                                    Element JavaDoc e,
61                                                    float w,
62                                                    float h) {
63
64         // no reference has been specified, no extra viewBox is defined
65
if (ref == null || ref.length() == 0) {
66             return getPreserveAspectRatioTransform(e, w, h);
67         }
68
69         ViewHandler vh = new ViewHandler();
70         FragmentIdentifierParser p = new FragmentIdentifierParser();
71         p.setFragmentIdentifierHandler(vh);
72         p.parse(ref);
73
74         Element JavaDoc attrDefElement = e; // the element that defines the attributes
75
if (vh.hasId) {
76             Document JavaDoc document = e.getOwnerDocument();
77             attrDefElement = document.getElementById(vh.id);
78         }
79         if (attrDefElement == null) {
80             throw new BridgeException(e, ERR_URI_MALFORMED,
81                                       new Object JavaDoc[] {ref});
82         }
83         // if the referenced element is not a view, the attribute
84
// values to use are those defined on the enclosed svg element
85
if (!(attrDefElement.getNamespaceURI().equals(SVG_NAMESPACE_URI)
86               && attrDefElement.getLocalName().equals(SVG_VIEW_TAG))) {
87             attrDefElement = getClosestAncestorSVGElement(e);
88         }
89
90         // 'viewBox'
91
float [] vb;
92         if (vh.hasViewBox) {
93             vb = vh.viewBox;
94         } else {
95             String JavaDoc viewBoxStr = attrDefElement.getAttributeNS
96                 (null, SVG_VIEW_BOX_ATTRIBUTE);
97             vb = parseViewBoxAttribute(attrDefElement, viewBoxStr);
98         }
99
100         // 'preserveAspectRatio'
101
short align;
102         boolean meet;
103         if (vh.hasPreserveAspectRatio) {
104             align = vh.align;
105             meet = vh.meet;
106         } else {
107             String JavaDoc aspectRatio = attrDefElement.getAttributeNS
108                 (null, SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE);
109             PreserveAspectRatioParser pp = new PreserveAspectRatioParser();
110             ViewHandler ph = new ViewHandler();
111             pp.setPreserveAspectRatioHandler(ph);
112             try {
113                 pp.parse(aspectRatio);
114             } catch (ParseException ex) {
115                 throw new BridgeException
116                     (attrDefElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
117                      new Object JavaDoc[] {SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE,
118                                        aspectRatio, ex});
119             }
120             align = ph.align;
121             meet = ph.meet;
122         }
123
124         // the additional transform that may appear on the URI
125
AffineTransform JavaDoc transform
126             = getPreserveAspectRatioTransform(vb, align, meet, w, h);
127         if (vh.hasTransform) {
128             transform.concatenate(vh.getAffineTransform());
129         }
130         return transform;
131     }
132
133     /**
134      * Returns the closest svg element ancestor of the specified element.
135      *
136      * @param e the element on which to start the svg element lookup
137      */

138     private static Element JavaDoc getClosestAncestorSVGElement(Element JavaDoc e) {
139         for (Node JavaDoc n = e;
140               n != null && n.getNodeType() == Node.ELEMENT_NODE;
141               n = n.getParentNode()) {
142             Element JavaDoc tmp = (Element JavaDoc)n;
143             if (tmp.getNamespaceURI().equals(SVG_NAMESPACE_URI)
144                 && tmp.getLocalName().equals(SVG_SVG_TAG)) {
145                 return tmp;
146             }
147         }
148         return null;
149     }
150
151     /**
152      * Returns the transformation matrix to apply to initalize a viewport or
153      * null if the specified viewBox disables the rendering of the element.
154      *
155      * @param e the element with a viewbox
156      * @param w the width of the effective viewport
157      * @param h The height of the effective viewport
158      */

159     public static AffineTransform JavaDoc getPreserveAspectRatioTransform(Element JavaDoc e,
160                                                                   float w,
161                                                                   float h) {
162         String JavaDoc viewBox
163             = e.getAttributeNS(null, SVG_VIEW_BOX_ATTRIBUTE);
164
165         String JavaDoc aspectRatio
166             = e.getAttributeNS(null, SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE);
167
168         return getPreserveAspectRatioTransform(e, viewBox, aspectRatio, w, h);
169     }
170
171     /**
172      * Returns the transformation matrix to apply to initalize a viewport or
173      * null if the specified viewBox disables the rendering of the element.
174      *
175      * @param e the element with a viewbox
176      * @param viewBox the viewBox definition
177      * @param w the width of the effective viewport
178      * @param h The height of the effective viewport
179      */

180     public static
181         AffineTransform JavaDoc getPreserveAspectRatioTransform(Element JavaDoc e,
182                                                         String JavaDoc viewBox,
183                                                         String JavaDoc aspectRatio,
184                                                         float w,
185                                                         float h) {
186
187         // no viewBox specified
188
if (viewBox.length() == 0) {
189             return new AffineTransform JavaDoc();
190         }
191         float[] vb = parseViewBoxAttribute(e, viewBox);
192
193         // 'preserveAspectRatio' attribute
194
PreserveAspectRatioParser p = new PreserveAspectRatioParser();
195         ViewHandler ph = new ViewHandler();
196         p.setPreserveAspectRatioHandler(ph);
197         try {
198             p.parse(aspectRatio);
199         } catch (ParseException ex) {
200             throw new BridgeException
201                 (e, ERR_ATTRIBUTE_VALUE_MALFORMED,
202                  new Object JavaDoc[] {SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE,
203                                    aspectRatio, ex});
204         }
205
206         return getPreserveAspectRatioTransform(vb, ph.align, ph.meet, w, h);
207     }
208
209     /**
210      * Returns the transformation matrix to apply to initalize a viewport or
211      * null if the specified viewBox disables the rendering of the element.
212      *
213      * @param e the element with a viewbox
214      * @param vb the viewBox definition as float
215      * @param w the width of the effective viewport
216      * @param h The height of the effective viewport
217      */

218     public static
219         AffineTransform JavaDoc getPreserveAspectRatioTransform(Element JavaDoc e,
220                             float [] vb,
221                             float w,
222                             float h) {
223
224         String JavaDoc aspectRatio
225             = e.getAttributeNS(null, SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE);
226
227         // 'preserveAspectRatio' attribute
228
PreserveAspectRatioParser p = new PreserveAspectRatioParser();
229         ViewHandler ph = new ViewHandler();
230         p.setPreserveAspectRatioHandler(ph);
231         try {
232             p.parse(aspectRatio);
233         } catch (ParseException ex) {
234             throw new BridgeException
235                 (e, ERR_ATTRIBUTE_VALUE_MALFORMED,
236                  new Object JavaDoc[] {SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE,
237                                    aspectRatio, ex});
238         }
239
240         return getPreserveAspectRatioTransform(vb, ph.align, ph.meet, w, h);
241     }
242
243     /**
244      * Parses a viewBox attribute.
245      *
246      * @param value the viewBox
247      * @return The 4 viewbox components or null.
248      */

249     public static float[] parseViewBoxAttribute(Element JavaDoc e, String JavaDoc value) {
250         if (value.length() == 0) {
251             return null;
252         }
253         int i = 0;
254         float[] vb = new float[4];
255         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(value, " ,");
256         try {
257             while (i < 4 && st.hasMoreTokens()) {
258                 vb[i] = Float.parseFloat(st.nextToken());
259                 i++;
260             }
261         } catch (NumberFormatException JavaDoc ex) {
262             throw new BridgeException
263                 (e, ERR_ATTRIBUTE_VALUE_MALFORMED,
264                  new Object JavaDoc[] {SVG_VIEW_BOX_ATTRIBUTE, value, ex});
265         }
266         if (i != 4) {
267             throw new BridgeException
268                 (e, ERR_ATTRIBUTE_VALUE_MALFORMED,
269                  new Object JavaDoc[] {SVG_VIEW_BOX_ATTRIBUTE, value});
270         }
271         // A negative value for <width> or <height> is an error
272
if (vb[2] < 0 || vb[3] < 0) {
273             throw new BridgeException
274                 (e, ERR_ATTRIBUTE_VALUE_MALFORMED,
275                  new Object JavaDoc[] {SVG_VIEW_BOX_ATTRIBUTE, value});
276         }
277         // A value of zero for width or height disables rendering of the element
278
if (vb[2] == 0 || vb[3] == 0) {
279             return null; // <!> FIXME : must disable !
280
}
281         return vb;
282     }
283
284     /**
285      * Returns the preserveAspectRatio transform according to the specified
286      * parameters.
287      *
288      * @param vb the viewBox definition
289      * @param align the alignment definition
290      * @param meet true means 'meet', false means 'slice'
291      * @param w the width of the region in which the document has to fit into
292      * @param h the height of the region in which the document has to fit into
293      */

294     public static
295         AffineTransform JavaDoc getPreserveAspectRatioTransform(float [] vb,
296                                                         short align,
297                                                         boolean meet,
298                                                         float w,
299                                                         float h) {
300         if (vb == null) {
301             return new AffineTransform JavaDoc();
302         }
303
304         AffineTransform JavaDoc result = new AffineTransform JavaDoc();
305         float vpar = vb[2] / vb[3];
306         float svgar = w / h;
307
308         if (align == SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE) {
309             result.scale(w / vb[2], h / vb[3]);
310             result.translate(-vb[0], -vb[1]);
311         } else if (vpar < svgar && meet || vpar >= svgar && !meet) {
312             float sf = h / vb[3];
313             result.scale(sf, sf);
314             switch (align) {
315             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN:
316             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID:
317             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX:
318                 result.translate(-vb[0], -vb[1]);
319                 break;
320             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN:
321             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID:
322             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX:
323                 result.translate(-vb[0] - (vb[2] - w * vb[3] / h) / 2 , -vb[1]);
324                 break;
325             default:
326                 result.translate(-vb[0] - (vb[2] - w * vb[3] / h) , -vb[1]);
327             }
328         } else {
329             float sf = w / vb[2];
330             result.scale(sf, sf);
331             switch (align) {
332             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN:
333             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN:
334             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN:
335                 result.translate(-vb[0], -vb[1]);
336                 break;
337             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID:
338             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID:
339             case SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID:
340                 result.translate(-vb[0], -vb[1] - (vb[3] - h * vb[2] / w) / 2);
341                 break;
342             default:
343                 result.translate(-vb[0], -vb[1] - (vb[3] - h * vb[2] / w));
344             }
345         }
346         return result;
347     }
348
349     /**
350      * This class can be used to store the value of the attribute viewBox or can
351      * also be used to store the various attribute value that can be specified
352      * on a SVG URI fragments.
353      */

354     protected static class ViewHandler extends AWTTransformProducer
355         implements FragmentIdentifierHandler {
356
357
358         /**
359          * Constructs a new <tt>ViewHandler</tt> instance.
360          */

361         protected ViewHandler() { }
362
363         //////////////////////////////////////////////////////////////////////
364
// TransformListHandler
365
//////////////////////////////////////////////////////////////////////
366

367         public boolean hasTransform;
368
369         public void endTransformList() throws ParseException {
370             super.endTransformList();
371             hasTransform = true;
372         }
373
374         //////////////////////////////////////////////////////////////////////
375
// FragmentIdentifierHandler
376
//////////////////////////////////////////////////////////////////////
377

378         public boolean hasId;
379         public boolean hasViewBox;
380         public boolean hasViewTargetParams;
381         public boolean hasZoomAndPanParams;
382
383         public String JavaDoc id;
384         public float [] viewBox;
385         public String JavaDoc viewTargetParams;
386         public boolean isMagnify;
387
388         /**
389          * Invoked when the fragment identifier starts.
390          * @exception ParseException if an error occured while processing the
391          * fragment identifier
392          */

393         public void startFragmentIdentifier() throws ParseException { }
394
395         /**
396          * Invoked when an ID has been parsed.
397          * @param s The string that represents the parsed ID.
398          * @exception ParseException if an error occured while processing the
399          * fragment identifier
400          */

401         public void idReference(String JavaDoc s) throws ParseException {
402             id = s;
403             hasId = true;
404         }
405
406         /**
407          * Invoked when 'viewBox(x,y,width,height)' has been parsed.
408          * @param x the viewbox x coordinate
409          * @param y the viewbox y coordinate
410          * @param width the viewbox width
411          * @param height the viewbox height
412          * @exception ParseException if an error occured while processing the
413          * fragment identifier
414          */

415         public void viewBox(float x, float y, float width, float height)
416             throws ParseException {
417
418             hasViewBox = true;
419             viewBox = new float[4];
420             viewBox[0] = x;
421             viewBox[1] = y;
422             viewBox[2] = width;
423             viewBox[3] = height;
424         }
425
426         /**
427          * Invoked when a view target specification starts.
428          * @exception ParseException if an error occured while processing the
429          * fragment identifier
430          */

431         public void startViewTarget() throws ParseException { }
432
433         /**
434          * Invoked when a identifier has been parsed within a view target
435          * specification.
436          * @param name the target name.
437          * @exception ParseException if an error occured while processing the
438          * fragment identifier
439          */

440         public void viewTarget(String JavaDoc name) throws ParseException {
441             viewTargetParams = name;
442             hasViewTargetParams = true;
443         }
444
445         /**
446          * Invoked when a view target specification ends.
447          * @exception ParseException if an error occured while processing the
448          * fragment identifier
449          */

450         public void endViewTarget() throws ParseException { }
451
452         /**
453          * Invoked when a 'zoomAndPan' specification has been parsed.
454          * @param magnify true if 'magnify' has been parsed.
455          * @exception ParseException if an error occured while processing the
456          * fragment identifier
457          */

458         public void zoomAndPan(boolean magnify) {
459             isMagnify = magnify;
460             hasZoomAndPanParams = true;
461         }
462
463         /**
464          * Invoked when the fragment identifier ends.
465          * @exception ParseException if an error occured while processing the
466          * fragment identifier
467          */

468         public void endFragmentIdentifier() throws ParseException { }
469
470         //////////////////////////////////////////////////////////////////////
471
// PreserveAspectRatioHandler
472
//////////////////////////////////////////////////////////////////////
473

474         public boolean hasPreserveAspectRatio;
475
476         public short align;
477         public boolean meet = true;
478
479         /**
480          * Invoked when the PreserveAspectRatio parsing starts.
481          * @exception ParseException if an error occured while processing
482          * the transform
483          */

484         public void startPreserveAspectRatio() throws ParseException { }
485
486         /**
487          * Invoked when 'none' been parsed.
488          * @exception ParseException if an error occured while processing
489          * the transform
490          */

491         public void none() throws ParseException {
492             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE;
493         }
494
495         /**
496          * Invoked when 'xMaxYMax' has been parsed.
497          * @exception ParseException if an error occured while processing
498          * the transform
499          */

500         public void xMaxYMax() throws ParseException {
501             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX;
502         }
503
504         /**
505          * Invoked when 'xMaxYMid' has been parsed.
506          * @exception ParseException if an error occured while processing
507          * the transform
508          */

509         public void xMaxYMid() throws ParseException {
510             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID;
511         }
512
513         /**
514          * Invoked when 'xMaxYMin' has been parsed.
515          * @exception ParseException if an error occured while processing
516          * the transform
517          */

518         public void xMaxYMin() throws ParseException {
519             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN;
520         }
521
522         /**
523          * Invoked when 'xMidYMax' has been parsed.
524          * @exception ParseException if an error occured while processing
525          * the transform
526          */

527         public void xMidYMax() throws ParseException {
528             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX;
529         }
530
531         /**
532          * Invoked when 'xMidYMid' has been parsed.
533          * @exception ParseException if an error occured while processing
534          * the transform
535          */

536         public void xMidYMid() throws ParseException {
537             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID;
538         }
539
540         /**
541          * Invoked when 'xMidYMin' has been parsed.
542          * @exception ParseException if an error occured while processing
543          * the transform
544          */

545         public void xMidYMin() throws ParseException {
546             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN;
547         }
548
549         /**
550          * Invoked when 'xMinYMax' has been parsed.
551          * @exception ParseException if an error occured while processing
552          * the transform
553          */

554         public void xMinYMax() throws ParseException {
555             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX;
556         }
557
558         /**
559          * Invoked when 'xMinYMid' has been parsed.
560          * @exception ParseException if an error occured while processing
561          * the transform
562          */

563         public void xMinYMid() throws ParseException {
564             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID;
565         }
566
567         /**
568          * Invoked when 'xMinYMin' has been parsed.
569          * @exception ParseException if an error occured while processing
570          * the transform
571          */

572         public void xMinYMin() throws ParseException {
573             align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN;
574         }
575
576         /**
577          * Invoked when 'meet' has been parsed.
578          * @exception ParseException if an error occured while processing
579          * the transform
580          */

581         public void meet() throws ParseException {
582             meet = true;
583         }
584
585         /**
586          * Invoked when 'slice' has been parsed.
587          * @exception ParseException if an error occured while processing
588          * the transform
589          */

590         public void slice() throws ParseException {
591             meet = false;
592         }
593
594         /**
595          * Invoked when the PreserveAspectRatio parsing ends.
596          * @exception ParseException if an error occured while processing
597          * the transform
598          */

599         public void endPreserveAspectRatio() throws ParseException {
600             hasPreserveAspectRatio = true;
601         }
602     }
603 }
604
Popular Tags