FOP-3277: Add font substitution support for PDFTranscoder
diff --git a/fop-core/src/main/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/fop-core/src/main/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
index 6fdc697..8f4e671 100644
--- a/fop-core/src/main/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
+++ b/fop-core/src/main/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
@@ -98,7 +98,7 @@
* be used to influence the start position of the first letter. The entry i+1 defines the
* cursor advancement after the character i. A null entry means no special advancement.
*/
- private final MinOptMax[] letterSpaceAdjustArray; //size = textArray.length + 1
+ private MinOptMax[] letterSpaceAdjustArray; //size = textArray.length + 1
/** Font used for the space between words. */
private Font spaceFont;
@@ -142,7 +142,6 @@
*/
public TextLayoutManager(FOText node, FOUserAgent userAgent) {
foText = node;
- letterSpaceAdjustArray = new MinOptMax[node.length() + 1];
mappings = new ArrayList<GlyphMapping>();
this.userAgent = userAgent;
}
@@ -267,7 +266,7 @@
}
for (int i = mapping.startIndex; i < mapping.endIndex; i++) {
- MinOptMax letterSpaceAdjustment = letterSpaceAdjustArray[i + 1];
+ MinOptMax letterSpaceAdjustment = getLetterSpaceAdjustment(i + 1);
if (letterSpaceAdjustment != null && letterSpaceAdjustment.isElastic()) {
letterSpaceCount++;
}
@@ -659,8 +658,7 @@
int j = letterSpaceAdjustIndex + i;
if (j > 0) {
int k = wordMapping.startIndex + i;
- MinOptMax adj = (k < letterSpaceAdjustArray.length)
- ? letterSpaceAdjustArray [ k ] : null;
+ MinOptMax adj = getLetterSpaceAdjustment(k);
letterSpaceAdjust [ j ] = (adj == null) ? 0 : adj.getOpt();
}
if (letterSpaceCount > 0) {
@@ -975,6 +973,9 @@
char breakOpportunityChar = breakOpportunity ? ch : 0;
char precedingChar = prevMapping != null && !prevMapping.isSpace
&& prevMapping.endIndex > 0 ? foText.charAt(prevMapping.endIndex - 1) : 0;
+ if (letterSpaceAdjustArray == null && font.hasKerning()) {
+ letterSpaceAdjustArray = new MinOptMax[foText.length() + 1];
+ }
GlyphMapping mapping = GlyphMapping.doGlyphMapping(foText, thisStart, lastIndex, font,
letterSpaceIPD, letterSpaceAdjustArray, precedingChar, breakOpportunityChar,
endsWithHyphen, level, false, false, retainControls);
@@ -1076,7 +1077,7 @@
newIPD = newIPD.plus(font.getCharWidth(cp));
//if (i > startIndex) {
if (i < stopIndex) {
- MinOptMax letterSpaceAdjust = letterSpaceAdjustArray[i + 1];
+ MinOptMax letterSpaceAdjust = getLetterSpaceAdjustment(i + 1);
if (i == stopIndex - 1 && hyphenFollows) {
//the letter adjust here needs to be handled further down during
//element generation because it depends on hyph/no-hyph condition
@@ -1388,7 +1389,7 @@
MinOptMax widthIfNoBreakOccurs = null;
if (mapping.endIndex < foText.length()) {
//Add in kerning in no-break condition
- widthIfNoBreakOccurs = letterSpaceAdjustArray[mapping.endIndex];
+ widthIfNoBreakOccurs = getLetterSpaceAdjustment(mapping.endIndex);
}
//if (mapping.breakIndex)
@@ -1523,4 +1524,10 @@
+ "}";
}
+ protected MinOptMax getLetterSpaceAdjustment(int i) {
+ if (letterSpaceAdjustArray == null || i >= letterSpaceAdjustArray.length) {
+ return null;
+ }
+ return letterSpaceAdjustArray[i];
+ }
}
diff --git a/fop-core/src/main/java/org/apache/fop/traits/MinOptMax.java b/fop-core/src/main/java/org/apache/fop/traits/MinOptMax.java
index a647ae3..fb339b7 100644
--- a/fop-core/src/main/java/org/apache/fop/traits/MinOptMax.java
+++ b/fop-core/src/main/java/org/apache/fop/traits/MinOptMax.java
@@ -20,6 +20,7 @@
package org.apache.fop.traits;
import java.io.Serializable;
+import java.util.Objects;
/**
* This class holds the resolved (as mpoints) form of a
@@ -37,7 +38,7 @@
/**
* The zero <code>MinOptMax</code> instance with <code>min == opt == max == 0</code>.
*/
- public static final MinOptMax ZERO = getInstance(0);
+ public static final MinOptMax ZERO = new MinOptMax(0, 0, 0);
private final int min;
private final int opt;
@@ -59,6 +60,9 @@
if (max < opt) {
throw new IllegalArgumentException("max (" + max + ") < opt (" + opt + ")");
}
+ if (min == 0 && opt == 0 && max == 0) {
+ return ZERO;
+ }
return new MinOptMax(min, opt, max);
}
@@ -71,7 +75,7 @@
* @see #isStiff()
*/
public static MinOptMax getInstance(int value) {
- return new MinOptMax(value, value, value);
+ return getInstance(value, value, value);
}
// Private constructor without consistency checks
@@ -136,7 +140,7 @@
* @return the sum of this <code>MinOptMax</code> and the given <code>MinOptMax</code>.
*/
public MinOptMax plus(MinOptMax operand) {
- return new MinOptMax(min + operand.min, opt + operand.opt, max + operand.max);
+ return getInstance(min + operand.min, opt + operand.opt, max + operand.max);
}
@@ -147,7 +151,7 @@
* @return the result of the addition
*/
public MinOptMax plus(int value) {
- return new MinOptMax(min + value, opt + value, max + value);
+ return getInstance(min + value, opt + value, max + value);
}
/**
@@ -166,7 +170,7 @@
public MinOptMax minus(MinOptMax operand) throws ArithmeticException {
checkCompatibility(getShrink(), operand.getShrink(), "shrink");
checkCompatibility(getStretch(), operand.getStretch(), "stretch");
- return new MinOptMax(min - operand.min, opt - operand.opt, max - operand.max);
+ return getInstance(min - operand.min, opt - operand.opt, max - operand.max);
}
private void checkCompatibility(int thisElasticity, int operandElasticity, String msge) {
@@ -184,7 +188,7 @@
* @return the result of the subtraction
*/
public MinOptMax minus(int value) {
- return new MinOptMax(min - value, opt - value, max - value);
+ return getInstance(min - value, opt - value, max - value);
}
/**
@@ -328,10 +332,7 @@
* {@inheritDoc}
*/
public int hashCode() {
- int result = min;
- result = 31 * result + opt;
- result = 31 * result + max;
- return result;
+ return Objects.hash(min, opt, max);
}
/**
diff --git a/fop-core/src/test/java/org/apache/fop/layoutmgr/inline/TextLayoutManagerTestCase.java b/fop-core/src/test/java/org/apache/fop/layoutmgr/inline/TextLayoutManagerTestCase.java
new file mode 100644
index 0000000..c2b19fe
--- /dev/null
+++ b/fop-core/src/test/java/org/apache/fop/layoutmgr/inline/TextLayoutManagerTestCase.java
@@ -0,0 +1,29 @@
+/*
+ * 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.layoutmgr.inline;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TextLayoutManagerTestCase {
+ @Test
+ public void testLetterSpaceAdjustArray() {
+ Assert.assertNull(new TextLayoutManager(null, null).getLetterSpaceAdjustment(1));
+ }
+}
diff --git a/fop-core/src/test/java/org/apache/fop/traits/MinOptMaxTestCase.java b/fop-core/src/test/java/org/apache/fop/traits/MinOptMaxTestCase.java
index 190fb47..abe0c2c 100644
--- a/fop-core/src/test/java/org/apache/fop/traits/MinOptMaxTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/traits/MinOptMaxTestCase.java
@@ -37,6 +37,7 @@
@Test
public void testZero() {
assertEquals(MinOptMax.getInstance(0), MinOptMax.ZERO);
+ assertTrue(MinOptMax.getInstance(0, 0, 0) == MinOptMax.ZERO);
}
@Test