From: Glenn Adams Date: Tue, 14 Oct 2014 02:28:08 +0000 (+0000) Subject: FOP-2249: elide formatting controls - preliminary X-Git-Tag: fop-2_0~46 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f5c6b91c2c4925c0c85afc3851769f8a6b08f4b1;p=xmlgraphics-fop.git FOP-2249: elide formatting controls - preliminary git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1631605 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/fop/complexscripts/fonts/Substitutable.java b/src/java/org/apache/fop/complexscripts/fonts/Substitutable.java index ef349240a..428995051 100644 --- a/src/java/org/apache/fop/complexscripts/fonts/Substitutable.java +++ b/src/java/org/apache/fop/complexscripts/fonts/Substitutable.java @@ -46,10 +46,11 @@ public interface Substitutable { * @param script a script identifier * @param language a language identifier * @param associations optional list to receive list of character associations + * @param retainControls if true, then retain control characters and their glyph mappings, otherwise remove * @return output sequence (represented as a character sequence, where each character in the returned sequence * denotes "font characters", i.e., character codes that map directly (1-1) to their associated glyphs */ - CharSequence performSubstitution(CharSequence cs, String script, String language, List associations); + CharSequence performSubstitution(CharSequence cs, String script, String language, List associations, boolean retainControls); /** * Reorder combining marks in character sequence so that they precede (within the sequence) the base diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java index 399be056a..b3cea0d6f 100644 --- a/src/java/org/apache/fop/fonts/Font.java +++ b/src/java/org/apache/fop/fonts/Font.java @@ -417,10 +417,10 @@ public class Font implements Substitutable, Positionable { /** {@inheritDoc} */ public CharSequence performSubstitution(CharSequence cs, - String script, String language, List associations) { + String script, String language, List associations, boolean retainControls) { if (metric instanceof Substitutable) { Substitutable s = (Substitutable) metric; - return s.performSubstitution(cs, script, language, associations); + return s.performSubstitution(cs, script, language, associations, retainControls); } else { throw new UnsupportedOperationException(); } diff --git a/src/java/org/apache/fop/fonts/GlyphMapping.java b/src/java/org/apache/fop/fonts/GlyphMapping.java index 59bf9f148..e75d9e0b6 100644 --- a/src/java/org/apache/fop/fonts/GlyphMapping.java +++ b/src/java/org/apache/fop/fonts/GlyphMapping.java @@ -83,11 +83,12 @@ public class GlyphMapping { public static GlyphMapping doGlyphMapping(TextFragment text, int startIndex, int endIndex, Font font, MinOptMax letterSpaceIPD, MinOptMax[] letterSpaceAdjustArray, char precedingChar, char breakOpportunityChar, final boolean endsWithHyphen, int level, - boolean dontOptimizeForIdentityMapping, boolean retainAssociations) { + boolean dontOptimizeForIdentityMapping, boolean retainAssociations, boolean retainControls) { GlyphMapping mapping; if (font.performsSubstitution() || font.performsPositioning()) { mapping = processWordMapping(text, startIndex, endIndex, font, - breakOpportunityChar, endsWithHyphen, level, dontOptimizeForIdentityMapping, retainAssociations); + breakOpportunityChar, endsWithHyphen, level, + dontOptimizeForIdentityMapping, retainAssociations, retainControls); } else { mapping = processWordNoMapping(text, startIndex, endIndex, font, letterSpaceIPD, letterSpaceAdjustArray, precedingChar, breakOpportunityChar, endsWithHyphen, level); @@ -98,7 +99,7 @@ public class GlyphMapping { private static GlyphMapping processWordMapping(TextFragment text, int startIndex, int endIndex, final Font font, final char breakOpportunityChar, final boolean endsWithHyphen, int level, - boolean dontOptimizeForIdentityMapping, boolean retainAssociations) { + boolean dontOptimizeForIdentityMapping, boolean retainAssociations, boolean retainControls) { int e = endIndex; // end index of word in FOText character buffer int nLS = 0; // # of letter spaces String script = text.getScript(); @@ -126,7 +127,7 @@ public class GlyphMapping { // 3. perform mapping of chars to glyphs ... to glyphs ... to chars, retaining // associations if requested. List associations = retainAssociations ? new java.util.ArrayList() : null; - CharSequence mcs = font.performSubstitution(ics, script, language, associations); + CharSequence mcs = font.performSubstitution(ics, script, language, associations, retainControls); // 4. compute glyph position adjustments on (substituted) characters. int[][] gpa = null; diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index fb0d8f06f..323a46cf1 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -415,10 +415,12 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, /** * {@inheritDoc} */ - public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations) { + public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations, + boolean retainControls) { load(true); if (realFontDescriptor instanceof Substitutable) { - return ((Substitutable)realFontDescriptor).performSubstitution(cs, script, language, associations); + return ((Substitutable)realFontDescriptor).performSubstitution(cs, + script, language, associations, retainControls); } else { return cs; } diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index d95958c19..296c86de2 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -38,6 +38,7 @@ import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; import org.apache.fop.complexscripts.fonts.GlyphTable; import org.apache.fop.complexscripts.fonts.Positionable; import org.apache.fop.complexscripts.fonts.Substitutable; +import org.apache.fop.complexscripts.util.CharAssociation; import org.apache.fop.complexscripts.util.CharNormalize; import org.apache.fop.complexscripts.util.GlyphSequence; import org.apache.fop.util.CharUtilities; @@ -490,7 +491,8 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl } /** {@inheritDoc} */ - public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations) { + public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations, + boolean retainControls) { if (gsub != null) { CharSequence ncs = normalize(cs, associations); GlyphSequence igs = mapCharsToGlyphs(ncs, associations); @@ -499,6 +501,9 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl associations.clear(); associations.addAll(ogs.getAssociations()); } + if (!retainControls) { + ogs = elideControls(ogs); + } CharSequence ocs = mapGlyphsToChars(ogs); return ocs; } else { @@ -695,6 +700,66 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl return sb; } + private static GlyphSequence elideControls(GlyphSequence gs) { + if (hasElidableControl(gs)) { + int[] ca = gs.getCharacterArray(false); + IntBuffer ngb = IntBuffer.allocate(gs.getGlyphCount()); + List nal = new java.util.ArrayList(gs.getGlyphCount()); + for (int i = 0, n = gs.getGlyphCount(); i < n; ++i) { + CharAssociation a = gs.getAssociation(i); + int s = a.getStart(); + int e = a.getEnd(); + while (s < e) { + int ch = ca [ s ]; + if (isElidableControl(ch)) { + break; + } else { + ++s; + } + } + if (s == e) { + ngb.put(gs.getGlyph(i)); + nal.add(a); + } + } + ngb.flip(); + return new GlyphSequence(gs.getCharacters(), ngb, nal, gs.getPredications()); + } else { + return gs; + } + } + + private static boolean hasElidableControl(GlyphSequence gs) { + int[] ca = gs.getCharacterArray(false); + for (int i = 0, n = ca.length; i < n; ++i) { + int ch = ca [ i ]; + if (isElidableControl(ch)) { + return true; + } + } + return false; + } + + private static boolean isElidableControl(int ch) { + if (ch < 0x0020) { + return true; + } else if ((ch >= 0x80) && (ch < 0x00A0)) { + return true; + } else if ((ch >= 0x2000) && (ch <= 0x206F)) { + if ((ch >= 0x200B) && (ch <= 0x200F)) { + return true; + } else if ((ch >= 0x2028) && (ch <= 0x202E)) { + return true; + } else if ((ch >= 0x2066) && (ch <= 0x206F)) { + return true; + } else { + return ch == 0x2060; + } + } else { + return false; + } + } + @Override public boolean hasFeature(int tableType, String script, String language, String feature) { GlyphTable table; diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index c7258ee6b..a0cad7973 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -761,6 +761,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { char ch = 0; int level = -1; int prevLevel = -1; + boolean retainControls = false; while (nextStart < foText.length()) { ch = foText.charAt(nextStart); level = foText.bidiLevelAt(nextStart); @@ -799,7 +800,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { || ((prevLevel != -1) && (level != prevLevel))) { // this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN prevMapping = processWord(alignment, sequence, prevMapping, ch, - breakOpportunity, true, prevLevel); + breakOpportunity, true, prevLevel, retainControls); } } else if (inWhitespace) { if (ch != CharUtilities.SPACE || breakOpportunity) { @@ -850,7 +851,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { // Process any last elements if (inWord) { - processWord(alignment, sequence, prevMapping, ch, false, false, prevLevel); + processWord(alignment, sequence, prevMapping, ch, false, false, prevLevel, retainControls); } else if (inWhitespace) { processWhitespace(alignment, sequence, !keepTogether, prevLevel); } else if (mapping != null) { @@ -918,7 +919,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { private GlyphMapping processWord(final int alignment, final KnuthSequence sequence, GlyphMapping prevMapping, final char ch, final boolean breakOpportunity, - final boolean checkEndsWithHyphen, int level) { + final boolean checkEndsWithHyphen, int level, boolean retainControls) { //Word boundary found, process widths and kerning int lastIndex = nextStart; @@ -934,7 +935,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { && prevMapping.endIndex > 0 ? foText.charAt(prevMapping.endIndex - 1) : 0; GlyphMapping mapping = GlyphMapping.doGlyphMapping(foText, thisStart, lastIndex, font, letterSpaceIPD, letterSpaceAdjustArray, precedingChar, breakOpportunityChar, - endsWithHyphen, level, false, false); + endsWithHyphen, level, false, false, retainControls); prevMapping = mapping; addGlyphMapping(mapping); tempStart = nextStart; diff --git a/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java b/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java index fcb913d53..62283915f 100644 --- a/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java +++ b/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java @@ -268,9 +268,10 @@ public class CustomFontMetricsMapper extends Typeface implements FontMetricsMapp /** * {@inheritDoc} */ - public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations) { + public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations, + boolean retainControls) { if (typeface instanceof Substitutable) { - return ((Substitutable) typeface).performSubstitution(cs, script, language, associations); + return ((Substitutable) typeface).performSubstitution(cs, script, language, associations, retainControls); } else { return cs; } diff --git a/src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java b/src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java index 77bdec48d..ef9adf08f 100644 --- a/src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java +++ b/src/java/org/apache/fop/svg/font/FOPGVTGlyphVector.java @@ -90,8 +90,10 @@ public class FOPGVTGlyphVector implements GVTGlyphVector { Font f = font.getFont(); MinOptMax letterSpaceIPD = MinOptMax.ZERO; MinOptMax[] letterSpaceAdjustments = new MinOptMax[text.getEndIndex() - text.getBeginIndex()]; + boolean retainControls = false; GlyphMapping mapping = GlyphMapping.doGlyphMapping(text, text.getBeginIndex(), text.getEndIndex(), - f, letterSpaceIPD, letterSpaceAdjustments, '\0', '\0', false, text.getBidiLevel(), true, true); + f, letterSpaceIPD, letterSpaceAdjustments, '\0', '\0', + false, text.getBidiLevel(), true, true, retainControls); CharacterIterator glyphAsCharIter = mapping.mapping != null ? new StringCharacterIterator(mapping.mapping) : text.getIterator(); this.glyphs = buildGlyphs(f, glyphAsCharIter);