From 6f814eed298d682410956a801a9d3e175326b8c3 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Fri, 15 Dec 2006 00:59:45 +0000 Subject: 2006-12-14 Roman Kennke * gnu/java/awt/font/autofit/HintScaler.java Renamed Scaler to HintScaler to avoid name-clash. * gnu/java/awt/font/autofit/AutoHinter.java (scaler): New field. (applyHints): Scale the metrics before applying the hints. (init): Copy font into scaler. * gnu/java/awt/font/autofit/Edge.java (blueEdge): New field. (toString): Include first and last fields in debug output. * gnu/java/awt/font/autofit/GlyphHints.java (reload): Grab the scales here. * gnu/java/awt/font/autofit/Latin.java (computeBlueEdges): Implemented blue-edge detection. (computeEdges): Correctly calculate edgeDistanceThreshold and the scaled edge position. (initWidths): Renamed Scaler to HintScaler. Sort widths and store widthCount. (scaleMetrics): Add HintScaler parameter. Implemented to scale the metrics. (scaleMetricsDim): New helper method. * gnu/java/awt/font/autofit/LatinAxis.java (orgDelta): New field. (orgScale): New field. * gnu/java/awt/font/autofit/LatinBlue.java: Reordered flags. (FLAG_BLUE_ACTIVE): New flag. * gnu/java/awt/font/autofit/Scaler.java: Renamed to HintScaler. * gnu/java/awt/font/autofit/Script.java (scaleMetrics): Add HintScaler argument. * gnu/java/awt/font/autofit/ScriptMetrics.java Renamed Scaler to HintScaler. * gnu/java/awt/font/autofit/Utils.java (sort(int,Width[])): New helper method. Sorts Width arrays. (mulDiv): New helper method. (pixFloor): New helper method. (pixRound): New helper method. * gnu/java/awt/font/autofit/Width.java (toString): New method. For debug output. * gnu/java/awt/font/opentype/truetype/Fixed.java (mul16): New method. Multiplies with 16.16 fixed point arithmetics. (div16): New method. Divides with 16.16 fixed point arithmetics. (valueOf16): New method. Converts double to 16.16 fixed point. * gnu/java/awt/font/opentype/truetype/Zone.java (scaleX): New field. (scaleY): New field. (shearX): New field. (shearY): New field. (transform): Store translation and shearing in fields instead of local vars. --- gnu/java/awt/font/autofit/AutoHinter.java | 7 + gnu/java/awt/font/autofit/Edge.java | 5 + gnu/java/awt/font/autofit/GlyphHints.java | 5 + gnu/java/awt/font/autofit/HintScaler.java | 53 +++++++ gnu/java/awt/font/autofit/Latin.java | 203 ++++++++++++++++++++++++- gnu/java/awt/font/autofit/LatinAxis.java | 2 + gnu/java/awt/font/autofit/LatinBlue.java | 5 +- gnu/java/awt/font/autofit/Scaler.java | 52 ------- gnu/java/awt/font/autofit/Script.java | 2 +- gnu/java/awt/font/autofit/ScriptMetrics.java | 4 +- gnu/java/awt/font/autofit/Utils.java | 34 +++++ gnu/java/awt/font/autofit/Width.java | 8 + gnu/java/awt/font/opentype/truetype/Fixed.java | 13 +- gnu/java/awt/font/opentype/truetype/Zone.java | 3 +- 14 files changed, 329 insertions(+), 67 deletions(-) create mode 100644 gnu/java/awt/font/autofit/HintScaler.java delete mode 100644 gnu/java/awt/font/autofit/Scaler.java (limited to 'gnu/java/awt') diff --git a/gnu/java/awt/font/autofit/AutoHinter.java b/gnu/java/awt/font/autofit/AutoHinter.java index 6f948e0cb..b61eaa182 100644 --- a/gnu/java/awt/font/autofit/AutoHinter.java +++ b/gnu/java/awt/font/autofit/AutoHinter.java @@ -40,6 +40,7 @@ package gnu.java.awt.font.autofit; import gnu.java.awt.font.opentype.Hinter; import gnu.java.awt.font.opentype.OpenTypeFont; +import gnu.java.awt.font.opentype.truetype.Fixed; import gnu.java.awt.font.opentype.truetype.Zone; /** @@ -52,18 +53,24 @@ public class AutoHinter LatinMetrics metrics; GlyphHints hints; + HintScaler scaler = new HintScaler(); public void init(OpenTypeFont font) { // TODO: Should support other scripts too. latinScript = new Latin(); metrics = new LatinMetrics(font); latinScript.initMetrics(metrics, font); + scaler.face = font; } public void applyHints(Zone outline) { if (hints == null) hints = new GlyphHints(); + scaler.xScale = Fixed.valueOf16(outline.scaleX * 64); + scaler.yScale = Fixed.valueOf16(outline.scaleY * 64); + latinScript.scaleMetrics(metrics, scaler); latinScript.applyHints(hints, outline, metrics); } + } diff --git a/gnu/java/awt/font/autofit/Edge.java b/gnu/java/awt/font/autofit/Edge.java index b71b2247c..8a19e55a4 100644 --- a/gnu/java/awt/font/autofit/Edge.java +++ b/gnu/java/awt/font/autofit/Edge.java @@ -48,6 +48,7 @@ class Edge Edge serif; int flags; int dir; + Width blueEdge; public String toString() { @@ -65,6 +66,10 @@ class Edge s.append(", link: "); s.append(link != null ? link.hashCode() : "null"); s.append(", flags: " + flags); + s.append(", first: "); + s.append(first.hashCode()); + s.append(", last: "); + s.append(last.hashCode()); return s.toString(); } } diff --git a/gnu/java/awt/font/autofit/GlyphHints.java b/gnu/java/awt/font/autofit/GlyphHints.java index 8b20ea320..3f8229511 100644 --- a/gnu/java/awt/font/autofit/GlyphHints.java +++ b/gnu/java/awt/font/autofit/GlyphHints.java @@ -129,6 +129,11 @@ class GlyphHints // TODO: Freetype seems to scale and translate the glyph at that point. // I suppose that this is not really needed. + // The scales are scaling from font units to 1/64 device pixels. + xScale = Fixed.valueOf16(outline.scaleX * 64); + yScale = Fixed.valueOf16(outline.scaleY * 64); + + // FIXME: What is that xDelta and yDelta used for? System.arraycopy(outline.getPoints(), 0, points, 0, numPoints); // Setup prev and next and contours array. diff --git a/gnu/java/awt/font/autofit/HintScaler.java b/gnu/java/awt/font/autofit/HintScaler.java new file mode 100644 index 000000000..01276b4db --- /dev/null +++ b/gnu/java/awt/font/autofit/HintScaler.java @@ -0,0 +1,53 @@ +/* Scaler.java -- FIXME: briefly describe file purpose + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font.autofit; + +import gnu.java.awt.font.opentype.OpenTypeFont; + +class HintScaler +{ + + int xScale; + int xDelta; + int yScale; + int yDelta; + OpenTypeFont face; + int renderMode; + +} diff --git a/gnu/java/awt/font/autofit/Latin.java b/gnu/java/awt/font/autofit/Latin.java index 4587d987e..d836b99b3 100644 --- a/gnu/java/awt/font/autofit/Latin.java +++ b/gnu/java/awt/font/autofit/Latin.java @@ -172,10 +172,119 @@ class Latin initBlues(lm, face); } - public void scaleMetrics(ScriptMetrics metrics) + public void scaleMetrics(ScriptMetrics metrics, HintScaler scaler) { - // TODO Auto-generated method stub + LatinMetrics lm = (LatinMetrics) metrics; + lm.scaler.renderMode = scaler.renderMode; + lm.scaler.face = scaler.face; + scaleMetricsDim(lm, scaler, DIMENSION_HORZ); + scaleMetricsDim(lm, scaler, DIMENSION_VERT); + } + private void scaleMetricsDim(LatinMetrics lm, HintScaler scaler, int dim) + { + int scale; + int delta; + if (dim == DIMENSION_HORZ) + { + scale = scaler.xScale; + delta = scaler.xDelta; + } + else + { + scale = scaler.yScale; + delta = scaler.yDelta; + } + LatinAxis axis = lm.axis[dim]; + if (axis.orgScale == scale && axis.orgDelta == delta) + // No change, no need to adjust. + return; + axis.orgScale = scale; + axis.orgDelta = delta; + + // Correct X and Y scale to optimize the alignment of the top small + // letters to the pixel grid. + LatinAxis axis2 = lm.axis[DIMENSION_VERT]; + LatinBlue blue = null; + for (int nn = 0; nn < axis2.blueCount; nn++) + { + if ((axis2.blues[nn].flags & LatinBlue.FLAG_ADJUSTMENT) != 0) + { + blue = axis2.blues[nn]; + break; + } + } + if (blue != null) + { + int scaled = Fixed.mul16(blue.shoot.org, scaler.yScale); + int fitted = Utils.pixRound(scaled); + if (scaled != fitted) + { + if (dim == DIMENSION_HORZ) + { + if (fitted < scaled) + { + scale -= scale / 50; + } + } + else + { + scale = Utils.mulDiv(scale, fitted, scaled); + } + } + } + axis.scale = scale; + axis.delta = delta; + if (dim == DIMENSION_HORZ) + { + lm.scaler.xScale = scale; + lm.scaler.xDelta = delta; + } + else + { + lm.scaler.yScale = scale; + lm.scaler.yDelta = delta; + } + // Scale the standard widths. + for (int nn = 0; nn < axis.widthCount; nn++) + { + Width w = axis.widths[nn]; + w.cur = Fixed.mul16(w.org, scale); + w.fit = w.cur; + } + // Scale blue zones. + if (dim == DIMENSION_VERT) + { + for (int nn = 0; nn < axis.blueCount; nn++) + { + blue = axis.blues[nn]; + blue.ref.cur = Fixed.mul16(blue.ref.org, scale) + delta; + blue.ref.fit = blue.ref.cur; + blue.shoot.cur = Fixed.mul16(blue.ref.org, scale) + delta; + blue.flags &= ~LatinBlue.FLAG_BLUE_ACTIVE; + // A blue zone is only active if it is less than 3/4 pixels tall. + int dist = Fixed.mul16(blue.ref.org - blue.shoot.org, scale); + if (dist <= 48 && dist >= -48) + { + int delta1 = blue.shoot.org - blue.ref.org; + int delta2 = delta1; + if (delta1 < 0) + delta2 = -delta2; + delta2 = Fixed.mul16(delta2, scale); + if (delta2 < 32) + delta2 = 0; + else if (delta2 < 64) + delta2 = 32 + (((delta2 - 32) + 16) & ~31); + else + delta2 = Utils.pixRound(delta2); + if (delta1 < 0) + delta2 = -delta2; + blue.ref.fit = Utils.pixRound(blue.ref.cur); + blue.shoot.fit = blue.ref.fit+ delta2; + blue.flags |= LatinBlue.FLAG_BLUE_ACTIVE; + } + } + } } /** @@ -196,7 +305,7 @@ class Latin // Consider this when the thing is done and we know what we need that for. Zone outline = face.getRawGlyphOutline(glyphIndex, IDENTITY); LatinMetrics dummy = new LatinMetrics(); - Scaler scaler = dummy.scaler; + HintScaler scaler = dummy.scaler; dummy.unitsPerEm = metrics.unitsPerEm; scaler.xScale = scaler.yScale = 10000; scaler.xDelta = scaler.yDelta = 0; @@ -224,6 +333,8 @@ class Latin } touched.add(seg); } + Utils.sort(numWidths, axis.widths); + axis.widthCount = numWidths; } for (int dim = 0; dim < DIMENSION_MAX; dim++) { @@ -638,11 +749,10 @@ class Latin // Note that the edge table is sorted along the segment/edge // position. - edgeDistanceThreshold = Fixed.mul(laxis.edgeDistanceTreshold, scale); + edgeDistanceThreshold = Fixed.mul16(laxis.edgeDistanceTreshold, scale); if (edgeDistanceThreshold > 64 / 4) edgeDistanceThreshold = 64 / 4; - edgeDistanceThreshold = Fixed.div(edgeDistanceThreshold, scale); - + edgeDistanceThreshold = Fixed.div16(edgeDistanceThreshold, scale); for (int i = 0; i < numSegments; i++) { seg = segments[i]; @@ -667,7 +777,7 @@ class Latin edge.first = seg; edge.last = seg; edge.fpos = seg.pos; - edge.opos = Fixed.mul(seg.pos, scale); + edge.opos = Fixed.mul16(seg.pos, scale); seg.edgeNext = seg; seg.edge = edge; } @@ -780,6 +890,83 @@ class Latin private void computeBlueEdges(GlyphHints hints, LatinMetrics metrics) { - // TODO: Implement. + AxisHints axis = hints.axis[DIMENSION_VERT]; + Edge[] edges = axis.edges; + int numEdges = axis.numEdges; + LatinAxis latin = metrics.axis[DIMENSION_VERT]; + int scale = latin.scale; + + // Compute which blue zones are active. I.e. have their scaled + // size < 3/4 pixels. + + // For each horizontal edge search the blue zone that is closest. + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + // System.err.println("checking edge: " + edge); + Width bestBlue = null; + int bestDist = Fixed.mul16(metrics.unitsPerEm / 40, scale); + + if (bestDist > 64 / 2) + bestDist = 64 / 2; + for (int bb = 0; bb < BLUE_MAX; bb++) + { + LatinBlue blue = latin.blues[bb]; + // System.err.println("checking blue: " + blue); + // Skip inactive blue zones, i.e. those that are too small. + if ((blue.flags & LatinBlue.FLAG_BLUE_ACTIVE) == 0) + continue; + // If it is a top zone, check for right edges. If it is a bottom + // zone, check for left edges. + boolean isTopBlue = (blue.flags & LatinBlue.FLAG_TOP) != 0; + boolean isMajorDir = edge.dir == axis.majorDir; + + // If it is a top zone, the edge must be against the major + // direction. If it is a bottom zone it must be in the major + // direction. + if (isTopBlue ^ isMajorDir) + { + int dist = edge.fpos - blue.ref.org; + if (dist < 0) + dist = -dist; + dist = Fixed.mul16(dist, scale); + if (dist < bestDist) + { + bestDist = dist; + bestBlue = blue.ref; + } + + // Now, compare it to the overshoot position if the edge is + // rounded, and if the edge is over the reference position of + // a top zone, or under the reference position of a bottom + // zone. + if ((edge.flags & Segment.FLAG_EDGE_ROUND) != 0 && dist != 0) + { + // Inversed vertical coordinates! + boolean isUnderRef = edge.fpos > blue.ref.org; + if (isTopBlue ^ isUnderRef) + { + blue = latin.blues[bb]; // Needed? + dist = edge.fpos - blue.shoot.org; + if (dist < 0) + dist = -dist; + dist = Fixed.mul16(dist, scale); + if (dist < bestDist) + { + bestDist = dist; + bestBlue = blue.shoot; + } + } + } + + } + } + if (bestBlue != null) + { + edge.blueEdge = bestBlue; + // Debug: Print out the blue edges. + // System.err.println("blue edge for: " + edge + ": " + bestBlue); + } + } } } diff --git a/gnu/java/awt/font/autofit/LatinAxis.java b/gnu/java/awt/font/autofit/LatinAxis.java index a720cd93c..9237d0ee5 100644 --- a/gnu/java/awt/font/autofit/LatinAxis.java +++ b/gnu/java/awt/font/autofit/LatinAxis.java @@ -52,6 +52,8 @@ class LatinAxis int edgeDistanceTreshold; LatinBlue[] blues; int blueCount; + int orgDelta; + int orgScale; LatinAxis() { widths = new Width[Latin.MAX_WIDTHS]; diff --git a/gnu/java/awt/font/autofit/LatinBlue.java b/gnu/java/awt/font/autofit/LatinBlue.java index 57143b065..694fb24fe 100644 --- a/gnu/java/awt/font/autofit/LatinBlue.java +++ b/gnu/java/awt/font/autofit/LatinBlue.java @@ -40,8 +40,9 @@ package gnu.java.awt.font.autofit; public class LatinBlue { - static final int FLAG_TOP = 1; - static final int FLAG_ADJUSTMENT = 1; + static final int FLAG_BLUE_ACTIVE = 1 << 0; + static final int FLAG_TOP = 1 << 1; + static final int FLAG_ADJUSTMENT = 1 << 2; Width ref; Width shoot; int flags; diff --git a/gnu/java/awt/font/autofit/Scaler.java b/gnu/java/awt/font/autofit/Scaler.java deleted file mode 100644 index 105185125..000000000 --- a/gnu/java/awt/font/autofit/Scaler.java +++ /dev/null @@ -1,52 +0,0 @@ -/* Scaler.java -- FIXME: briefly describe file purpose - Copyright (C) 2006 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - - -package gnu.java.awt.font.autofit; - -import gnu.java.awt.font.opentype.OpenTypeFont; - -class Scaler -{ - - int xScale; - int xDelta; - int yScale; - int yDelta; - OpenTypeFont face; - -} diff --git a/gnu/java/awt/font/autofit/Script.java b/gnu/java/awt/font/autofit/Script.java index d394ff2e6..c223f0a26 100644 --- a/gnu/java/awt/font/autofit/Script.java +++ b/gnu/java/awt/font/autofit/Script.java @@ -52,7 +52,7 @@ interface Script */ void initMetrics(ScriptMetrics metrics, OpenTypeFont face); - void scaleMetrics(ScriptMetrics metrics/* , scaler, map this */); + void scaleMetrics(ScriptMetrics metrics , HintScaler scaler); void doneMetrics(ScriptMetrics metrics); diff --git a/gnu/java/awt/font/autofit/ScriptMetrics.java b/gnu/java/awt/font/autofit/ScriptMetrics.java index 6ec5d33f5..984a06dae 100644 --- a/gnu/java/awt/font/autofit/ScriptMetrics.java +++ b/gnu/java/awt/font/autofit/ScriptMetrics.java @@ -45,9 +45,9 @@ class ScriptMetrics { Script script; - Scaler scaler; + HintScaler scaler; ScriptMetrics() { - scaler = new Scaler(); + scaler = new HintScaler(); } } diff --git a/gnu/java/awt/font/autofit/Utils.java b/gnu/java/awt/font/autofit/Utils.java index bf093ba92..1b68ea791 100644 --- a/gnu/java/awt/font/autofit/Utils.java +++ b/gnu/java/awt/font/autofit/Utils.java @@ -212,4 +212,38 @@ class Utils } } } + + static void sort(int num, Width[] array) + { + Width swap; + for (int i = 1; i < num; i++) + { + for (int j = 1; j > 0; j--) + { + if (array[j].org > array[j - 1].org) + break; + swap = array[j]; + array[j] = array[j - 1]; + array[j - 1] = swap; + } + } + } + + static int pixRound(int val) + { + return pixFloor(val + 32); + } + + static int pixFloor(int val) + { + return val & ~63; + } + + public static int mulDiv(int a, int b, int c) + { + long prod = a * b; + long div = (prod / c); + return (int) div; + } + } diff --git a/gnu/java/awt/font/autofit/Width.java b/gnu/java/awt/font/autofit/Width.java index 0a2f0602b..15a344b63 100644 --- a/gnu/java/awt/font/autofit/Width.java +++ b/gnu/java/awt/font/autofit/Width.java @@ -47,4 +47,12 @@ public class Width { org = dist; } + + public String toString() + { + StringBuilder s = new StringBuilder(); + s.append("[Width] org: "); + s.append(org); + return s.toString(); + } } diff --git a/gnu/java/awt/font/opentype/truetype/Fixed.java b/gnu/java/awt/font/opentype/truetype/Fixed.java index 03a8a87cf..4e1ba441e 100644 --- a/gnu/java/awt/font/opentype/truetype/Fixed.java +++ b/gnu/java/awt/font/opentype/truetype/Fixed.java @@ -69,14 +69,21 @@ public final class Fixed return (int) ((((long) a) * b) >> 6); } + public static int mul16(int a, int b) + { + return (int) ((((long) a) * b) >> 16); + } public static int div(int a, int b) { return (int) ((((long) a) << 6) / b); } + public static int div16(int a, int b) + { + return (int) ((((long) a) << 16) / b); + } - public static int ceil(int a) { return (a + 63) & -64; @@ -138,6 +145,10 @@ public final class Fixed return (int) (d * 64); } + public static int valueOf16(double d) + { + return (int) (d * (1 << 16)); + } /** * Makes a string representation of a fixed-point number. diff --git a/gnu/java/awt/font/opentype/truetype/Zone.java b/gnu/java/awt/font/opentype/truetype/Zone.java index 8ce9a0c4f..63b1aa626 100644 --- a/gnu/java/awt/font/opentype/truetype/Zone.java +++ b/gnu/java/awt/font/opentype/truetype/Zone.java @@ -50,6 +50,8 @@ public final class Zone private Point[] points; private int numPoints; + public double scaleX, scaleY, shearX, shearY; + public Zone(int maxNumPoints) { points = new Point[maxNumPoints]; @@ -160,7 +162,6 @@ public final class Zone void transform(double pointSize, AffineTransform deviceTransform, int unitsPerEm, int preTranslateX, int preTranslateY) { - double scaleX, scaleY, shearX, shearY; double factor; factor = pointSize / (double) unitsPerEm; -- cgit v1.2.1