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:
020: package org.apache.batik.css.engine.value.css2;
021:
022: import java.util.HashSet;
023: import java.util.Set;
024:
025: import org.apache.batik.css.engine.CSSEngine;
026: import org.apache.batik.css.engine.value.ValueManager;
027: import org.apache.batik.css.engine.value.IdentifierManager;
028: import org.apache.batik.css.engine.value.AbstractValueFactory;
029: import org.apache.batik.css.engine.value.ShorthandManager;
030: import org.apache.batik.css.engine.value.StringMap;
031: import org.apache.batik.css.parser.CSSLexicalUnit;
032: import org.apache.batik.util.CSSConstants;
033: import org.w3c.css.sac.LexicalUnit;
034:
035: /**
036: * This class provides support for the CSS2 'font' shorthand property.
037: *
038: * The form of this property is:
039: * [ [ <font-style> || <font-variant> || <font-weight> ]?
040: * <font-size> [ / <line-height> ]? <font-family> ] |
041: * caption | icon | menu | message-box | small-caption |
042: * status-bar | inherit
043: *
044: * It is worth noting that there is a potential ambiguity
045: * between font-size and font-weight since in SVG they can both
046: * be unitless. This is solved by considering the 'last' number
047: * before an 'ident' or '/' to be font-size and any preceeding
048: * number to be font-weight.
049: *
050: * @author <a href="mailto:deweese@apache.org">deweese</a>
051: * @version $Id: FontShorthandManager.java 478160 2006-11-22 13:35:06Z dvholten $
052: */
053: public class FontShorthandManager extends AbstractValueFactory
054: implements ShorthandManager {
055:
056: public FontShorthandManager() {
057: }
058:
059: /**
060: * Implements {@link ValueManager#getPropertyName()}.
061: */
062: public String getPropertyName() {
063: return CSSConstants.CSS_FONT_PROPERTY;
064: }
065:
066: /**
067: * Implements {@link ShorthandManager#isAnimatableProperty()}.
068: */
069: public boolean isAnimatableProperty() {
070: return true;
071: }
072:
073: /**
074: * Implements {@link ValueManager#isAdditiveProperty()}.
075: */
076: public boolean isAdditiveProperty() {
077: return false;
078: }
079:
080: static LexicalUnit NORMAL_LU = CSSLexicalUnit.createString(
081: LexicalUnit.SAC_IDENT, CSSConstants.CSS_NORMAL_VALUE, null);
082: static LexicalUnit BOLD_LU = CSSLexicalUnit.createString(
083: LexicalUnit.SAC_IDENT, CSSConstants.CSS_BOLD_VALUE, null);
084:
085: static LexicalUnit MEDIUM_LU = CSSLexicalUnit.createString(
086: LexicalUnit.SAC_IDENT, CSSConstants.CSS_MEDIUM_VALUE, null);
087:
088: static LexicalUnit SZ_10PT_LU = CSSLexicalUnit.createFloat(
089: LexicalUnit.SAC_POINT, 10, null);
090: static LexicalUnit SZ_8PT_LU = CSSLexicalUnit.createFloat(
091: LexicalUnit.SAC_POINT, 8, null);
092:
093: static LexicalUnit FONT_FAMILY_LU;
094: static {
095: LexicalUnit lu;
096: FONT_FAMILY_LU = CSSLexicalUnit.createString(
097: LexicalUnit.SAC_IDENT, "Dialog", null);
098: lu = CSSLexicalUnit.createString(LexicalUnit.SAC_IDENT,
099: "Helvetica", FONT_FAMILY_LU);
100: CSSLexicalUnit.createString(LexicalUnit.SAC_IDENT,
101: CSSConstants.CSS_SANS_SERIF_VALUE, lu);
102: }
103:
104: protected static final Set values = new HashSet();
105: static {
106: values.add(CSSConstants.CSS_CAPTION_VALUE);
107: values.add(CSSConstants.CSS_ICON_VALUE);
108: values.add(CSSConstants.CSS_MENU_VALUE);
109: values.add(CSSConstants.CSS_MESSAGE_BOX_VALUE);
110: values.add(CSSConstants.CSS_SMALL_CAPTION_VALUE);
111: values.add(CSSConstants.CSS_STATUS_BAR_VALUE);
112: }
113:
114: public void handleSystemFont(CSSEngine eng,
115: ShorthandManager.PropertyHandler ph, String s, boolean imp) {
116:
117: LexicalUnit fontStyle = NORMAL_LU;
118: LexicalUnit fontVariant = NORMAL_LU;
119: LexicalUnit fontWeight = NORMAL_LU;
120: LexicalUnit lineHeight = NORMAL_LU;
121: LexicalUnit fontFamily = FONT_FAMILY_LU;
122:
123: LexicalUnit fontSize;
124: if (s.equals(CSSConstants.CSS_SMALL_CAPTION_VALUE)) {
125: fontSize = SZ_8PT_LU;
126: } else {
127: fontSize = SZ_10PT_LU;
128: }
129: ph.property(CSSConstants.CSS_FONT_FAMILY_PROPERTY, fontFamily,
130: imp);
131: ph.property(CSSConstants.CSS_FONT_STYLE_PROPERTY, fontStyle,
132: imp);
133: ph.property(CSSConstants.CSS_FONT_VARIANT_PROPERTY,
134: fontVariant, imp);
135: ph.property(CSSConstants.CSS_FONT_WEIGHT_PROPERTY, fontWeight,
136: imp);
137: ph.property(CSSConstants.CSS_FONT_SIZE_PROPERTY, fontSize, imp);
138: ph.property(CSSConstants.CSS_LINE_HEIGHT_PROPERTY, lineHeight,
139: imp);
140: }
141:
142: /**
143: * Implements {@link ShorthandManager#setValues(CSSEngine,ShorthandManager.PropertyHandler,LexicalUnit,boolean)}.
144: */
145: public void setValues(CSSEngine eng,
146: ShorthandManager.PropertyHandler ph, LexicalUnit lu,
147: boolean imp) {
148: switch (lu.getLexicalUnitType()) {
149: case LexicalUnit.SAC_INHERIT:
150: return;
151: case LexicalUnit.SAC_IDENT: {
152: String s = lu.getStringValue().toLowerCase();
153: if (values.contains(s)) {
154: handleSystemFont(eng, ph, s, imp);
155: return;
156: }
157: }
158: }
159:
160: LexicalUnit fontStyle = null;
161: LexicalUnit fontVariant = null;
162: LexicalUnit fontWeight = null;
163: LexicalUnit fontSize = null;
164: LexicalUnit lineHeight = null;
165: LexicalUnit fontFamily = null;
166:
167: ValueManager[] vMgrs = eng.getValueManagers();
168: int fst, fv, fw, fsz, lh;
169: fst = eng
170: .getPropertyIndex(CSSConstants.CSS_FONT_STYLE_PROPERTY);
171: fv = eng
172: .getPropertyIndex(CSSConstants.CSS_FONT_VARIANT_PROPERTY);
173: fw = eng
174: .getPropertyIndex(CSSConstants.CSS_FONT_WEIGHT_PROPERTY);
175: fsz = eng.getPropertyIndex(CSSConstants.CSS_FONT_SIZE_PROPERTY);
176: lh = eng
177: .getPropertyIndex(CSSConstants.CSS_LINE_HEIGHT_PROPERTY);
178:
179: IdentifierManager fstVM = (IdentifierManager) vMgrs[fst];
180: IdentifierManager fvVM = (IdentifierManager) vMgrs[fv];
181: IdentifierManager fwVM = (IdentifierManager) vMgrs[fw];
182: FontSizeManager fszVM = (FontSizeManager) vMgrs[fsz];
183:
184: StringMap fstSM = fstVM.getIdentifiers();
185: StringMap fvSM = fvVM.getIdentifiers();
186: StringMap fwSM = fwVM.getIdentifiers();
187: StringMap fszSM = fszVM.getIdentifiers();
188:
189: // Check for font-style, font-variant, & font-weight
190: // These are all optional.
191:
192: boolean svwDone = false;
193: LexicalUnit intLU = null;
194: while (!svwDone && (lu != null)) {
195: switch (lu.getLexicalUnitType()) {
196: case LexicalUnit.SAC_IDENT: {
197: String s = lu.getStringValue().toLowerCase().intern();
198: if (fontStyle == null && fstSM.get(s) != null) {
199: fontStyle = lu;
200: if (intLU != null) {
201: if (fontWeight == null) {
202: fontWeight = intLU;
203: intLU = null;
204: } else {
205: throw createInvalidLexicalUnitDOMException(intLU
206: .getLexicalUnitType());
207: }
208: }
209: break;
210: }
211:
212: if (fontVariant == null && fvSM.get(s) != null) {
213: fontVariant = lu;
214: if (intLU != null) {
215: if (fontWeight == null) {
216: fontWeight = intLU;
217: intLU = null;
218: } else {
219: throw createInvalidLexicalUnitDOMException(intLU
220: .getLexicalUnitType());
221: }
222: }
223: break;
224: }
225:
226: if (intLU == null && fontWeight == null
227: && fwSM.get(s) != null) {
228: fontWeight = lu;
229: break;
230: }
231:
232: svwDone = true;
233: break;
234: }
235: case LexicalUnit.SAC_INTEGER:
236: if (intLU == null && fontWeight == null) {
237: intLU = lu;
238: break;
239: }
240: svwDone = true;
241: break;
242:
243: default: // All other must be size,'/line-height', family
244: svwDone = true;
245: break;
246: }
247: if (!svwDone)
248: lu = lu.getNextLexicalUnit();
249: }
250:
251: // Must have font-size.
252: if (lu == null)
253: throw createMalformedLexicalUnitDOMException();
254:
255: // Now we need to get font-size
256: switch (lu.getLexicalUnitType()) {
257: case LexicalUnit.SAC_IDENT: {
258: String s = lu.getStringValue().toLowerCase().intern();
259: if (fszSM.get(s) != null) {
260: fontSize = lu; // This is a font-size ident.
261: lu = lu.getNextLexicalUnit();
262: }
263: }
264: break;
265:
266: case LexicalUnit.SAC_EM:
267: case LexicalUnit.SAC_EX:
268: case LexicalUnit.SAC_PIXEL:
269: case LexicalUnit.SAC_CENTIMETER:
270: case LexicalUnit.SAC_MILLIMETER:
271: case LexicalUnit.SAC_INCH:
272: case LexicalUnit.SAC_POINT:
273: case LexicalUnit.SAC_PICA:
274: case LexicalUnit.SAC_INTEGER:
275: case LexicalUnit.SAC_REAL:
276: case LexicalUnit.SAC_PERCENTAGE:
277: fontSize = lu;
278: lu = lu.getNextLexicalUnit();
279: break;
280: }
281:
282: if (fontSize == null) {
283: // We must have a font-size so see if we can use intLU...
284: if (intLU != null) {
285: fontSize = intLU; // Yup!
286: intLU = null;
287: } else {
288: throw createInvalidLexicalUnitDOMException(lu
289: .getLexicalUnitType());
290: }
291: }
292:
293: if (intLU != null) {
294: // We have a intLU left see if we can use it as font-weight
295: if (fontWeight == null) {
296: fontWeight = intLU; // use intLU as font-weight.
297: } else {
298: // we have an 'extra' integer in property.
299: throw createInvalidLexicalUnitDOMException(intLU
300: .getLexicalUnitType());
301: }
302: }
303:
304: // Must have Font-Family, so if it's null now we are done!
305: if (lu == null)
306: throw createMalformedLexicalUnitDOMException();
307:
308: // Now at this point we want to look for
309: // line-height.
310: switch (lu.getLexicalUnitType()) {
311: case LexicalUnit.SAC_OPERATOR_SLASH: // we have line-height
312: lu = lu.getNextLexicalUnit();
313: if (lu == null) // OOPS!
314: throw createMalformedLexicalUnitDOMException();
315: lineHeight = lu;
316: lu = lu.getNextLexicalUnit();
317: break;
318: }
319:
320: // Must have Font-Family, so if it's null now we are done!
321: if (lu == null)
322: throw createMalformedLexicalUnitDOMException();
323: fontFamily = lu;
324:
325: if (fontStyle == null)
326: fontStyle = NORMAL_LU;
327: if (fontVariant == null)
328: fontVariant = NORMAL_LU;
329: if (fontWeight == null)
330: fontWeight = NORMAL_LU;
331: if (lineHeight == null)
332: lineHeight = NORMAL_LU;
333:
334: ph.property(CSSConstants.CSS_FONT_FAMILY_PROPERTY, fontFamily,
335: imp);
336: ph.property(CSSConstants.CSS_FONT_STYLE_PROPERTY, fontStyle,
337: imp);
338: ph.property(CSSConstants.CSS_FONT_VARIANT_PROPERTY,
339: fontVariant, imp);
340: ph.property(CSSConstants.CSS_FONT_WEIGHT_PROPERTY, fontWeight,
341: imp);
342: ph.property(CSSConstants.CSS_FONT_SIZE_PROPERTY, fontSize, imp);
343: if (lh != -1) {
344: ph.property(CSSConstants.CSS_LINE_HEIGHT_PROPERTY,
345: lineHeight, imp);
346: }
347: }
348: }
|