Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/batik/bridge/SVGAltGlyphElementBridge.java


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.Paint;
21  import java.awt.Stroke;
22  import java.awt.font.TextAttribute;
23  import java.text.AttributedCharacterIterator;
24  
25  import org.apache.batik.dom.svg.SVGOMDocument;
26  import org.apache.batik.dom.svg.XMLBaseSupport;
27  import org.apache.batik.dom.util.XLinkSupport;
28  import org.apache.batik.gvt.font.Glyph;
29  import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
30  import org.apache.batik.gvt.text.TextPaintInfo;
31  import org.w3c.dom.Element;
32  import org.w3c.dom.Node;
33  import org.w3c.dom.NodeList;
34  
35  
36  /**
37   * Bridge class for the <altGlyph> element.
38   *
39   * @author <a href="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
40   * @version $Id: SVGAltGlyphElementBridge.java,v 1.18 2005/03/03 01:19:52 deweese Exp $
41   */
42  public class SVGAltGlyphElementBridge extends AbstractSVGBridge
43                                        implements ErrorConstants {
44  
45      public static final AttributedCharacterIterator.Attribute PAINT_INFO
46          = GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO;
47  
48      /**
49       * Constructs a new bridge for the &lt;altGlyph> element.
50       */
51      public SVGAltGlyphElementBridge() {
52      }
53  
54      /**
55       * Returns 'altGlyph'.
56       */
57      public String getLocalName() {
58          return SVG_ALT_GLYPH_TAG;
59      }
60  
61      /**
62       * Constructs an array of Glyphs that represents the specified
63       * &lt;altGlyph> element at the requested size.
64       *
65       * @param ctx The current bridge context.
66       * @param altGlyphElement The altGlyph element to base the SVGGVTGlyphVector
67       * construction on.
68       * @param fontSize The font size of the Glyphs to create.
69       *
70       * @return The new SVGGVTGlyphVector or null if any of the glyphs are
71       * unavailable.
72       */
73      public Glyph[] createAltGlyphArray(BridgeContext ctx,
74                                         Element altGlyphElement,
75                                         float fontSize,
76                                         AttributedCharacterIterator aci) {
77  
78          // get the referenced element
79          String uri = XLinkSupport.getXLinkHref(altGlyphElement);
80  
81          Element refElement = null;
82  
83          try {
84              refElement = ctx.getReferencedElement(altGlyphElement, uri);
85          } catch (BridgeException e) {
86              if (ERR_URI_UNSECURE.equals(e.getCode())) {
87                  ctx.getUserAgent().displayError(e);
88              }
89          }
90  
91          if (refElement == null) {
92              // couldn't find the referenced element
93              return null;
94          }
95          if (!SVG_NAMESPACE_URI.equals(refElement.getNamespaceURI()))
96              return null; // Not an SVG element.
97  
98          // if the referenced element is a glyph
99          if (refElement.getLocalName().equals(SVG_GLYPH_TAG)) {
100 
101             Glyph glyph = getGlyph(ctx, uri, altGlyphElement, fontSize, aci);
102 
103             if (glyph == null) {
104                 // failed to create a glyph for the specified glyph uri
105                 return null;
106             }
107 
108             Glyph[] glyphArray = new Glyph[1];
109             glyphArray[0] = glyph;
110             return glyphArray;
111         }
112 
113         // else should be an altGlyphDef element
114         if (refElement.getLocalName().equals(SVG_ALT_GLYPH_DEF_TAG)) {
115 
116             // if not local import the referenced altGlyphDef
117             // into the current document
118             SVGOMDocument document
119                 = (SVGOMDocument)altGlyphElement.getOwnerDocument();
120             SVGOMDocument refDocument
121                 = (SVGOMDocument)refElement.getOwnerDocument();
122             boolean isLocal = (refDocument == document);
123 
124             Element localRefElement = (isLocal) ? refElement
125                                  : (Element)document.importNode(refElement, true);
126             if (!isLocal) {
127                 // need to attach the imported element to the document and
128                 // then compute the styles and uris
129                 String base = XMLBaseSupport.getCascadedXMLBase(altGlyphElement);
130                 Element g = document.createElementNS(SVG_NAMESPACE_URI, SVG_G_TAG);
131                 g.appendChild(localRefElement);
132                 g.setAttributeNS(XMLBaseSupport.XML_NAMESPACE_URI,
133                                  "xml:base",
134                                  base);
135                 CSSUtilities.computeStyleAndURIs(refElement, 
136                                                  localRefElement, 
137                                                  uri);
138             }
139 
140             // look for glyphRef children
141             NodeList altGlyphDefChildren = localRefElement.getChildNodes();
142             boolean containsGlyphRefNodes = false;
143             int numAltGlyphDefChildren = altGlyphDefChildren.getLength();
144             for (int i = 0; i < numAltGlyphDefChildren; i++) {
145                 Node altGlyphChild = altGlyphDefChildren.item(i);
146                 if (altGlyphChild.getNodeType() == Node.ELEMENT_NODE) {
147                     Element agc = (Element)altGlyphChild;
148                     if (SVG_NAMESPACE_URI.equals(agc.getNamespaceURI()) &&
149                         SVG_GLYPH_REF_TAG.equals(agc.getLocalName())) {
150                         containsGlyphRefNodes = true;
151                         break;
152                     }
153                 }
154             }
155             if (containsGlyphRefNodes) { // process the glyphRef children
156 
157                 NodeList glyphRefNodes
158                     = localRefElement.getElementsByTagNameNS(SVG_NAMESPACE_URI,
159                    SVG_GLYPH_REF_TAG);
160                 int numGlyphRefNodes = glyphRefNodes.getLength();
161                 Glyph[] glyphArray = new Glyph[numGlyphRefNodes];
162                 for (int i = 0; i < numGlyphRefNodes; i++) {
163                     // get the referenced glyph element
164                     Element glyphRefElement = (Element)glyphRefNodes.item(i);
165                     String glyphUri = XLinkSupport.getXLinkHref(glyphRefElement);
166 
167                     Glyph glyph
168                         = getGlyph(ctx, glyphUri, glyphRefElement, fontSize, aci);
169                     if (glyph == null) {
170                         // failed to create a glyph for the specified glyph uri
171                         return null;
172                     }
173                     glyphArray[i] = glyph;
174                 }
175                 return glyphArray;
176 
177             } else { // try looking for altGlyphItem children
178 
179                 NodeList altGlyphItemNodes
180                     = localRefElement.getElementsByTagNameNS
181         (SVG_NAMESPACE_URI, SVG_ALT_GLYPH_ITEM_TAG);
182                 int numAltGlyphItemNodes = altGlyphItemNodes.getLength();
183                 if (numAltGlyphItemNodes > 0) {
184                     boolean foundMatchingGlyph = false;
185                     Glyph[] glyphArray = null;
186 
187                     //look through all altGlyphItem to find the one
188                     //that have all its glyphs available
189 
190                     for (int i = 0; i < numAltGlyphItemNodes && !foundMatchingGlyph ; i++) {
191 
192                         // try to find a resolvable glyphRef
193                         Element altGlyphItemElement = (Element)altGlyphItemNodes.item(i);
194                         NodeList altGlyphRefNodes
195                             = altGlyphItemElement.getElementsByTagNameNS
196           (SVG_NAMESPACE_URI, SVG_GLYPH_REF_TAG);
197                         int numAltGlyphRefNodes = altGlyphRefNodes.getLength();
198 
199                         glyphArray = new Glyph[numAltGlyphRefNodes];
200 
201                         // consider that all glyphs are available
202                         // and check if they can be found
203                         foundMatchingGlyph = true;
204 
205                         for (int j = 0; j < numAltGlyphRefNodes; j++) {
206                             // get the referenced glyph element
207                             Element glyphRefElement = (Element)altGlyphRefNodes.item(j);
208                             String glyphUri = XLinkSupport.getXLinkHref(glyphRefElement);
209 
210                             Glyph glyph = getGlyph(ctx, glyphUri, glyphRefElement, fontSize, aci);
211                             if (glyph != null) {
212                                 // found a matching glyph for this altGlyphItem
213                                 glyphArray[j] = glyph;
214                             }
215                             else{
216                                 //this altGlyphItem is not good
217                                 //seek for the next one
218                                 foundMatchingGlyph = false;
219                                 break;
220                             }
221                         }
222                     }
223                     if (!foundMatchingGlyph) {
224                         // couldn't find a  alGlyphItem
225                         // with all its glyphs available
226                         // so stop and return null
227                         return null;
228                     }
229                     
230                     return glyphArray;
231                 }
232             }
233         }
234 
235 
236         /*
237         // reference is not to a valid element type, throw an exception
238         throw new BridgeException(altGlyphElement, ERR_URI_BAD_TARGET,
239                                   new Object[] {uri});
240         */
241         //reference not valid, no altGlyph created
242         return null;
243     }
244 
245 
246     /**
247      * Returns a Glyph object that represents the glyph at the specified URI
248      * scaled to the required font size.
249      *
250      * @param ctx The bridge context.
251      * @param glyphUri The URI of the glyph to retreive.
252      * @param altGlyphElement The element that references the glyph.
253      * @param fontSize Indicates the required size of the glyph.
254      * @return The Glyph or null if the glyph URI is not available.
255      */
256     private Glyph getGlyph(BridgeContext ctx,
257                            String glyphUri,
258                            Element altGlyphElement,
259                            float fontSize,
260                            AttributedCharacterIterator aci) {
261 
262         Element refGlyphElement = null;
263         try {
264             refGlyphElement = ctx.getReferencedElement(altGlyphElement, 
265                                                        glyphUri);
266         } catch (BridgeException e) {
267             // this is ok, it is possible that the glyph at the given
268             // uri is not available. 
269 
270             // Display an error message if a security exception occured
271             if (ERR_URI_UNSECURE.equals(e.getCode())) {
272                 ctx.getUserAgent().displayError(e);
273             }
274         }
275 
276         if ((refGlyphElement == null) ||
277             (!SVG_NAMESPACE_URI.equals(refGlyphElement.getNamespaceURI())) ||
278             (!SVG_GLYPH_TAG.equals(refGlyphElement.getLocalName())))
279             // couldn't find the referenced glyph element,
280             // or referenced element not a glyph
281             return null;
282 
283         // see if the referenced glyph element is local
284         SVGOMDocument document
285             = (SVGOMDocument)altGlyphElement.getOwnerDocument();
286         SVGOMDocument refDocument
287             = (SVGOMDocument)refGlyphElement.getOwnerDocument();
288         boolean isLocal = (refDocument == document);
289 
290         // if not local, import both the glyph and its font-face element
291         Element localGlyphElement = null;
292         Element localFontFaceElement = null;
293         Element localFontElement = null;
294         if (isLocal) {
295             localGlyphElement = refGlyphElement;
296             localFontElement = (Element)localGlyphElement.getParentNode();
297             NodeList fontFaceElements
298                 = localFontElement.getElementsByTagNameNS
299     (SVG_NAMESPACE_URI, SVG_FONT_FACE_TAG);
300             if (fontFaceElements.getLength() > 0) {
301                 localFontFaceElement = (Element)fontFaceElements.item(0);
302             }
303 
304         } else {
305             // import the whole font
306             localFontElement = (Element)document.importNode
307                 (refGlyphElement.getParentNode(), true);
308             String base = XMLBaseSupport.getCascadedXMLBase(altGlyphElement);
309             Element g = document.createElementNS(SVG_NAMESPACE_URI, SVG_G_TAG);
310             g.appendChild(localFontElement);
311             g.setAttributeNS(XMLBaseSupport.XML_NAMESPACE_URI,
312                              "xml:base",
313                              base);
314             CSSUtilities.computeStyleAndURIs(
315                 (Element)refGlyphElement.getParentNode(), 
316                 localFontElement, glyphUri);
317 
318             // get the local glyph element
319             String glyphId = refGlyphElement.getAttributeNS
320                 (null, SVG_ID_ATTRIBUTE);
321             NodeList glyphElements = localFontElement.getElementsByTagNameNS
322     (SVG_NAMESPACE_URI, SVG_GLYPH_TAG);
323             for (int i = 0; i < glyphElements.getLength(); i++) {
324                 Element glyphElem = (Element)glyphElements.item(i);
325                 if (glyphElem.getAttributeNS(null, SVG_ID_ATTRIBUTE).equals(glyphId)) {
326                     localGlyphElement = glyphElem;
327                     break;
328                 }
329             }
330             // get the local font-face element
331             NodeList fontFaceElements
332                 = localFontElement.getElementsByTagNameNS
333     (SVG_NAMESPACE_URI, SVG_FONT_FACE_TAG);
334             if (fontFaceElements.getLength() > 0) {
335                 localFontFaceElement = (Element)fontFaceElements.item(0);
336             }
337         }
338 
339         // if couldn't find the glyph or its font-face return null
340         if (localGlyphElement == null || localFontFaceElement == null) {
341             return null;
342         }
343 
344         SVGFontFaceElementBridge fontFaceBridge
345             = (SVGFontFaceElementBridge)ctx.getBridge(localFontFaceElement);
346         SVGFontFace fontFace = fontFaceBridge.createFontFace
347             (ctx, localFontFaceElement);
348         SVGGlyphElementBridge glyphBridge
349             = (SVGGlyphElementBridge)ctx.getBridge(localGlyphElement);
350 
351         aci.first();
352         TextPaintInfo tpi = (TextPaintInfo)aci.getAttribute(PAINT_INFO);
353 
354         return glyphBridge.createGlyph(ctx, localGlyphElement, altGlyphElement,
355                                        -1, fontSize, fontFace, tpi);
356     }
357 }