Skip to content

Commit

Permalink
GH-182 text selection bounds improvements (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
pcorless authored Apr 27, 2021
1 parent 9020fda commit 880560c
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ enum ByteEncoding {

long LAYOUT_NONE = 0;

// todo do some refacotring of method name 'e' awlays seemed strange to me.

Point2D getAdvance(char ech);

FontFile deriveFont(AffineTransform at);
Expand All @@ -54,12 +52,12 @@ FontFile deriveFont(float[] widths, int firstCh, float missingWidth,
FontFile deriveFont(Map<Integer, Float> widths, int firstCh, float missingWidth,
float ascent, float descent, Rectangle2D bbox, char[] diff);

FontFile deriveFont(float pointSize);

boolean canDisplay(char ech);

void setIsCid();

FontFile deriveFont(float pointsize);

CMap getToUnicode();

String toUnicode(String displayText);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ protected void parseWidth() {
// currently not using afm, instead using font's width table, seems more reliable
else if (afm != null && !isFontSubstitution) {
font = font.deriveFont(afm.getWidths(), firstchar, missingWidth, ascent, descent, bbox, null);
} else if (bbox != null) {
font = font.deriveFont(new float[0], firstchar, missingWidth, ascent, descent, bbox, null);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,12 @@ public FontFile deriveFont(float[] widths, int firstCh, float missingWidth, floa
font.firstCh = firstCh;
font.ascent = ascent;
font.descent = descent;
font.widths = widths;
if (widths != null && widths.length > 0) {
font.widths = widths;
}
font.cMap = diff;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand All @@ -198,6 +201,7 @@ public FontFile deriveFont(Map<Integer, Float> widths, int firstCh, float missin
font.descent = descent;
font.cMap = diff;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,12 @@ public FontFile deriveFont(float[] widths, int firstCh, float missingWidth, floa
font.firstCh = firstCh;
font.ascent = ascent;
font.descent = descent;
font.widths = widths;
if (widths != null && widths.length > 0) {
font.widths = widths;
}
font.cMap = diff != null ? diff : font.cMap;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand All @@ -181,6 +184,7 @@ public FontFile deriveFont(Map<Integer, Float> widths, int firstCh, float missin
font.descent = descent;
font.cMap = diff;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ public FontFile deriveFont(float[] widths, int firstCh, float missingWidth, floa
font.firstCh = firstCh;
font.ascent = ascent;
font.descent = descent;
font.widths = widths;
if (widths != null && widths.length > 0) {
font.widths = widths;
}
font.cMap = diff != null ? diff : font.cMap;
font.bbox = bbox;
return font;
Expand All @@ -126,6 +128,7 @@ public FontFile deriveFont(Map<Integer, Float> widths, int firstCh, float missin
font.descent = descent;
font.cMap = diff;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ public Point2D getAdvance(char ech) {

@Override
protected String codeToName(String estr) {
// might be able to blow this out out some point, but we're in the weeds at this point, not
// a lot of good examples.
// This isn't quite right yet. But if we are using the standard encoding as set in the TypeFont class
// use the font's internal encoding.
if (org.icepdf.core.pobjects.fonts.zfont.Encoding.STANDARD_ENCODING_NAME.equals(encoding.getName())) {
return cffType1Font.getEncoding().getName(estr.charAt(0));
} else {
Expand Down Expand Up @@ -95,9 +95,12 @@ public FontFile deriveFont(float[] widths, int firstCh, float missingWidth, floa
font.firstCh = firstCh;
font.ascent = ascent;
font.descent = descent;
font.widths = widths;
if (widths != null && widths.length > 0) {
font.widths = widths;
}
font.cMap = diff != null ? diff : font.cMap;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand All @@ -110,6 +113,7 @@ public FontFile deriveFont(Map<Integer, Float> widths, int firstCh, float missin
font.descent = descent;
font.cMap = diff;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ public FontFile deriveFont(float[] widths, int firstCh, float missingWidth, floa
font.descent = descent;
font.cMap = diff;
font.bbox = bbox;
if (widths != null && widths.length > 0) {
font.widths = widths;
}
font.maxCharBounds = null;
return font;
}

Expand All @@ -164,6 +168,7 @@ public FontFile deriveFont(Map<Integer, Float> widths, int firstCh, float missin
font.descent = descent;
font.cMap = diff;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,15 @@ public FontFile deriveFont(Encoding encoding, CMap toUnicode) {
public FontFile deriveFont(float[] widths, int firstCh, float missingWidth, float ascent, float descent, Rectangle2D bbox, char[] diff) {
ZFontType3 font = (ZFontType3) deriveFont(this.size);
font.encoding = encoding;
font.widths = widths;
if (widths != null && widths.length > 0) {
font.widths = widths;
}
font.firstCh = firstCh;
font.missingWidth = missingWidth;
font.ascent = ascent;
font.descent = descent;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand All @@ -123,6 +126,7 @@ public FontFile deriveFont(Map<Integer, Float> widths, int firstCh, float missin
font.ascent = ascent;
font.descent = descent;
font.bbox = bbox;
font.maxCharBounds = null;
return font;
}

Expand Down Expand Up @@ -221,27 +225,6 @@ public Rectangle2D getMaxCharBounds() {
return af.createTransformedShape(bBox.toJava2dCoordinates()).getBounds2D();
}

public Rectangle2D getCharBounds(char displayChar) {
Rectangle2D r = getMaxCharBounds();

String charName = encoding.getName(displayChar);
float width = 0f;
if (widths != null && displayChar - firstCh >= 0 && displayChar - firstCh < widths.length) {
width = widths[displayChar - firstCh];

}

if (width == 0.0f) {
width = charWidths.get(charName).x;
}

PRectangle charRect = charBBoxes.get(charName);
r.setRect(0.0, r.getY(),
width * size,
charRect.getHeight() * size);
return r;
}

/**
* <p>Sets the horizontal displacement of this Type3 font for the specified
* name. Like BBox this value must be set from inside the content parser as
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public abstract class ZSimpleFont implements FontFile {
protected float ascent;
protected float descent;
protected Rectangle2D bbox = new Rectangle2D.Double(0.0, 0.0, 1.0, 1.0);
protected Rectangle2D maxCharBounds;

// cid specific, todo new subclass if we get a few more?
protected float defaultWidth;
Expand Down Expand Up @@ -186,7 +187,10 @@ public Shape getOutline(String estr, float x, float y) {

@Override
public Rectangle2D getMaxCharBounds() {
return calculateBbox(bbox);
AffineTransform af = new AffineTransform();
af.scale(size, -size);
af.concatenate(fontMatrix);
return af.createTransformedShape(bbox).getBounds2D();
}

@Override
Expand Down Expand Up @@ -225,12 +229,34 @@ public float getSize() {

@Override
public double getAscent() {
return ascent;
if (ascent != 0) {
return ascent * size;
} else {
if (maxCharBounds == null) {
maxCharBounds = getMaxCharBounds();
}
return maxCharBounds.getY();
}

}

public double getHeight() {
if (maxCharBounds == null) {
maxCharBounds = getMaxCharBounds();
}
return maxCharBounds.getHeight();
}


@Override
public double getDescent() {
return descent;
if (descent != 0) {
return descent * size;
} else {
double height = getHeight();
double ascent = getAscent();
return height - ascent;
}
}

@Override
Expand Down Expand Up @@ -309,6 +335,7 @@ protected void setPointSize(float pointSize) {
fontTransform.concatenate(gsTransform);
fontTransform.scale(pointSize, -pointSize);
size = pointSize;
maxCharBounds = null;
}

protected char getCharDiff(char character) {
Expand All @@ -319,16 +346,6 @@ protected char getCharDiff(char character) {
}
}

protected Rectangle2D calculateBbox(Rectangle2D bbox) {
if (bbox != null) {
AffineTransform af = new AffineTransform();
// af.scale(size, size);
af.concatenate(fontMatrix);
return af.createTransformedShape(bbox).getBounds2D();
}
return this.bbox;
}

protected AffineTransform convertFontMatrix(FontBoxFont fontBoxFont) {
try {
java.util.List<Number> matrix = fontBoxFont.getFontMatrix();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,38 +102,42 @@ public TextSprite(FontFile font, int contentLength, AffineTransform graphicState
* @return new GlyphText object containing the text data.
*/
public GlyphText addText(String cid, String unicode, float x, float y, float width) {

// x,y must not chance as it will affect painting of the glyph,
// x,y must not change as it will affect painting of the glyph,
// we can change the bounds of glyphBounds as this is what needs to be normalized
// to page space
// IMPORTANT: where working in Java Coordinates with any of the Font bounds
float descent = (float) font.getDescent();
float ascent = (float) font.getAscent();
float w = width;
float h = ascent - descent;
// width/height are kept unscaled for coords, w/h are scaled to get correct bounds w/h
float height = h;
h = Math.abs(h);

// zero height will not intersect with clip rectangle and maybe have visibility issues.
// we generally get here if the font.getAscent is zero and as a result must compensate.
if (h <= 0.0f) {
if (h == 0.0f) {
Rectangle2D bounds = font.getBounds(cid, 0, 1);
if (bounds != null && bounds.getHeight() > 0) {
h = (float) bounds.getHeight();
} else {
// match the width, as it will make text selection work a bit better.
h = font.getSize();
}
height = h;
}
// can't have Rectangle2D with negative w or h, api will zero the bounds.
w = Math.abs(w);
// this is still terrible, should be applying the fontTransform but this little hack is fast until I can
// figure out the geometry for the corner cases.
h *= Math.abs(font.getSize());
Rectangle2D.Float glyphBounds;
// negative layout
if (w < 0.0f || font.getSize() < 0) {
glyphBounds = new Rectangle2D.Float(x + width, y - ascent, w, h);
if (width < 0.0f || font.getSize() < 0) {
glyphBounds = new Rectangle2D.Float(x + width, y - descent, w, h);
}
// inverted layout
else if (font.getFontTransform() != null && font.getFontTransform().getScaleY() < 0) {
glyphBounds = new Rectangle2D.Float(x, y - h - descent, w, h);
glyphBounds = new Rectangle2D.Float(x, y - height, w, h);
}
// standard layout.
else {
Expand Down

0 comments on commit 880560c

Please sign in to comment.