aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/svg/font
diff options
context:
space:
mode:
authorVincent Hennebert <vhennebert@apache.org>2013-07-29 21:45:20 +0000
committerVincent Hennebert <vhennebert@apache.org>2013-07-29 21:45:20 +0000
commitf8e822efe1de8bd8192dbb8ff035b9a79f876614 (patch)
tree8d38f873dd101e6ed0c2ba3b4dfa29e1eb0fdc60 /src/java/org/apache/fop/svg/font
parentc0b99ad44d0e1409008886e2f687c46f4ac05d9d (diff)
downloadxmlgraphics-fop-f8e822efe1de8bd8192dbb8ff035b9a79f876614.tar.gz
xmlgraphics-fop-f8e822efe1de8bd8192dbb8ff035b9a79f876614.zip
Directly use FOP fonts to lay out SVG images for PDF, PS and AFP outputs.
The metrics are now taken from FOP configured fonts and no longer from AWT equivalents. That avoids discrepancies in case AWT and FOP use slightly different fonts, or if the font is not installed on the system. That actually also avoids having to install the font on the system. FOP is also used for the primary layout of text (prior to SVG-specific transforms like translation or rotation) for consistency between SVG and XSL-FO. This is a joint work from Peter Hancock and myself. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_FopFontsForSVG@1508208 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/svg/font')
-rw-r--r--src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java70
-rw-r--r--src/java/org/apache/fop/svg/font/FOPFontFamilyResolver.java31
-rw-r--r--src/java/org/apache/fop/svg/font/FOPFontFamilyResolverImpl.java67
-rw-r--r--src/java/org/apache/fop/svg/font/FOPGVTFont.java159
-rw-r--r--src/java/org/apache/fop/svg/font/FOPGVTFontFamily.java73
-rw-r--r--src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java339
-rw-r--r--src/java/org/apache/fop/svg/font/FilteringFontFamilyResolver.java47
7 files changed, 786 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java b/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java
new file mode 100644
index 000000000..313a6a74b
--- /dev/null
+++ b/src/java/org/apache/fop/svg/font/AggregatingFontFamilyResolver.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.svg.font;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.batik.gvt.font.FontFamilyResolver;
+import org.apache.batik.gvt.font.GVTFontFamily;
+
+public class AggregatingFontFamilyResolver implements FontFamilyResolver {
+
+ private final List<FontFamilyResolver> resolvers;
+
+ public AggregatingFontFamilyResolver(FontFamilyResolver... resolvers) {
+ this.resolvers = Arrays.<FontFamilyResolver>asList(resolvers);
+ }
+
+ public String lookup(String familyName) {
+ for (FontFamilyResolver resolver : resolvers) {
+ String lookup = resolver.lookup(familyName);
+ if (lookup != null) {
+ return lookup;
+ }
+ }
+ return null;
+ }
+
+ public GVTFontFamily resolve(String familyName) {
+ for (FontFamilyResolver resolver : resolvers) {
+ GVTFontFamily family = resolver.resolve(familyName);
+ if (family != null) {
+ return family;
+ }
+ }
+ return null;
+ }
+
+ public GVTFontFamily getDefault() {
+ return resolve("any");
+ }
+
+ public GVTFontFamily getFamilyThatCanDisplay(char c) {
+ for (FontFamilyResolver resolver : resolvers) {
+ GVTFontFamily family = resolver.getFamilyThatCanDisplay(c);
+ if (family != null) {
+ return family;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/font/FOPFontFamilyResolver.java b/src/java/org/apache/fop/svg/font/FOPFontFamilyResolver.java
new file mode 100644
index 000000000..7af5f0b4f
--- /dev/null
+++ b/src/java/org/apache/fop/svg/font/FOPFontFamilyResolver.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.svg.font;
+
+import org.apache.batik.gvt.font.FontFamilyResolver;
+
+public interface FOPFontFamilyResolver extends FontFamilyResolver {
+
+ FOPGVTFontFamily resolve(String familyName);
+
+ FOPGVTFontFamily getDefault();
+
+ FOPGVTFontFamily getFamilyThatCanDisplay(char c);
+}
diff --git a/src/java/org/apache/fop/svg/font/FOPFontFamilyResolverImpl.java b/src/java/org/apache/fop/svg/font/FOPFontFamilyResolverImpl.java
new file mode 100644
index 000000000..a9a631691
--- /dev/null
+++ b/src/java/org/apache/fop/svg/font/FOPFontFamilyResolverImpl.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.svg.font;
+
+import java.util.Map;
+
+import org.apache.fop.fonts.Font;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.fonts.Typeface;
+
+public class FOPFontFamilyResolverImpl implements FOPFontFamilyResolver {
+
+ private final FontInfo fontInfo;
+
+ public FOPFontFamilyResolverImpl(FontInfo fontInfo) {
+ this.fontInfo = fontInfo;
+ }
+
+ public String lookup(String familyName) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ public FOPGVTFontFamily resolve(String familyName) {
+ FOPGVTFontFamily gvtFontFamily = null;
+ FontTriplet triplet = fontInfo.fontLookup(familyName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL);
+ if (fontInfo.hasFont(familyName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)) {
+ gvtFontFamily = new FOPGVTFontFamily(fontInfo, familyName, triplet);
+ }
+ return gvtFontFamily;
+ }
+
+ public FOPGVTFontFamily getDefault() {
+ return resolve("any");
+ }
+
+ public FOPGVTFontFamily getFamilyThatCanDisplay(char c) {
+ Map<String, Typeface> fonts = fontInfo.getFonts();
+ for (Typeface font : fonts.values()) {
+ if (font.hasChar(c)) {
+ String fontFamily = font.getFamilyNames().iterator().next();
+ return new FOPGVTFontFamily(fontInfo, fontFamily,
+ new FontTriplet(fontFamily, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL));
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/font/FOPGVTFont.java b/src/java/org/apache/fop/svg/font/FOPGVTFont.java
new file mode 100644
index 000000000..c55e2fa8b
--- /dev/null
+++ b/src/java/org/apache/fop/svg/font/FOPGVTFont.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.svg.font;
+
+import java.awt.font.FontRenderContext;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+
+import org.apache.batik.gvt.font.GVTFont;
+import org.apache.batik.gvt.font.GVTFontFamily;
+import org.apache.batik.gvt.font.GVTGlyphVector;
+import org.apache.batik.gvt.font.GVTLineMetrics;
+
+import org.apache.fop.fonts.Font;
+import org.apache.fop.fonts.FontMetrics;
+
+public class FOPGVTFont implements GVTFont {
+
+ private final Font font;
+
+ private final GVTFontFamily fontFamily;
+
+ public FOPGVTFont(Font font, GVTFontFamily fontFamily) {
+ this.font = font;
+ this.fontFamily = fontFamily;
+ }
+
+ public Font getFont() {
+ return font;
+ }
+
+ public boolean canDisplay(char c) {
+ return font.hasChar(c);
+ }
+
+ public int canDisplayUpTo(char[] text, int start, int limit) {
+ for (int i = start; i < limit; i++) {
+ if (!canDisplay(text[i])) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
+ public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
+ for (char c = iter.setIndex(start); iter.getIndex() < limit; c = iter.next()) {
+ if (!canDisplay(c)) {
+ return iter.getIndex();
+ }
+ }
+ return -1;
+ }
+
+ public int canDisplayUpTo(String str) {
+ for (int i = 0; i < str.length(); i++) {
+ if (!canDisplay(str.charAt(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public GVTGlyphVector createGlyphVector(FontRenderContext frc, char[] chars) {
+ return createGlyphVector(frc, new String(chars));
+ }
+
+ public GVTGlyphVector createGlyphVector(FontRenderContext frc, CharacterIterator ci) {
+ // TODO Batik does manual glyph shaping for Arabic. Replace with complex scripts implementation
+ return new FOPGVTGlyphVector(this, ci, frc);
+ }
+
+ public GVTGlyphVector createGlyphVector(FontRenderContext frc,
+ int[] glyphCodes,
+ CharacterIterator ci) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ public GVTGlyphVector createGlyphVector(FontRenderContext frc, String str) {
+ StringCharacterIterator sci = new StringCharacterIterator(str);
+ return createGlyphVector(frc, sci);
+ }
+
+ public FOPGVTFont deriveFont(float size) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ public String getFamilyName() {
+ return fontFamily.getFamilyName();
+ }
+
+ public GVTLineMetrics getLineMetrics(char[] chars, int beginIndex, int limit, FontRenderContext frc) {
+ return getLineMetrics(limit - beginIndex);
+ }
+
+ GVTLineMetrics getLineMetrics(int numChars) {
+ numChars = numChars < 0 ? 0 : numChars;
+ FontMetrics metrics = font.getFontMetrics();
+ int size = font.getFontSize();
+ return new GVTLineMetrics(
+ metrics.getCapHeight(size) / 1000000f,
+ java.awt.Font.ROMAN_BASELINE, // Not actually used by Batik
+ null, // Not actually used by Batik
+ -metrics.getDescender(size) / 1000000f,
+ 0, // Not actually used by Batik
+ 0, // Not actually used by Batik
+ numChars,
+ -metrics.getStrikeoutPosition(size) / 1000000f,
+ metrics.getStrikeoutThickness(size) / 1000000f,
+ -metrics.getUnderlinePosition(size) / 1000000f,
+ metrics.getUnderlineThickness(size) / 1000000f,
+ -metrics.getCapHeight(size) / 1000000f, // Because this is what Batik does in GVTLineMetrics
+ metrics.getUnderlineThickness(size) / 1000000f);
+ }
+
+ public GVTLineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, int limit,
+ FontRenderContext frc) {
+ return getLineMetrics(limit - beginIndex);
+ }
+
+ public GVTLineMetrics getLineMetrics(String str, FontRenderContext frc) {
+ return getLineMetrics(str.length());
+ }
+
+ public GVTLineMetrics getLineMetrics(String str, int beginIndex, int limit, FontRenderContext frc) {
+ return getLineMetrics(limit - beginIndex);
+ }
+
+ public float getSize() {
+ return font.getFontSize() / 1000f;
+ }
+
+ public float getVKern(int glyphCode1, int glyphCode2) {
+ return 0;
+ }
+
+ public float getHKern(int glyphCode1, int glyphCode2) {
+ // TODO Cannot be implemented until getKernValue takes glyph indices instead of character codes
+ return 0;
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/font/FOPGVTFontFamily.java b/src/java/org/apache/fop/svg/font/FOPGVTFontFamily.java
new file mode 100644
index 000000000..036b560a0
--- /dev/null
+++ b/src/java/org/apache/fop/svg/font/FOPGVTFontFamily.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.svg.font;
+
+import java.awt.font.TextAttribute;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import org.apache.batik.gvt.font.GVTFontFace;
+import org.apache.batik.gvt.font.GVTFontFamily;
+
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.svg.ACIUtils;
+
+public class FOPGVTFontFamily implements GVTFontFamily {
+
+ private final FontInfo fontInfo;
+
+ private final FontTriplet fontTriplet;
+
+ private final String familyName;
+
+ public FOPGVTFontFamily(FontInfo fontInfo, String familyName, FontTriplet triplet) {
+ this.fontInfo = fontInfo;
+ this.fontTriplet = triplet;
+ this.familyName = familyName;
+ }
+
+ public String getFamilyName() {
+ return familyName;
+ }
+
+ public GVTFontFace getFontFace() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ public FOPGVTFont deriveFont(float size, AttributedCharacterIterator aci) {
+ return deriveFont(size, aci.getAttributes());
+ }
+
+ public FOPGVTFont deriveFont(float size, @SuppressWarnings("rawtypes") Map attrs) {
+ Float fontWeight = (Float) attrs.get(TextAttribute.WEIGHT);
+ int weight = fontWeight == null ? fontTriplet.getWeight() : ACIUtils.toCSSWeight(fontWeight);
+ Float fontStyle = (Float) attrs.get(TextAttribute.POSTURE);
+ String style = fontStyle == null ? fontTriplet.getStyle() : ACIUtils.toStyle(fontStyle);
+ FontTriplet triplet = fontInfo.fontLookup(fontTriplet.getName(), style, weight);
+ return new FOPGVTFont(fontInfo.getFontInstance(triplet, (int) (size * 1000)), this);
+ }
+
+ public boolean isComplex() {
+ return false;
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java b/src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java
new file mode 100644
index 000000000..3567bb508
--- /dev/null
+++ b/src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.svg.font;
+
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.text.AttributedCharacterIterator;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Arrays;
+
+import org.apache.batik.gvt.font.GVTFont;
+import org.apache.batik.gvt.font.GVTGlyphMetrics;
+import org.apache.batik.gvt.font.GVTGlyphVector;
+import org.apache.batik.gvt.font.GVTLineMetrics;
+
+import org.apache.fop.fonts.Font;
+import org.apache.fop.fonts.FontMetrics;
+import org.apache.fop.fonts.GlyphMapping;
+import org.apache.fop.fonts.TextFragment;
+import org.apache.fop.traits.MinOptMax;
+
+class FOPGVTGlyphVector implements GVTGlyphVector {
+
+ private final CharacterIterator charIter;
+
+ private final FOPGVTFont font;
+
+ private final int fontSize;
+
+ private final FontMetrics fontMetrics;
+
+ private final FontRenderContext frc;
+
+ private int[] glyphs;
+
+ private float[] positions;
+
+ private Rectangle2D[] boundingBoxes;
+
+ private GeneralPath outline;
+
+ private AffineTransform[] glyphTransforms;
+
+ private boolean[] glyphVisibilities;
+
+ private Rectangle2D logicalBounds;
+
+ FOPGVTGlyphVector(FOPGVTFont font, final CharacterIterator iter, FontRenderContext frc) {
+ this.charIter = iter;
+ this.font = font;
+ Font f = font.getFont();
+ this.fontSize = f.getFontSize();
+ this.fontMetrics = f.getFontMetrics();
+ this.frc = frc;
+ }
+
+ public void performDefaultLayout() {
+ Font f = font.getFont();
+ TextFragment text = new SVGTextFragment(charIter);
+ MinOptMax letterSpaceIPD = MinOptMax.ZERO;
+ MinOptMax[] letterSpaceAdjustments = new MinOptMax[charIter.getEndIndex() - charIter.getBeginIndex()];
+ GlyphMapping mapping = GlyphMapping.doGlyphMapping(text, charIter.getBeginIndex(), charIter.getEndIndex(),
+ f, letterSpaceIPD, letterSpaceAdjustments, '\0', '\0', false, 0 /* TODO */);
+ glyphs = buildGlyphs(f, mapping.mapping != null ? new StringCharacterIterator(mapping.mapping) : charIter);
+ buildGlyphPositions(mapping, letterSpaceAdjustments);
+ this.glyphVisibilities = new boolean[this.glyphs.length];
+ Arrays.fill(glyphVisibilities, true);
+ this.glyphTransforms = new AffineTransform[this.glyphs.length];
+ }
+
+ private static class SVGTextFragment implements TextFragment {
+
+ private final CharacterIterator charIter;
+
+ SVGTextFragment(CharacterIterator charIter) {
+ this.charIter = charIter;
+ }
+
+ public CharSequence subSequence(int startIndex, int endIndex) {
+ StringBuilder sb = new StringBuilder();
+ for (char c = charIter.first(); c != CharacterIterator.DONE; c = charIter.next()) {
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ public String getScript() {
+ return "DFLT"; // TODO pass on script value from SVG
+ }
+
+ public String getLanguage() {
+ return "dflt"; // TODO pass on language value from SVG
+ }
+
+ public char charAt(int index) {
+ return charIter.setIndex(index - charIter.getBeginIndex());
+ }
+ }
+
+ private int[] buildGlyphs(Font font, final CharacterIterator charIter) {
+ int[] glyphs = new int[charIter.getEndIndex() - charIter.getBeginIndex()];
+ int index = 0;
+ for (char c = charIter.first(); c != CharacterIterator.DONE; c = charIter.next()) {
+ glyphs[index] = font.mapChar(c);
+ index++;
+ }
+ return glyphs;
+ }
+
+ private void buildGlyphPositions(GlyphMapping ai, MinOptMax[] letterSpaceAdjustments) {
+ positions = new float[2 * glyphs.length + 2];
+ if (ai.gposAdjustments != null) {
+ assert ai.gposAdjustments.length == glyphs.length;
+ for (int glyphIndex = 0; glyphIndex < glyphs.length; glyphIndex++) {
+ int n = 2 * glyphIndex;
+ if (ai.gposAdjustments[glyphIndex] != null) {
+ for (int p = 0; p < 4; p++) {
+ positions[n + p] += ai.gposAdjustments[glyphIndex][p] / 1000f;
+ }
+ }
+ positions[n + 2] += positions[n] + getGlyphWidth(glyphIndex);
+ }
+ } else {
+ for (int i = 0, n = 2; i < glyphs.length; i++, n += 2) {
+ int kern = i < glyphs.length - 1 && letterSpaceAdjustments[i + 1] != null
+ ? letterSpaceAdjustments[i + 1].getOpt()
+ : 0;
+ positions[n] = positions[n - 2] + getGlyphWidth(i) + kern / 1000f;
+ positions[n + 1] = 0;
+ }
+ }
+ }
+
+ private float getGlyphWidth(int index) {
+ return fontMetrics.getWidth(glyphs[index], fontSize) / 1000000f;
+ }
+
+ public GVTFont getFont() {
+ return font;
+ }
+
+ public FontRenderContext getFontRenderContext() {
+ return frc;
+ }
+
+ public int getGlyphCode(int glyphIndex) {
+ return glyphs[glyphIndex];
+ }
+
+ public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+ int[] codeReturn) {
+ if (codeReturn == null) {
+ codeReturn = new int[numEntries];
+ }
+ System.arraycopy(glyphs, beginGlyphIndex, codeReturn, 0, numEntries);
+ return codeReturn;
+ }
+
+ public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ public Shape getGlyphLogicalBounds(int glyphIndex) {
+ GVTGlyphMetrics metrics = getGlyphMetrics(glyphIndex);
+ Point2D pos = getGlyphPosition(glyphIndex);
+ GVTLineMetrics fontMetrics = font.getLineMetrics(0);
+ Rectangle2D bounds = new Rectangle2D.Float(0, -fontMetrics.getDescent(), metrics.getHorizontalAdvance(),
+ fontMetrics.getAscent() + fontMetrics.getDescent());
+ AffineTransform t = AffineTransform.getTranslateInstance(pos.getX(), pos.getY());
+ AffineTransform transf = getGlyphTransform(glyphIndex);
+ if (transf != null) {
+ t.concatenate(transf);
+ }
+ t.scale(1, -1); // Translate from glyph coordinate system to user
+ return t.createTransformedShape(bounds);
+ }
+
+ public GVTGlyphMetrics getGlyphMetrics(int glyphIndex) {
+ Rectangle2D bbox = getBoundingBoxes()[glyphIndex];
+ return new GVTGlyphMetrics(positions[2 * (glyphIndex + 1)] - positions[2 * glyphIndex],
+ (fontMetrics.getAscender(fontSize) - fontMetrics.getDescender(fontSize)) / 1000000f,
+ bbox, GlyphMetrics.STANDARD);
+ }
+
+ public Shape getGlyphOutline(int glyphIndex) {
+ Shape glyphBox = getBoundingBoxes()[glyphIndex];
+ AffineTransform tr = AffineTransform.getTranslateInstance(positions[glyphIndex * 2],
+ positions[glyphIndex * 2 + 1]);
+ AffineTransform glyphTransform = getGlyphTransform(glyphIndex);
+ if (glyphTransform != null) {
+ tr.concatenate(glyphTransform);
+ }
+ return tr.createTransformedShape(glyphBox);
+ }
+
+ public Rectangle2D getGlyphCellBounds(int glyphIndex) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ public Point2D getGlyphPosition(int glyphIndex) {
+ int positionIndex = glyphIndex * 2;
+ return new Point2D.Float(positions[positionIndex], positions[positionIndex + 1]);
+ }
+
+ public float[] getGlyphPositions(int beginGlyphIndex, int numEntries, float[] positionReturn) {
+ if (positionReturn == null) {
+ positionReturn = new float[numEntries * 2];
+ }
+ System.arraycopy(positions, beginGlyphIndex * 2, positionReturn, 0, numEntries * 2);
+ return positionReturn;
+ }
+
+ public AffineTransform getGlyphTransform(int glyphIndex) {
+ return glyphTransforms[glyphIndex];
+ }
+
+ public Shape getGlyphVisualBounds(int glyphIndex) {
+ Rectangle2D bbox = getBoundingBoxes()[glyphIndex];
+ Point2D pos = getGlyphPosition(glyphIndex);
+ AffineTransform t = AffineTransform.getTranslateInstance(pos.getX(), pos.getY());
+ AffineTransform transf = getGlyphTransform(glyphIndex);
+ if (transf != null) {
+ t.concatenate(transf);
+ }
+ return t.createTransformedShape(bbox);
+ }
+
+ public Rectangle2D getLogicalBounds() {
+ if (logicalBounds == null) {
+ GeneralPath logicalBoundsPath = new GeneralPath();
+ for (int i = 0; i < getNumGlyphs(); i++) {
+ Shape glyphLogicalBounds = getGlyphLogicalBounds(i);
+ logicalBoundsPath.append(glyphLogicalBounds, false);
+ }
+ logicalBounds = logicalBoundsPath.getBounds2D();
+ }
+ return logicalBounds;
+ }
+
+ public int getNumGlyphs() {
+ return glyphs.length;
+ }
+
+ public Shape getOutline() {
+ if (outline == null) {
+ outline = new GeneralPath();
+ for (int i = 0; i < glyphs.length; i++) {
+ outline.append(getGlyphOutline(i), false);
+ }
+ }
+ return outline;
+ }
+
+ public Shape getOutline(float x, float y) {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ public Rectangle2D getGeometricBounds() {
+ // TODO Auto-generated method stub
+ throw new UnsupportedOperationException();
+ }
+
+ public Rectangle2D getBounds2D(AttributedCharacterIterator aci) {
+ return getOutline().getBounds2D();
+ }
+
+ public void setGlyphPosition(int glyphIndex, Point2D newPos) {
+ int idx = glyphIndex * 2;
+ positions[idx] = (float) newPos.getX();
+ positions[idx + 1] = (float) newPos.getY();
+ }
+
+ public void setGlyphTransform(int glyphIndex, AffineTransform newTX) {
+ glyphTransforms[glyphIndex] = newTX;
+ }
+
+ public void setGlyphVisible(int glyphIndex, boolean visible) {
+ glyphVisibilities[glyphIndex] = visible;
+ }
+
+ public boolean isGlyphVisible(int glyphIndex) {
+ return glyphVisibilities[glyphIndex];
+ }
+
+ public int getCharacterCount(int startGlyphIndex, int endGlyphIndex) {
+ // TODO Not that simple if complex scripts are involved
+ return endGlyphIndex - startGlyphIndex + 1;
+ }
+
+ public void draw(Graphics2D graphics2d, AttributedCharacterIterator aci) {
+ // NOP
+ }
+
+ private Rectangle2D[] getBoundingBoxes() {
+ if (boundingBoxes == null) {
+ buildBoundingBoxes();
+ }
+ return boundingBoxes;
+ }
+
+ private void buildBoundingBoxes() {
+ boundingBoxes = new Rectangle2D[glyphs.length];
+ for (int i = 0; i < glyphs.length; i++) {
+ Rectangle bbox = fontMetrics.getBoundingBox(glyphs[i], fontSize);
+ boundingBoxes[i] = new Rectangle2D.Float(bbox.x / 1000000f, -(bbox.y + bbox.height) / 1000000f,
+ bbox.width / 1000000f, bbox.height / 1000000f);
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/svg/font/FilteringFontFamilyResolver.java b/src/java/org/apache/fop/svg/font/FilteringFontFamilyResolver.java
new file mode 100644
index 000000000..319d6b2b8
--- /dev/null
+++ b/src/java/org/apache/fop/svg/font/FilteringFontFamilyResolver.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.svg.font;
+
+
+public class FilteringFontFamilyResolver implements FOPFontFamilyResolver {
+
+ private final FOPFontFamilyResolver delegate;
+
+ public FilteringFontFamilyResolver(FOPFontFamilyResolver delegate) {
+ this.delegate = delegate;
+ }
+
+ public String lookup(String familyName) {
+ return delegate.lookup(familyName);
+ }
+
+ public FOPGVTFontFamily resolve(String familyName) {
+ return delegate.resolve(familyName);
+ }
+
+ public FOPGVTFontFamily getDefault() {
+ return delegate.getDefault();
+ }
+
+ public FOPGVTFontFamily getFamilyThatCanDisplay(char c) {
+ return delegate.getFamilyThatCanDisplay(c);
+ }
+
+}