1 18 package org.apache.batik.svggen; 19 20 import java.awt.Font ; 21 import java.awt.Shape ; 22 import java.awt.font.FontRenderContext ; 23 import java.awt.font.GlyphMetrics ; 24 import java.awt.font.GlyphVector ; 25 import java.awt.font.LineMetrics ; 26 import java.awt.font.TextAttribute ; 27 import java.awt.geom.AffineTransform ; 28 import java.util.HashMap ; 29 import java.util.Map ; 30 31 import org.apache.batik.ext.awt.g2d.GraphicContext; 32 import org.w3c.dom.Document ; 33 import org.w3c.dom.Element ; 34 import org.w3c.dom.NodeList ; 35 36 44 public class SVGFont extends AbstractSVGConverter { 45 public static final float EXTRA_LIGHT = 46 TextAttribute.WEIGHT_EXTRA_LIGHT.floatValue(); 47 public static final float LIGHT = 48 TextAttribute.WEIGHT_LIGHT.floatValue(); 49 public static final float DEMILIGHT = 50 TextAttribute.WEIGHT_DEMILIGHT.floatValue(); 51 public static final float REGULAR = 52 TextAttribute.WEIGHT_REGULAR.floatValue(); 53 public static final float SEMIBOLD = 54 TextAttribute.WEIGHT_SEMIBOLD.floatValue(); 55 public static final float MEDIUM = 56 TextAttribute.WEIGHT_MEDIUM.floatValue(); 57 public static final float DEMIBOLD = 58 TextAttribute.WEIGHT_DEMIBOLD.floatValue(); 59 public static final float BOLD = 60 TextAttribute.WEIGHT_BOLD.floatValue(); 61 public static final float HEAVY = 62 TextAttribute.WEIGHT_HEAVY.floatValue(); 63 public static final float EXTRABOLD = 64 TextAttribute.WEIGHT_EXTRABOLD.floatValue(); 65 public static final float ULTRABOLD = 66 TextAttribute.WEIGHT_ULTRABOLD.floatValue(); 67 68 public static final float POSTURE_REGULAR = 69 TextAttribute.POSTURE_REGULAR.floatValue(); 70 public static final float POSTURE_OBLIQUE = 71 TextAttribute.POSTURE_OBLIQUE.floatValue(); 72 73 79 static final float fontStyles[] = { 80 POSTURE_REGULAR + (POSTURE_OBLIQUE - POSTURE_REGULAR)/2 81 }; 82 83 86 static final String svgStyles[] = { 87 SVG_NORMAL_VALUE, 88 SVG_ITALIC_VALUE 89 }; 90 91 97 static final float fontWeights[] = { EXTRA_LIGHT + (LIGHT - EXTRA_LIGHT)/2f, 98 LIGHT + (DEMILIGHT - LIGHT)/2f, 99 DEMILIGHT + (REGULAR - DEMILIGHT)/2f, 100 REGULAR + (SEMIBOLD - REGULAR)/2f, 101 SEMIBOLD + (MEDIUM - SEMIBOLD)/2f, 102 MEDIUM + (DEMIBOLD - MEDIUM)/2f, 103 DEMIBOLD + (BOLD - DEMIBOLD)/2f, 104 BOLD + (HEAVY - BOLD)/2f, 105 HEAVY + (EXTRABOLD - HEAVY)/2f, 106 EXTRABOLD + (ULTRABOLD - EXTRABOLD), 107 }; 108 109 112 static final String svgWeights[] = { 113 SVG_100_VALUE, 114 SVG_200_VALUE, 115 SVG_300_VALUE, 116 SVG_NORMAL_VALUE, 117 SVG_500_VALUE, 118 SVG_500_VALUE, 119 SVG_600_VALUE, 120 SVG_BOLD_VALUE, 121 SVG_800_VALUE, 122 SVG_800_VALUE, 123 SVG_900_VALUE 124 }; 125 126 129 static Map logicalFontMap = new HashMap (); 130 131 static { 132 logicalFontMap.put("dialog", "sans-serif"); 133 logicalFontMap.put("dialoginput", "monospace"); 134 logicalFontMap.put("monospaced", "monospace"); 135 logicalFontMap.put("serif", "serif"); 136 logicalFontMap.put("sansserif", "sans-serif"); 137 logicalFontMap.put("symbol", "'WingDings'"); 138 } 139 140 143 static final int COMMON_FONT_SIZE = 100; 144 145 149 Map fontStringMap = new HashMap (); 150 151 154 public SVGFont(SVGGeneratorContext generatorContext) { 155 super(generatorContext); 156 } 157 158 163 public void recordFontUsage(String string, Font font) { 164 165 Font commonSizeFont = createCommonSizeFont(font); 166 String fontKey = commonSizeFont.getFamily() + commonSizeFont.getStyle(); 167 String textUsingFont = (String )fontStringMap.get(fontKey); 168 if (textUsingFont == null) { 169 textUsingFont = ""; 171 } 172 char ch; 174 for (int i = 0; i < string.length(); i++) { 175 ch = string.charAt(i); 176 if (textUsingFont.indexOf(ch) == -1) { 177 textUsingFont += ch; 178 } 179 } 180 fontStringMap.put(fontKey, textUsingFont); 181 } 182 183 188 private static Font createCommonSizeFont(Font font) { 189 HashMap attributes = new HashMap (font.getAttributes()); 190 attributes.put(TextAttribute.SIZE, new Float (COMMON_FONT_SIZE)); 191 return new Font (attributes); 192 } 193 194 204 public SVGDescriptor toSVG(GraphicContext gc) { 205 return toSVG(gc.getFont(), gc.getFontRenderContext()); 206 } 207 208 215 public SVGFontDescriptor toSVG(Font font, FontRenderContext frc) { 216 217 String fontSize = "" + doubleString(font.getSize2D()); 218 String fontWeight = weightToSVG(font); 219 String fontStyle = styleToSVG(font); 220 String fontFamilyStr = familyToSVG(font); 221 222 Font commonSizeFont = createCommonSizeFont(font); 223 String fontKey = commonSizeFont.getFamily() + commonSizeFont.getStyle(); 224 225 String textUsingFont = (String )fontStringMap.get(fontKey); 226 227 if (textUsingFont == null) { 228 return new SVGFontDescriptor(fontSize, fontWeight, 231 fontStyle, fontFamilyStr, 232 null); 233 } 234 235 Document domFactory = generatorContext.domFactory; 236 237 SVGFontDescriptor fontDesc = 239 (SVGFontDescriptor)descMap.get(fontKey); 240 241 Element fontDef; 242 243 if (fontDesc != null) { 244 245 fontDef = fontDesc.getDef(); 247 248 } else { 249 250 fontDef = domFactory.createElementNS(SVG_NAMESPACE_URI, 252 SVG_FONT_TAG); 253 254 Element fontFace = domFactory.createElementNS(SVG_NAMESPACE_URI, 258 SVG_FONT_FACE_TAG); 259 String svgFontFamilyString = fontFamilyStr; 260 if (fontFamilyStr.startsWith("'") && fontFamilyStr.endsWith("'")) { 261 svgFontFamilyString 263 = fontFamilyStr.substring(1, fontFamilyStr.length()-1); 264 } 265 fontFace.setAttributeNS(null, SVG_FONT_FAMILY_ATTRIBUTE, 266 svgFontFamilyString); 267 fontFace.setAttributeNS(null, SVG_FONT_WEIGHT_ATTRIBUTE, 268 fontWeight); 269 fontFace.setAttributeNS(null, SVG_FONT_STYLE_ATTRIBUTE, 270 fontStyle); 271 fontFace.setAttributeNS(null, SVG_UNITS_PER_EM_ATTRIBUTE, 272 ""+COMMON_FONT_SIZE); 273 fontDef.appendChild(fontFace); 274 275 Element missingGlyphElement 279 = domFactory.createElementNS(SVG_NAMESPACE_URI, 280 SVG_MISSING_GLYPH_TAG); 281 282 int missingGlyphCode[] = new int[1]; 283 missingGlyphCode[0] = commonSizeFont.getMissingGlyphCode(); 284 GlyphVector gv = commonSizeFont.createGlyphVector(frc, missingGlyphCode); 285 Shape missingGlyphShape = gv.getGlyphOutline(0); 286 GlyphMetrics gm = gv.getGlyphMetrics(0); 287 288 AffineTransform at = AffineTransform.getScaleInstance(1, -1); 291 missingGlyphShape = at.createTransformedShape(missingGlyphShape); 292 293 missingGlyphElement.setAttributeNS(null, SVG_D_ATTRIBUTE, 294 SVGPath.toSVGPathData(missingGlyphShape, generatorContext)); 295 missingGlyphElement.setAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE, 296 "" + gm.getAdvance()); 297 fontDef.appendChild(missingGlyphElement); 298 299 fontDef.setAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE, "" + gm.getAdvance()); 302 303 LineMetrics lm = commonSizeFont.getLineMetrics("By", frc); 305 fontFace.setAttributeNS(null, SVG_ASCENT_ATTRIBUTE, "" + lm.getAscent()); 306 fontFace.setAttributeNS(null, SVG_DESCENT_ATTRIBUTE, "" + lm.getDescent()); 307 308 fontDef.setAttributeNS(null, ATTR_ID, 312 generatorContext.idGenerator. 313 generateID(ID_PREFIX_FONT)); 314 } 315 316 320 for (int i = textUsingFont.length()-1; i >= 0; i--) { 323 char c = textUsingFont.charAt(i); 324 boolean foundGlyph = false; 325 NodeList fontChildren = fontDef.getChildNodes(); 326 for (int j = 0; j < fontChildren.getLength(); j++) { 327 if (fontChildren.item(j) instanceof Element ) { 328 Element childElement = (Element )fontChildren.item(j); 329 if (childElement.getAttributeNS(null, 330 SVG_UNICODE_ATTRIBUTE).equals(""+c)) { 331 foundGlyph = true; 332 break; 333 } 334 } 335 } 336 if (!foundGlyph) { 337 Element glyphElement 339 = domFactory.createElementNS(SVG_NAMESPACE_URI, 340 SVG_GLYPH_TAG); 341 342 GlyphVector gv = commonSizeFont.createGlyphVector(frc, ""+c); 343 Shape glyphShape = gv.getGlyphOutline(0); 344 GlyphMetrics gm = gv.getGlyphMetrics(0); 345 346 AffineTransform at = AffineTransform.getScaleInstance(1, -1); 349 glyphShape = at.createTransformedShape(glyphShape); 350 351 glyphElement.setAttributeNS(null, SVG_D_ATTRIBUTE, 352 SVGPath.toSVGPathData(glyphShape, generatorContext)); 353 glyphElement.setAttributeNS(null, SVG_HORIZ_ADV_X_ATTRIBUTE, 354 "" + gm.getAdvance()); 355 glyphElement.setAttributeNS(null, SVG_UNICODE_ATTRIBUTE, 356 "" + c); 357 358 fontDef.appendChild(glyphElement); 359 } else { 360 break; 363 } 364 } 365 366 SVGFontDescriptor newFontDesc 370 = new SVGFontDescriptor(fontSize, fontWeight, 371 fontStyle, fontFamilyStr, 372 fontDef); 373 374 if (fontDesc == null) { 378 descMap.put(fontKey, newFontDesc); 379 defSet.add(fontDef); 380 } 381 382 return newFontDesc; 383 } 384 385 389 public static String familyToSVG(Font font) { 390 String fontFamilyStr = font.getFamily(); 391 String logicalFontFamily = 392 (String )logicalFontMap.get(font.getName().toLowerCase()); 393 if (logicalFontFamily != null) 394 fontFamilyStr = logicalFontFamily; 395 else { 396 StringBuffer fontFamily = new StringBuffer ("'"); 397 fontFamily.append(fontFamilyStr); 398 fontFamily.append("'"); 399 fontFamilyStr = fontFamily.toString(); 400 } 401 return fontFamilyStr; 402 } 403 404 408 public static String styleToSVG(Font font) { 409 Map attrMap = font.getAttributes(); 410 Float styleValue = (Float )attrMap.get(TextAttribute.POSTURE); 411 412 if (styleValue == null) { 413 if (font.isItalic()) 414 styleValue = TextAttribute.POSTURE_OBLIQUE; 415 else 416 styleValue = TextAttribute.POSTURE_REGULAR; 417 } 418 419 float style = styleValue.floatValue(); 420 421 int i = 0; 422 for (i=0; i< fontStyles.length; i++) { 423 if (style <= fontStyles[i]) 424 break; 425 } 426 427 return svgStyles[i]; 428 } 429 430 435 public static String weightToSVG(Font font) { 436 Map attrMap = font.getAttributes(); 437 Float weightValue = (Float )attrMap.get(TextAttribute.WEIGHT); 438 if (weightValue==null) { 439 if (font.isBold()) 440 weightValue = TextAttribute.WEIGHT_BOLD; 441 else 442 weightValue = TextAttribute.WEIGHT_REGULAR; 443 } 444 445 float weight = weightValue.floatValue(); 446 447 int i = 0; 448 for (i=0; i<fontWeights.length; i++) { 449 if (weight<=fontWeights[i]) 450 break; 451 } 452 453 return svgWeights[i]; 454 } 455 } 456 | Popular Tags |