/* * 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; } }