001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.perseus.model;
028:
029: import com.sun.perseus.util.SVGConstants;
030:
031: import com.sun.perseus.j2d.RenderGraphics;
032:
033: import org.w3c.dom.DOMException;
034:
035: /**
036: * A <code>HKern</code> corresponds to an SVG <code><hkern></code>
037: * element. <br />
038: *
039: * @version $Id: HKern.java,v 1.5 2006/06/29 10:47:32 ln156897 Exp $
040: */
041: public class HKern extends ElementNode {
042: /**
043: * Only the k trait is required on <hkern>
044: */
045: static final String[] REQUIRED_TRAITS = { SVGConstants.SVG_K_ATTRIBUTE };
046:
047: /**
048: * Unicode ranges
049: */
050: protected int[][] u1, u2;
051:
052: /**
053: * Name matches
054: */
055: protected String[] g1, g2;
056:
057: /**
058: * Adjusted horizontal advance
059: */
060: protected float k;
061:
062: /**
063: * For use by <code>Font</code>
064: */
065: protected HKern nextHKern;
066:
067: /**
068: * Constructor.
069: *
070: * @param ownerDocument this element's owner <code>DocumentNode</code>
071: */
072: public HKern(final DocumentNode ownerDocument) {
073: super (ownerDocument);
074: }
075:
076: /**
077: * @return the SVGConstants.SVG_HKERN_TAG value
078: */
079:
080: public String getLocalName() {
081: return SVGConstants.SVG_HKERN_TAG;
082: }
083:
084: /**
085: * Used by <code>DocumentNode</code> to create a new instance from
086: * a prototype <code>HKern</code>.
087: *
088: * @param doc the <code>DocumentNode</code> for which a new node is
089: * should be created.
090: * @return a new <code>HKern</code> for the requested document.
091: */
092: public ElementNode newInstance(final DocumentNode doc) {
093: return new HKern(doc);
094: }
095:
096: /**
097: * Sets this kerning entry's first match
098: *
099: * @param u1 the new matching unicode ranges.
100: *
101: * @throws IllegalArgumentException if the input array has an entry which
102: * is not of length 2.
103: */
104: public void setU1(final int[][] u1) {
105: if (u1 != null) {
106: for (int i = 0; i < u1.length; i++) {
107: if (u1[i] == null || u1[i].length != 2) {
108: throw new IllegalArgumentException();
109: }
110: }
111: }
112:
113: if (equal(u1, this .u1)) {
114: return;
115: }
116: modifyingNode();
117: this .u1 = u1;
118: modifiedNode();
119: }
120:
121: /**
122: * Sets this kerning entry's second match
123: *
124: * @param u2 the new matching unicode ranges.
125: *
126: * @throws IllegalArgumentException if the input array has an entry which
127: * is not of length 2.
128: */
129: public void setU2(final int[][] u2) {
130: if (u2 != null) {
131: for (int i = 0; i < u2.length; i++) {
132: if (u2[i] == null || u2[i].length != 2) {
133: throw new IllegalArgumentException();
134: }
135: }
136: }
137:
138: if (equal(u2, this .u2)) {
139: return;
140: }
141: modifyingNode();
142: this .u2 = u2;
143: modifiedNode();
144: }
145:
146: /**
147: * Sets this kerning entry first glyph names matches.
148: *
149: * @param g1 the list of matching names.
150: */
151: public void setG1(final String[] g1) {
152: if (equal(g1, this .g1)) {
153: return;
154: }
155: modifyingNode();
156: this .g1 = g1;
157: modifiedNode();
158: }
159:
160: /**
161: * Sets this kerning entry second glyph names matches.
162: *
163: * @param g2 the list of matching names.
164: */
165: public void setG2(final String[] g2) {
166: if (equal(g2, this .g2)) {
167: return;
168: }
169: modifyingNode();
170: this .g2 = g2;
171: modifiedNode();
172: }
173:
174: /**
175: * Sets this kernixng entry's advance.
176: *
177: * @param k the new kerning advance
178: */
179: public void setK(final float k) {
180: if (this .k == k) {
181: return;
182: }
183: modifyingNode();
184: this .k = k;
185: modifiedNode();
186: }
187:
188: /**
189: * @return this kerning entry's advance.
190: */
191: public float getK() {
192: return k;
193: }
194:
195: /**
196: * @return this node's matching unicode ranges for the first glyph
197: */
198: public int[][] getU1() {
199: return u1;
200: }
201:
202: /**
203: * @return this node's matching unicode ranges for the second glyph
204: */
205: public int[][] getU2() {
206: return u2;
207: }
208:
209: /**
210: * @return this node's matching glyphs names for the first glyph
211: */
212: public String[] getG1() {
213: return g1;
214: }
215:
216: /**
217: * @return this node's matching glyph names for the second glyph
218: */
219: public String[] getG2() {
220: return g2;
221: }
222:
223: /**
224: * Checks if the input glyph is a match for u1 or g1.
225: *
226: * @param g the glyph to match.
227: * @return true if the unicode range or glyph name of the input
228: * <code>Glyph</code> matches the kerning's u1 or g1
229: * setting.
230: */
231: public boolean matchesFirst(final Glyph g) {
232: return matches(g, u1, g1);
233: }
234:
235: /**
236: * Checks if the input glyph is a match for u2 or g2.
237: *
238: * @param g the glyph to match.
239: * @return true if the unicode range or glyph name of the input
240: * <code>Glyph</code> matches the kerning's u2 or g2
241: * setting.
242: */
243: public boolean matchesSecond(final Glyph g) {
244: return matches(g, u2, g2);
245: }
246:
247: /**
248: * Checks if the input glyph is a match for the input
249: * set of unicode ranges and/or glyph names.
250: *
251: * @param glyph the glyph to match.
252: * @param u the set of unicode ranges
253: * @param g the set of glyph names.
254: * @return true if there is a match.
255: */
256: boolean matches(final Glyph glyph, final int[][] u, final String[] g) {
257: String gu = glyph.getUnicode();
258: String[] gg = glyph.getGlyphName();
259:
260: if (u != null && gu != null && gu.length() == 1) {
261: char c = gu.charAt(0);
262: for (int i = 0; i < u.length; i++) {
263: if (c >= u[i][0] && c <= u[i][1]) {
264: return true;
265: }
266: }
267: }
268:
269: if (gg != null && g != null) {
270: for (int i = 0; i < gg.length; i++) {
271: String gn = gg[i];
272: for (int j = 0; j < g.length; j++) {
273: if (g[j].equals(gn)) {
274: return true;
275: }
276: }
277: }
278: }
279:
280: return false;
281: }
282:
283: /**
284: * HKern handles the u1, u2, g1, g2 and k traits.
285: *
286: * @param traitName the name of the trait which the element may support.
287: * @return true if this element supports the given trait in one of the
288: * trait accessor methods.
289: */
290: boolean supportsTrait(final String traitName) {
291: if (SVGConstants.SVG_U1_ATTRIBUTE == traitName
292: || SVGConstants.SVG_U2_ATTRIBUTE == traitName
293: || SVGConstants.SVG_G1_ATTRIBUTE == traitName
294: || SVGConstants.SVG_G2_ATTRIBUTE == traitName
295: || SVGConstants.SVG_K_ATTRIBUTE == traitName) {
296: return true;
297: }
298:
299: return super .supportsTrait(traitName);
300: }
301:
302: /**
303: * @return an array of traits that are required by this element.
304: */
305: public String[] getRequiredTraits() {
306: return REQUIRED_TRAITS;
307: }
308:
309: /**
310: * HKern handles the u1, u2, g1, g2 and k traits.
311: *
312: * @param name the requested trait name (e.g., "horiz-adv-x")
313: * @return the trait's value, as a string.
314: *
315: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
316: * trait is not supported on this element or null.
317: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
318: * trait's computed value cannot be converted to a String (SVG Tiny only).
319: */
320: public String getTraitImpl(final String name) throws DOMException {
321: if (SVGConstants.SVG_U1_ATTRIBUTE == name) {
322: return unicodeRangeToStringTrait(u1);
323: } else if (SVGConstants.SVG_U2_ATTRIBUTE == name) {
324: return unicodeRangeToStringTrait(u2);
325: } else if (SVGConstants.SVG_G1_ATTRIBUTE == name) {
326: return toStringTrait(g1);
327: } else if (SVGConstants.SVG_G2_ATTRIBUTE == name) {
328: return toStringTrait(g2);
329: } else if (SVGConstants.SVG_K_ATTRIBUTE == name) {
330: return Float.toString(k);
331: } else {
332: return super .getTraitImpl(name);
333: }
334: }
335:
336: /**
337: * HKern handles the u1, u2, g1, g2 and k traits.
338: *
339: * @param name the trait's name (e.g., "units-per-em")
340: * @param value the new trait string value (e.g., "1000")
341: *
342: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
343: * trait is not supported on this element or null.
344: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
345: * trait's value cannot be specified as a String
346: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
347: * value is an invalid value for the given trait or null.
348: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
349: * attempt is made to change readonly trait.
350: */
351: public void setTraitImpl(final String name, final String value)
352: throws DOMException {
353: if (SVGConstants.SVG_U1_ATTRIBUTE == name) {
354: checkWriteLoading(name);
355: setU1(parseUnicodeRangeTrait(name, value));
356: } else if (SVGConstants.SVG_U2_ATTRIBUTE == name) {
357: checkWriteLoading(name);
358: setU2(parseUnicodeRangeTrait(name, value));
359: } else if (SVGConstants.SVG_G1_ATTRIBUTE == name) {
360: checkWriteLoading(name);
361: setG1(parseStringArrayTrait(name, value,
362: SVGConstants.COMMA_STR));
363: } else if (SVGConstants.SVG_G2_ATTRIBUTE == name) {
364: checkWriteLoading(name);
365: setG2(parseStringArrayTrait(name, value,
366: SVGConstants.COMMA_STR));
367: } else if (SVGConstants.SVG_K_ATTRIBUTE == name) {
368: checkWriteLoading(name);
369: setK(parseFloatTrait(name, value));
370: } else {
371: super.setTraitImpl(name, value);
372: }
373: }
374:
375: }
|