/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.font;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
/* These are font metrics: they are in user space, not device space.
* Hence they are not truly "strike" metrics. However it is convenient to
* treat them as such since we need to have a scaler context to obtain them
* and also to cache them. The old implementation obtained a C++ strike object
* that matched the Font TX + pt size only. It was wasteful of strike objects.
* This new implementation still has separate StrikeMetrics for 2 fonts that
* are really the same but are used in different device transforms, but at
* least it doesn't create a whole new strike just to get the metrics for
* a strike in a transformed graphics.
* So these metrics do not take into account the device transform. They
* are considered inherent properties of the font. Hence it may be that we
* should use the device transform to obtain the most accurate metrics, but
* typically 1.1 APIs do not provide for this. So some APIs may want to
* ignore the dev. tx and others may want to use it, and then apply an
* inverse transform. For now we ignore the dev. tx.
* "Font" metrics are representative of a typical glyph in the font.
* Generally speaking these values are the choice of the font designer and
* are stored in the font, from which we retrieve the values. They do
* not necessarily equate to the maximum bounds of all glyphs in the font.
* Note that the ascent fields are typically a -ve value as we use a top-left
* origin user space, and text is positioned relative to its baseline.
*/
public final class StrikeMetrics {
public float ascentX;
public float ascentY;
public float descentX;
public float descentY;
public float baselineX;
public float baselineY;
public float leadingX;
public float leadingY;
public float maxAdvanceX;
public float maxAdvanceY;
/* The no-args constructor is used by CompositeStrike, which then
* merges in the metrics of physical fonts.
* The approach here is the same as earlier releases but it is flawed
* take for example the following which ignores leading for simplicity.
* Say we have a composite with an element asc=-9, dsc=2, and another with
* asc=-7, dsc=3. The merged font is (-9,3) for height of -(-9)+3=12.
* Suppose this same font has been derived with a 180% rotation
* Now its signs for ascent/descent are reversed. Its (9,-2) and (7,-3)
* Its merged values are (using the code in this class) (7,-2) for
* a height of -(7)+-2 = =-9!
* We need to have a more intelligent merging algorithm,
* which so far as I can see needs to apply an inverse of the font
* tx, do its merging, and then reapply the font tx.
* This wouldn't often be a problem as there rarely is a font TX, and
* the tricky part is getting the information. Probably the no-args
* constructor needs to pass a TX in to be applied to all merges.
* CompositeStrike would be left with the problem of figuring out what
* tx to use.
* But at least for now we are probably no worse than 1.4 ...
* REMIND: FIX THIS.
*/
StrikeMetrics() {
ascentX = ascentY = Integer.MAX_VALUE;
descentX = descentY = leadingX = leadingY = Integer.MIN_VALUE;
baselineX = baselineX = maxAdvanceX = maxAdvanceY = Integer.MIN_VALUE;
}
StrikeMetrics(float ax, float ay, float dx, float dy, float bx, float by,
float lx, float ly, float mx, float my) {
ascentX = ax;
ascentY = ay;
descentX = dx;
descentY = dy;
baselineX = bx;
baselineY = by;
leadingX = lx;
leadingY = ly;
maxAdvanceX = mx;
maxAdvanceY = my;
}
public float getAscent() {
return -ascentY;
}
public float getDescent() {
return descentY;
}
public float getLeading() {
return leadingY;
}
public float getMaxAdvance() {
return maxAdvanceX;
}
/*
* Currently only used to merge together slot metrics to create
* the metrics for a composite font.
*/
void merge(StrikeMetrics other) {
if (other == null) {
return;
}
if (other.ascentX < ascentX) {
ascentX = other.ascentX;
}
if (other.ascentY < ascentY) {
ascentY = other.ascentY;
}
if (other.descentX > descentX) {
descentX = other.descentX;
}
if (other.descentY > descentY) {
descentY = other.descentY;
}
if (other.baselineX > baselineX) {
baselineX = other.baselineX;
}
if (other.baselineY > baselineY) {
baselineY = other.baselineY;
}
if (other.leadingX > leadingX) {
leadingX = other.leadingX;
}
if (other.leadingY > leadingY) {
leadingY = other.leadingY;
}
if (other.maxAdvanceX > maxAdvanceX) {
maxAdvanceX = other.maxAdvanceX;
}
if (other.maxAdvanceY > maxAdvanceY) {
maxAdvanceY = other.maxAdvanceY;
}
}
/* Used to transform the values back into user space.
* This is done ONCE by the strike so clients should not need
* to worry about this
*/
void convertToUserSpace(AffineTransform invTx) {
Point2D.Float pt2D = new Point2D.Float();
pt2D.x = ascentX; pt2D.y = ascentY;
invTx.deltaTransform(pt2D, pt2D);
ascentX = pt2D.x; ascentY = pt2D.y;
pt2D.x = descentX; pt2D.y = descentY;
invTx.deltaTransform(pt2D, pt2D);
descentX = pt2D.x; descentY = pt2D.y;
pt2D.x = baselineX; pt2D.y = baselineY;
invTx.deltaTransform(pt2D, pt2D);
baselineX = pt2D.x; baselineY = pt2D.y;
pt2D.x = leadingX; pt2D.y = leadingY;
invTx.deltaTransform(pt2D, pt2D);
leadingX = pt2D.x; leadingY = pt2D.y;
pt2D.x = maxAdvanceX; pt2D.y = maxAdvanceY;
invTx.deltaTransform(pt2D, pt2D);
maxAdvanceX = pt2D.x; maxAdvanceY = pt2D.y;
}
public String toString() {
return "ascent:x=" + ascentX + " y=" + ascentY +
" descent:x=" + descentX + " y=" + descentY +
" baseline:x=" + baselineX + " y=" + baselineY +
" leading:x=" + leadingX + " y=" + leadingY +
" maxAdvance:x=" + maxAdvanceX + " y=" + maxAdvanceY;
}
}