You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ACIUtils.java 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. 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. /* $Id$ */
  18. package org.apache.fop.svg;
  19. import java.awt.font.TextAttribute;
  20. import java.text.AttributedCharacterIterator;
  21. import java.text.AttributedCharacterIterator.Attribute;
  22. import java.text.CharacterIterator;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.Map.Entry;
  26. import java.util.Set;
  27. import org.apache.commons.logging.Log;
  28. import org.apache.commons.logging.LogFactory;
  29. import org.apache.batik.bridge.SVGFontFamily;
  30. import org.apache.batik.gvt.font.GVTFont;
  31. import org.apache.batik.gvt.font.GVTFontFamily;
  32. import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
  33. import org.apache.fop.fonts.Font;
  34. import org.apache.fop.fonts.FontInfo;
  35. import org.apache.fop.fonts.FontTriplet;
  36. /**
  37. * Utilities for java.text.AttributedCharacterIterator.
  38. */
  39. public final class ACIUtils {
  40. /** the logger for this class */
  41. private static final Log LOG = LogFactory.getLog(ACIUtils.class);
  42. private ACIUtils() {
  43. //This class shouldn't be instantiated.
  44. }
  45. /**
  46. * Tries to find matching fonts in FOP's {@link FontInfo} instance for fonts used by
  47. * Apache Batik. The method inspects the various GVT attributes found in the ACI.
  48. * @param aci the ACI to find matching fonts for
  49. * @param fontInfo the font info instance with FOP's fonts
  50. * @return an array of matching fonts
  51. */
  52. public static Font[] findFontsForBatikACI(AttributedCharacterIterator aci, FontInfo fontInfo) {
  53. List<Font> fonts = new java.util.ArrayList<Font>();
  54. @SuppressWarnings("unchecked")
  55. List<GVTFontFamily> gvtFonts = (List<GVTFontFamily>) aci.getAttribute(
  56. GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
  57. Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
  58. Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
  59. Float fontSize = (Float) aci.getAttribute(TextAttribute.SIZE);
  60. String style = toStyle(posture);
  61. int weight = toCSSWeight(taWeight);
  62. int fsize = (int)(fontSize.floatValue() * 1000);
  63. String firstFontFamily = null;
  64. //GVT_FONT can sometimes be different from the fonts in GVT_FONT_FAMILIES
  65. //or GVT_FONT_FAMILIES can even be empty and only GVT_FONT is set
  66. /* The following code section is not available until Batik 1.7 is released. */
  67. GVTFont gvtFont = (GVTFont)aci.getAttribute(
  68. GVTAttributedCharacterIterator.TextAttribute.GVT_FONT);
  69. if (gvtFont != null) {
  70. String gvtFontFamily = gvtFont.getFamilyName();
  71. if (fontInfo.hasFont(gvtFontFamily, style, weight)) {
  72. FontTriplet triplet = fontInfo.fontLookup(gvtFontFamily, style,
  73. weight);
  74. Font f = fontInfo.getFontInstance(triplet, fsize);
  75. if (LOG.isDebugEnabled()) {
  76. LOG.debug("Found a font that matches the GVT font: "
  77. + gvtFontFamily + ", " + weight + ", " + style
  78. + " -> " + f);
  79. }
  80. fonts.add(f);
  81. }
  82. firstFontFamily = gvtFontFamily;
  83. }
  84. if (gvtFonts != null) {
  85. boolean haveInstanceOfSVGFontFamily = false;
  86. for (GVTFontFamily fam : gvtFonts) {
  87. if (fam instanceof SVGFontFamily) {
  88. haveInstanceOfSVGFontFamily = true;
  89. }
  90. String fontFamily = fam.getFamilyName();
  91. if (fontInfo.hasFont(fontFamily, style, weight)) {
  92. FontTriplet triplet = fontInfo.fontLookup(fontFamily, style,
  93. weight);
  94. Font f = fontInfo.getFontInstance(triplet, fsize);
  95. if (LOG.isDebugEnabled()) {
  96. LOG.debug("Found a font that matches the GVT font family: "
  97. + fontFamily + ", " + weight + ", " + style
  98. + " -> " + f);
  99. }
  100. fonts.add(f);
  101. }
  102. if (firstFontFamily == null) {
  103. firstFontFamily = fontFamily;
  104. }
  105. }
  106. // SVG fonts are embedded fonts in the SVG document and are rarely used; however if they
  107. // are used but the fonts also exists in the system and are known to FOP then FOP should
  108. // use them; then the decision whether Batik should stroke the text should be made after
  109. // no matching fonts are found
  110. if (fonts.isEmpty() && haveInstanceOfSVGFontFamily) {
  111. fontInfo.notifyStrokingSVGTextAsShapes(firstFontFamily);
  112. return null; // Let Batik paint this text!
  113. }
  114. }
  115. if (fonts.isEmpty()) {
  116. if (firstFontFamily == null) {
  117. //This will probably never happen. Just to be on the safe side.
  118. firstFontFamily = "any";
  119. }
  120. //lookup with fallback possibility (incl. substitution notification)
  121. FontTriplet triplet = fontInfo.fontLookup(firstFontFamily, style, weight);
  122. Font f = fontInfo.getFontInstance(triplet, fsize);
  123. if (LOG.isDebugEnabled()) {
  124. LOG.debug("Falling back to adjustable font lookup up for: "
  125. + firstFontFamily + ", " + weight + ", " + style
  126. + " -> " + f);
  127. }
  128. fonts.add(f);
  129. }
  130. return fonts.toArray(new Font[fonts.size()]);
  131. }
  132. private static int toCSSWeight(Float weight) {
  133. if (weight == null) {
  134. return 400;
  135. } else if (weight <= TextAttribute.WEIGHT_EXTRA_LIGHT.floatValue()) {
  136. return 100;
  137. } else if (weight <= TextAttribute.WEIGHT_LIGHT.floatValue()) {
  138. return 200;
  139. } else if (weight <= TextAttribute.WEIGHT_DEMILIGHT.floatValue()) {
  140. return 300;
  141. } else if (weight <= TextAttribute.WEIGHT_REGULAR.floatValue()) {
  142. return 400;
  143. } else if (weight <= TextAttribute.WEIGHT_SEMIBOLD.floatValue()) {
  144. return 500;
  145. } else if (weight < TextAttribute.WEIGHT_BOLD.floatValue()) {
  146. return 600;
  147. } else if (weight == TextAttribute.WEIGHT_BOLD.floatValue()) {
  148. return 700;
  149. } else if (weight <= TextAttribute.WEIGHT_HEAVY.floatValue()) {
  150. return 800;
  151. } else if (weight <= TextAttribute.WEIGHT_EXTRABOLD.floatValue()) {
  152. return 900;
  153. } else {
  154. return 900;
  155. }
  156. }
  157. private static String toStyle(Float posture) {
  158. return ((posture != null) && (posture.floatValue() > 0.0))
  159. ? Font.STYLE_ITALIC
  160. : Font.STYLE_NORMAL;
  161. }
  162. /**
  163. * Dumps the contents of an ACI to System.out. Used for debugging only.
  164. * @param aci the ACI to dump
  165. */
  166. public static void dumpAttrs(AttributedCharacterIterator aci) {
  167. aci.first();
  168. Set<Entry<Attribute, Object>> entries = aci.getAttributes().entrySet();
  169. for (Map.Entry<Attribute, Object> entry : entries) {
  170. if (entry.getValue() != null) {
  171. System.out.println(entry.getKey() + ": " + entry.getValue());
  172. }
  173. }
  174. int start = aci.getBeginIndex();
  175. System.out.print("AttrRuns: ");
  176. while (aci.current() != CharacterIterator.DONE) {
  177. int end = aci.getRunLimit();
  178. System.out.print("" + (end - start) + ", ");
  179. aci.setIndex(end);
  180. if (start == end) {
  181. break;
  182. }
  183. start = end;
  184. }
  185. System.out.println("");
  186. }
  187. }