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 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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.svg.font.FOPGVTFont;
  36. import org.apache.fop.svg.font.FOPGVTFontFamily;
  37. /**
  38. * Utilities for java.text.AttributedCharacterIterator.
  39. */
  40. public final class ACIUtils {
  41. /** the logger for this class */
  42. private static final Log LOG = LogFactory.getLog(ACIUtils.class);
  43. private ACIUtils() {
  44. //This class shouldn't be instantiated.
  45. }
  46. /**
  47. * Tries to find matching fonts in FOP's {@link FontInfo} instance for fonts used by
  48. * Apache Batik. The method inspects the various GVT attributes found in the ACI.
  49. * @param aci the ACI to find matching fonts for
  50. * @param fontInfo the font info instance with FOP's fonts
  51. * @return an array of matching fonts
  52. */
  53. public static Font[] findFontsForBatikACI(AttributedCharacterIterator aci, FontInfo fontInfo) {
  54. List<Font> fonts = new java.util.ArrayList<Font>();
  55. @SuppressWarnings("unchecked")
  56. List<GVTFontFamily> gvtFonts = (List<GVTFontFamily>) aci.getAttribute(
  57. GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
  58. String style = toStyle((Float) aci.getAttribute(TextAttribute.POSTURE));
  59. int weight = toCSSWeight((Float) aci.getAttribute(TextAttribute.WEIGHT));
  60. float fontSize = ((Float) aci.getAttribute(TextAttribute.SIZE)).floatValue();
  61. String firstFontFamily = null;
  62. //GVT_FONT can sometimes be different from the fonts in GVT_FONT_FAMILIES
  63. //or GVT_FONT_FAMILIES can even be empty and only GVT_FONT is set
  64. GVTFont gvtFont = (GVTFont) aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT);
  65. if (gvtFont != null) {
  66. String gvtFontFamily = gvtFont.getFamilyName();
  67. if (gvtFont instanceof FOPGVTFont) {
  68. Font font = ((FOPGVTFont) gvtFont).getFont();
  69. if (LOG.isDebugEnabled()) {
  70. LOG.debug("Found a font that matches the GVT font: "
  71. + gvtFontFamily + ", " + weight + ", " + style
  72. + " -> " + font);
  73. }
  74. fonts.add(font);
  75. }
  76. firstFontFamily = gvtFontFamily;
  77. }
  78. if (gvtFonts != null) {
  79. boolean haveInstanceOfSVGFontFamily = false;
  80. for (GVTFontFamily fontFamily : gvtFonts) {
  81. if (fontFamily instanceof SVGFontFamily) {
  82. haveInstanceOfSVGFontFamily = true;
  83. } else if (fontFamily instanceof FOPGVTFontFamily) {
  84. Font font = ((FOPGVTFontFamily) fontFamily).deriveFont(fontSize, aci).getFont();
  85. if (LOG.isDebugEnabled()) {
  86. LOG.debug("Found a font that matches the GVT font family: "
  87. + fontFamily.getFamilyName() + ", " + weight + ", " + style + " -> " + font);
  88. }
  89. fonts.add(font);
  90. }
  91. if (firstFontFamily == null) {
  92. firstFontFamily = fontFamily.getFamilyName();
  93. }
  94. }
  95. // SVG fonts are embedded fonts in the SVG document and are rarely used; however if they
  96. // are used but the fonts also exists in the system and are known to FOP then FOP should
  97. // use them; then the decision whether Batik should stroke the text should be made after
  98. // no matching fonts are found
  99. if (fonts.isEmpty() && haveInstanceOfSVGFontFamily) {
  100. fontInfo.notifyStrokingSVGTextAsShapes(firstFontFamily);
  101. return null; // Let Batik paint this text!
  102. }
  103. }
  104. return fonts.isEmpty() ? null : fonts.toArray(new Font[fonts.size()]);
  105. }
  106. public static int toCSSWeight(Float weight) {
  107. if (weight == null) {
  108. return 400;
  109. } else if (weight <= TextAttribute.WEIGHT_EXTRA_LIGHT.floatValue()) {
  110. return 100;
  111. } else if (weight <= TextAttribute.WEIGHT_LIGHT.floatValue()) {
  112. return 200;
  113. } else if (weight <= TextAttribute.WEIGHT_DEMILIGHT.floatValue()) {
  114. return 300;
  115. } else if (weight <= TextAttribute.WEIGHT_REGULAR.floatValue()) {
  116. return 400;
  117. } else if (weight <= TextAttribute.WEIGHT_SEMIBOLD.floatValue()) {
  118. return 500;
  119. } else if (weight < TextAttribute.WEIGHT_BOLD.floatValue()) {
  120. return 600;
  121. } else if (weight == TextAttribute.WEIGHT_BOLD.floatValue()) {
  122. return 700;
  123. } else if (weight <= TextAttribute.WEIGHT_HEAVY.floatValue()) {
  124. return 800;
  125. } else if (weight <= TextAttribute.WEIGHT_EXTRABOLD.floatValue()) {
  126. return 900;
  127. } else {
  128. return 900;
  129. }
  130. }
  131. public static String toStyle(Float posture) {
  132. return ((posture != null) && (posture.floatValue() > 0.0))
  133. ? Font.STYLE_ITALIC
  134. : Font.STYLE_NORMAL;
  135. }
  136. /**
  137. * Dumps the contents of an ACI to System.out. Used for debugging only.
  138. * @param aci the ACI to dump
  139. */
  140. public static void dumpAttrs(AttributedCharacterIterator aci) {
  141. aci.first();
  142. Set<Entry<Attribute, Object>> entries = aci.getAttributes().entrySet();
  143. for (Map.Entry<Attribute, Object> entry : entries) {
  144. if (entry.getValue() != null) {
  145. System.out.println(entry.getKey() + ": " + entry.getValue());
  146. }
  147. }
  148. int start = aci.getBeginIndex();
  149. System.out.print("AttrRuns: ");
  150. while (aci.current() != CharacterIterator.DONE) {
  151. int end = aci.getRunLimit();
  152. System.out.print("" + (end - start) + ", ");
  153. aci.setIndex(end);
  154. if (start == end) {
  155. break;
  156. }
  157. start = end;
  158. }
  159. System.out.println("");
  160. }
  161. }