001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.bridge;
020:
021: import java.awt.font.TextAttribute;
022: import java.util.ArrayList;
023: import java.util.StringTokenizer;
024:
025: import org.apache.batik.css.engine.SVGCSSEngine;
026: import org.apache.batik.css.engine.value.Value;
027: import org.apache.batik.gvt.TextNode;
028: import org.apache.batik.util.CSSConstants;
029: import org.w3c.dom.Element;
030: import org.w3c.dom.Node;
031: import org.w3c.dom.css.CSSPrimitiveValue;
032:
033: /**
034: * A collection of utility method for text.
035: *
036: * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
037: * @author <a href="mailto:bill.haneman@ireland.sun.com">Bill Haneman</a>
038: * @version $Id: TextUtilities.java 501922 2007-01-31 17:47:47Z dvholten $
039: */
040: public abstract class TextUtilities implements CSSConstants,
041: ErrorConstants {
042:
043: /**
044: * Returns the content of the given element.
045: */
046: public static String getElementContent(Element e) {
047: StringBuffer result = new StringBuffer();
048: for (Node n = e.getFirstChild(); n != null; n = n
049: .getNextSibling()) {
050: switch (n.getNodeType()) {
051: case Node.ELEMENT_NODE:
052: result.append(getElementContent((Element) n));
053: break;
054: case Node.CDATA_SECTION_NODE:
055: case Node.TEXT_NODE:
056: result.append(n.getNodeValue());
057: }
058: }
059: return result.toString();
060: }
061:
062: /**
063: * Returns the float list that represents a set of horizontal
064: * values or percentage.
065: *
066: * @param element the element that defines the specified coordinates
067: * @param attrName the name of the attribute (used by error handling)
068: * @param valueStr the delimited string containing values of the coordinate
069: * @param ctx the bridge context
070: */
071: public static ArrayList svgHorizontalCoordinateArrayToUserSpace(
072: Element element, String attrName, String valueStr,
073: BridgeContext ctx) {
074:
075: UnitProcessor.Context uctx = UnitProcessor.createContext(ctx,
076: element);
077: ArrayList values = new ArrayList();
078: StringTokenizer st = new StringTokenizer(valueStr, ", ", false);
079: while (st.hasMoreTokens()) {
080: values.add(new Float(UnitProcessor
081: .svgHorizontalCoordinateToUserSpace(st.nextToken(),
082: attrName, uctx)));
083: }
084: return values;
085: }
086:
087: /**
088: * Returns the float list that represents a set of values or percentage.
089: *
090: *
091: * @param element the element that defines the specified coordinates
092: * @param attrName the name of the attribute (used by error handling)
093: * @param valueStr the delimited string containing values of the coordinate
094: * @param ctx the bridge context
095: */
096: public static ArrayList svgVerticalCoordinateArrayToUserSpace(
097: Element element, String attrName, String valueStr,
098: BridgeContext ctx) {
099:
100: UnitProcessor.Context uctx = UnitProcessor.createContext(ctx,
101: element);
102: ArrayList values = new ArrayList();
103: StringTokenizer st = new StringTokenizer(valueStr, ", ", false);
104: while (st.hasMoreTokens()) {
105: values.add(new Float(UnitProcessor
106: .svgVerticalCoordinateToUserSpace(st.nextToken(),
107: attrName, uctx)));
108: }
109: return values;
110: }
111:
112: public static ArrayList svgRotateArrayToFloats(Element element,
113: String attrName, String valueStr, BridgeContext ctx) {
114:
115: StringTokenizer st = new StringTokenizer(valueStr, ", ", false);
116: ArrayList values = new ArrayList();
117: String s;
118: while (st.hasMoreTokens()) {
119: try {
120: s = st.nextToken();
121: values.add(new Float(Math.toRadians(SVGUtilities
122: .convertSVGNumber(s))));
123: } catch (NumberFormatException nfEx) {
124: throw new BridgeException(ctx, element, nfEx,
125: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
126: attrName, valueStr });
127: }
128: }
129: return values;
130: }
131:
132: /**
133: * Converts the font-size CSS value to a float value.
134: * @param e the element
135: */
136: public static Float convertFontSize(Element e) {
137: Value v = CSSUtilities.getComputedStyle(e,
138: SVGCSSEngine.FONT_SIZE_INDEX);
139: return new Float(v.getFloatValue());
140: }
141:
142: /**
143: * Converts the font-style CSS value to a float value.
144: * @param e the element
145: */
146: public static Float convertFontStyle(Element e) {
147: Value v = CSSUtilities.getComputedStyle(e,
148: SVGCSSEngine.FONT_STYLE_INDEX);
149: switch (v.getStringValue().charAt(0)) {
150: case 'n':
151: return TextAttribute.POSTURE_REGULAR;
152: default:
153: return TextAttribute.POSTURE_OBLIQUE;
154: }
155: }
156:
157: /**
158: * Converts the font-stretch CSS value to a float value.
159: * @param e the element
160: */
161: public static Float convertFontStretch(Element e) {
162: Value v = CSSUtilities.getComputedStyle(e,
163: SVGCSSEngine.FONT_STRETCH_INDEX);
164: String s = v.getStringValue();
165: switch (s.charAt(0)) {
166: case 'u':
167: if (s.charAt(6) == 'c') {
168: return TextAttribute.WIDTH_CONDENSED;
169: } else {
170: return TextAttribute.WIDTH_EXTENDED;
171: }
172:
173: case 'e':
174: if (s.charAt(6) == 'c') {
175: return TextAttribute.WIDTH_CONDENSED;
176: } else {
177: if (s.length() == 8) {
178: return TextAttribute.WIDTH_SEMI_EXTENDED;
179: } else {
180: return TextAttribute.WIDTH_EXTENDED;
181: }
182: }
183:
184: case 's':
185: if (s.charAt(6) == 'c') {
186: return TextAttribute.WIDTH_SEMI_CONDENSED;
187: } else {
188: return TextAttribute.WIDTH_SEMI_EXTENDED;
189: }
190:
191: default:
192: return TextAttribute.WIDTH_REGULAR;
193: }
194: }
195:
196: /**
197: * Converts the font-weight CSS value to a float value.
198: * @param e the element
199: */
200: public static Float convertFontWeight(Element e) {
201: Value v = CSSUtilities.getComputedStyle(e,
202: SVGCSSEngine.FONT_WEIGHT_INDEX);
203: float f = v.getFloatValue();
204: switch ((int) f) {
205: case 100:
206: return TextAttribute.WEIGHT_EXTRA_LIGHT;
207: case 200:
208: return TextAttribute.WEIGHT_LIGHT;
209: case 300:
210: return TextAttribute.WEIGHT_DEMILIGHT;
211: case 400:
212: return TextAttribute.WEIGHT_REGULAR;
213: case 500:
214: return TextAttribute.WEIGHT_SEMIBOLD;
215: default:
216: return TextAttribute.WEIGHT_BOLD;
217: /* Would like to do this but the JDK 1.3 & 1.4
218: seems to drop back to 'REGULAR' instead of 'BOLD'
219: if there is not a match.
220: case 700:
221: return TextAttribute.WEIGHT_HEAVY;
222: case 800:
223: return TextAttribute.WEIGHT_EXTRABOLD;
224: case 900:
225: return TextAttribute.WEIGHT_ULTRABOLD;
226: */
227: }
228: }
229:
230: /**
231: * Converts the text-anchor CSS value to a TextNode.Anchor.
232: * @param e the element
233: */
234: public static TextNode.Anchor convertTextAnchor(Element e) {
235: Value v = CSSUtilities.getComputedStyle(e,
236: SVGCSSEngine.TEXT_ANCHOR_INDEX);
237: switch (v.getStringValue().charAt(0)) {
238: case 's':
239: return TextNode.Anchor.START;
240: case 'm':
241: return TextNode.Anchor.MIDDLE;
242: default:
243: return TextNode.Anchor.END;
244: }
245: }
246:
247: /**
248: * Converts a baseline-shift CSS value to a value usable as a text
249: * attribute, or null.
250: * @param e the element
251: */
252: public static Object convertBaselineShift(Element e) {
253: Value v = CSSUtilities.getComputedStyle(e,
254: SVGCSSEngine.BASELINE_SHIFT_INDEX);
255: if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
256: String s = v.getStringValue();
257: switch (s.charAt(2)) {
258: case 'p': //suPerscript
259: return TextAttribute.SUPERSCRIPT_SUPER;
260:
261: case 'b': //suBscript
262: return TextAttribute.SUPERSCRIPT_SUB;
263:
264: default:
265: return null;
266: }
267: } else {
268: return new Float(v.getFloatValue());
269: }
270: }
271:
272: /**
273: * Converts a kerning CSS value to a value usable as a text
274: * attribute, or null.
275: * @param e the element
276: */
277: public static Float convertKerning(Element e) {
278: Value v = CSSUtilities.getComputedStyle(e,
279: SVGCSSEngine.KERNING_INDEX);
280: if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
281: return null;
282: }
283: return new Float(v.getFloatValue());
284: }
285:
286: /**
287: * Converts a letter-spacing CSS value to a value usable as a text
288: * attribute, or null.
289: * @param e the element
290: */
291: public static Float convertLetterSpacing(Element e) {
292: Value v = CSSUtilities.getComputedStyle(e,
293: SVGCSSEngine.LETTER_SPACING_INDEX);
294: if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
295: return null;
296: }
297: return new Float(v.getFloatValue());
298: }
299:
300: /**
301: * Converts a word-spacing CSS value to a value usable as a text
302: * attribute, or null.
303: * @param e the element
304: */
305: public static Float convertWordSpacing(Element e) {
306: Value v = CSSUtilities.getComputedStyle(e,
307: SVGCSSEngine.WORD_SPACING_INDEX);
308: if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
309: return null;
310: }
311: return new Float(v.getFloatValue());
312: }
313: }
|