1 /* 2 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.font; 27 28 import java.awt.geom.AffineTransform; 29 import java.awt.geom.Point2D; 30 31 /* These are font metrics: they are in user space, not device space. 32 * Hence they are not truly "strike" metrics. However it is convenient to 33 * treat them as such since we need to have a scaler context to obtain them 34 * and also to cache them. The old implementation obtained a C++ strike object 35 * that matched the Font TX + pt size only. It was wasteful of strike objects. 36 * This new implementation still has separate StrikeMetrics for 2 fonts that 37 * are really the same but are used in different device transforms, but at 38 * least it doesn't create a whole new strike just to get the metrics for 39 * a strike in a transformed graphics. 40 * So these metrics do not take into account the device transform. They 41 * are considered inherent properties of the font. Hence it may be that we 42 * should use the device transform to obtain the most accurate metrics, but 43 * typically 1.1 APIs do not provide for this. So some APIs may want to 44 * ignore the dev. tx and others may want to use it, and then apply an 45 * inverse transform. For now we ignore the dev. tx. 46 * "Font" metrics are representative of a typical glyph in the font. 47 * Generally speaking these values are the choice of the font designer and 48 * are stored in the font, from which we retrieve the values. They do 49 * not necessarily equate to the maximum bounds of all glyphs in the font. 50 * Note that the ascent fields are typically a -ve value as we use a top-left 51 * origin user space, and text is positioned relative to its baseline. 52 */ 53 public final class StrikeMetrics { 54 55 public float ascentX; 56 public float ascentY; 57 public float descentX; 58 public float descentY; 59 public float baselineX; 60 public float baselineY; 61 public float leadingX; 62 public float leadingY; 63 public float maxAdvanceX; 64 public float maxAdvanceY; 65 66 67 /* The no-args constructor is used by CompositeStrike, which then 68 * merges in the metrics of physical fonts. 69 * The approach here is the same as earlier releases but it is flawed 70 * take for example the following which ignores leading for simplicity. 71 * Say we have a composite with an element asc=-9, dsc=2, and another with 72 * asc=-7, dsc=3. The merged font is (-9,3) for height of -(-9)+3=12. 73 * Suppose this same font has been derived with a 180% rotation 74 * Now its signs for ascent/descent are reversed. Its (9,-2) and (7,-3) 75 * Its merged values are (using the code in this class) (7,-2) for 76 * a height of -(7)+-2 = =-9! 77 * We need to have a more intelligent merging algorithm, 78 * which so far as I can see needs to apply an inverse of the font 79 * tx, do its merging, and then reapply the font tx. 80 * This wouldn't often be a problem as there rarely is a font TX, and 81 * the tricky part is getting the information. Probably the no-args 82 * constructor needs to pass a TX in to be applied to all merges. 83 * CompositeStrike would be left with the problem of figuring out what 84 * tx to use. 85 * But at least for now we are probably no worse than 1.4 ... 86 * REMIND: FIX THIS. 87 */ StrikeMetrics()88 StrikeMetrics() { 89 ascentX = ascentY = Integer.MAX_VALUE; 90 descentX = descentY = leadingX = leadingY = Integer.MIN_VALUE; 91 baselineX = baselineX = maxAdvanceX = maxAdvanceY = Integer.MIN_VALUE; 92 } 93 StrikeMetrics(float ax, float ay, float dx, float dy, float bx, float by, float lx, float ly, float mx, float my)94 StrikeMetrics(float ax, float ay, float dx, float dy, float bx, float by, 95 float lx, float ly, float mx, float my) { 96 ascentX = ax; 97 ascentY = ay; 98 descentX = dx; 99 descentY = dy; 100 baselineX = bx; 101 baselineY = by; 102 leadingX = lx; 103 leadingY = ly; 104 maxAdvanceX = mx; 105 maxAdvanceY = my; 106 } 107 getAscent()108 public float getAscent() { 109 return -ascentY; 110 } 111 getDescent()112 public float getDescent() { 113 return descentY; 114 } 115 getLeading()116 public float getLeading() { 117 return leadingY; 118 } 119 getMaxAdvance()120 public float getMaxAdvance() { 121 return maxAdvanceX; 122 } 123 124 /* 125 * Currently only used to merge together slot metrics to create 126 * the metrics for a composite font. 127 */ merge(StrikeMetrics other)128 void merge(StrikeMetrics other) { 129 if (other == null) { 130 return; 131 } 132 if (other.ascentX < ascentX) { 133 ascentX = other.ascentX; 134 } 135 if (other.ascentY < ascentY) { 136 ascentY = other.ascentY; 137 } 138 if (other.descentX > descentX) { 139 descentX = other.descentX; 140 } 141 if (other.descentY > descentY) { 142 descentY = other.descentY; 143 } 144 if (other.baselineX > baselineX) { 145 baselineX = other.baselineX; 146 } 147 if (other.baselineY > baselineY) { 148 baselineY = other.baselineY; 149 } 150 if (other.leadingX > leadingX) { 151 leadingX = other.leadingX; 152 } 153 if (other.leadingY > leadingY) { 154 leadingY = other.leadingY; 155 } 156 if (other.maxAdvanceX > maxAdvanceX) { 157 maxAdvanceX = other.maxAdvanceX; 158 } 159 if (other.maxAdvanceY > maxAdvanceY) { 160 maxAdvanceY = other.maxAdvanceY; 161 } 162 } 163 164 /* Used to transform the values back into user space. 165 * This is done ONCE by the strike so clients should not need 166 * to worry about this 167 */ convertToUserSpace(AffineTransform invTx)168 void convertToUserSpace(AffineTransform invTx) { 169 Point2D.Float pt2D = new Point2D.Float(); 170 171 pt2D.x = ascentX; pt2D.y = ascentY; 172 invTx.deltaTransform(pt2D, pt2D); 173 ascentX = pt2D.x; ascentY = pt2D.y; 174 175 pt2D.x = descentX; pt2D.y = descentY; 176 invTx.deltaTransform(pt2D, pt2D); 177 descentX = pt2D.x; descentY = pt2D.y; 178 179 pt2D.x = baselineX; pt2D.y = baselineY; 180 invTx.deltaTransform(pt2D, pt2D); 181 baselineX = pt2D.x; baselineY = pt2D.y; 182 183 pt2D.x = leadingX; pt2D.y = leadingY; 184 invTx.deltaTransform(pt2D, pt2D); 185 leadingX = pt2D.x; leadingY = pt2D.y; 186 187 pt2D.x = maxAdvanceX; pt2D.y = maxAdvanceY; 188 invTx.deltaTransform(pt2D, pt2D); 189 maxAdvanceX = pt2D.x; maxAdvanceY = pt2D.y; 190 } 191 toString()192 public String toString() { 193 return "ascent:x=" + ascentX + " y=" + ascentY + 194 " descent:x=" + descentX + " y=" + descentY + 195 " baseline:x=" + baselineX + " y=" + baselineY + 196 " leading:x=" + leadingX + " y=" + leadingY + 197 " maxAdvance:x=" + maxAdvanceX + " y=" + maxAdvanceY; 198 } 199 } 200