Browse Source

Fixed a bug in TTF subsetting where a composite glyph could get remapped more than once resulting in garbled character.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1151195 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_1rc1old
Jeremias Maerki 13 years ago
parent
commit
61bbd77c1e
2 changed files with 53 additions and 38 deletions
  1. 49
    38
      src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java
  2. 4
    0
      status.xml

+ 49
- 38
src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java View File

import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;




/** /**
* Returns a List containing the glyph itself plus all glyphs * Returns a List containing the glyph itself plus all glyphs
* that this composite glyph uses * that this composite glyph uses
*/ */
private List getIncludedGlyphs(FontFileReader in, int glyphOffset,
private List<Integer> getIncludedGlyphs(FontFileReader in, int glyphOffset,
Integer glyphIdx) throws IOException { Integer glyphIdx) throws IOException {
List ret = new java.util.ArrayList();
List<Integer> ret = new java.util.ArrayList<Integer>();
ret.add(glyphIdx); ret.add(glyphIdx);
int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() + 10; int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() + 10;
Integer compositeIdx = null; Integer compositeIdx = null;
boolean moreComposites = true; boolean moreComposites = true;
while (moreComposites) { while (moreComposites) {
flags = in.readTTFUShort(offset); flags = in.readTTFUShort(offset);
compositeIdx = new Integer(in.readTTFUShort(offset + 2));
compositeIdx = Integer.valueOf(in.readTTFUShort(offset + 2));
ret.add(compositeIdx); ret.add(compositeIdx);


offset += 4; offset += 4;
} }




/**
* We need to remember which composites were already remapped because the value to be
* remapped is being read from the TTF file and being replaced right there. Doing this
* twice would create a bad map the second time.
*/
private Set<Long> remappedComposites = null;

/** /**
* Rewrite all compositepointers in glyphindex glyphIdx * Rewrite all compositepointers in glyphindex glyphIdx
*
*/ */
private void remapComposite(FontFileReader in, Map glyphs,
int glyphOffset,
private void remapComposite(FontFileReader in, Map<Integer, Integer> glyphs,
long glyphOffset,
Integer glyphIdx) throws IOException { Integer glyphIdx) throws IOException {
int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset()
+ 10;
if (remappedComposites == null) {
remappedComposites = new java.util.HashSet<Long>();
}
TTFMtxEntry mtxEntry = mtxTab[glyphIdx.intValue()];
long offset = glyphOffset + mtxEntry.getOffset() + 10;
if (remappedComposites.contains(offset)) {
return;
}
remappedComposites.add(offset);


Integer compositeIdx = null; Integer compositeIdx = null;
int flags = 0; int flags = 0;


while (moreComposites) { while (moreComposites) {
flags = in.readTTFUShort(offset); flags = in.readTTFUShort(offset);
compositeIdx = new Integer(in.readTTFUShort(offset + 2));
Integer newIdx = (Integer)glyphs.get(compositeIdx);
compositeIdx = Integer.valueOf(in.readTTFUShort(offset + 2));
Integer newIdx = glyphs.get(compositeIdx);
if (newIdx == null) { if (newIdx == null) {
// This errormessage would look much better // This errormessage would look much better
// if the fontname was printed to // if the fontname was printed to
continue; continue;
} }


in.writeTTFUShort(offset + 2, newIdx.intValue());
in.writeTTFUShort((int)(offset + 2), newIdx.intValue());


offset += 4; offset += 4;


* mapping * mapping
*/ */
private void scanGlyphs(FontFileReader in, private void scanGlyphs(FontFileReader in,
Map glyphs) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
Map newComposites = null;
Map allComposites = new java.util.HashMap();
Map<Integer, Integer> glyphs) throws IOException {
TTFDirTabEntry glyfTable = (TTFDirTabEntry)dirTabs.get("glyf");
Map<Integer, Integer> newComposites = null;
Set<Integer> allComposites = new java.util.HashSet<Integer>();


int newIndex = glyphs.size(); int newIndex = glyphs.size();


if (entry != null) {
if (glyfTable != null) {
while (newComposites == null || newComposites.size() > 0) { while (newComposites == null || newComposites.size() > 0) {
// Inefficient to iterate through all glyphs // Inefficient to iterate through all glyphs
newComposites = new java.util.HashMap();
newComposites = new java.util.HashMap<Integer, Integer>();


Iterator e = glyphs.keySet().iterator();
while (e.hasNext()) {
Integer origIndex = (Integer)e.next();

if (in.readTTFShort(entry.getOffset()
+ mtxTab[origIndex.intValue()].getOffset()) < 0) {
for (int origIndex : glyphs.keySet()) {
short numberOfContours = in.readTTFShort(glyfTable.getOffset()
+ mtxTab[origIndex].getOffset());
if (numberOfContours < 0) {
// origIndex is a composite glyph // origIndex is a composite glyph
allComposites.put(origIndex, glyphs.get(origIndex));
List composites
= getIncludedGlyphs(in, (int)entry.getOffset(),
allComposites.add(origIndex);
List<Integer> composites
= getIncludedGlyphs(in, (int)glyfTable.getOffset(),
origIndex); origIndex);


if (log.isTraceEnabled()) {
log.trace("Glyph " + origIndex
+ " is a composite glyph using the following glyphs: "
+ composites);
}

// Iterate through all composites pointed to // Iterate through all composites pointed to
// by this composite and check if they exists // by this composite and check if they exists
// in the glyphs map, add them if not. // in the glyphs map, add them if not.
Iterator cps = composites.iterator();
while (cps.hasNext()) {
Integer cIdx = (Integer)cps.next();
for (int cIdx : composites) {
if (glyphs.get(cIdx) == null if (glyphs.get(cIdx) == null
&& newComposites.get(cIdx) == null) { && newComposites.get(cIdx) == null) {
newComposites.put(cIdx,
new Integer(newIndex));
newComposites.put(cIdx, newIndex);
newIndex++; newIndex++;
} }
} }
} }


// Add composites to glyphs // Add composites to glyphs
Iterator m = newComposites.keySet().iterator();
while (m.hasNext()) {
Integer im = (Integer)m.next();
for (int im : newComposites.keySet()) {
glyphs.put(im, newComposites.get(im)); glyphs.put(im, newComposites.get(im));
} }
} }


// Iterate through all composites to remap their composite index // Iterate through all composites to remap their composite index
Iterator ce = allComposites.keySet().iterator();
while (ce.hasNext()) {
remapComposite(in, glyphs, (int)entry.getOffset(),
(Integer)ce.next());
for (int glyphIdx : allComposites) {
remapComposite(in, glyphs, glyfTable.getOffset(), glyphIdx);
} }


} else { } else {

+ 4
- 0
status.xml View File

documents. Example: the fix of marks layering will be such a case when it's done. documents. Example: the fix of marks layering will be such a case when it's done.
--> -->
<release version="FOP Trunk" date="TBD"> <release version="FOP Trunk" date="TBD">
<action context="Fonts" dev="JM" type="fix">
Fixed a bug in TTF subsetting where a composite glyph could get
remapped more than once resulting in garbled character.
</action>
<action context="Fonts" dev="JM" type="fix" fixes-bug="50605"> <action context="Fonts" dev="JM" type="fix" fixes-bug="50605">
Fixed a number of bugs concerning Type 1 and other single-byte fonts Fixed a number of bugs concerning Type 1 and other single-byte fonts
(glyph width mismatches and overlapping characters). (glyph width mismatches and overlapping characters).

Loading…
Cancel
Save