1 /* 2 * Copyright (c) 2003, 2005, 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.Font; 29 import java.awt.Rectangle; 30 import java.awt.geom.GeneralPath; 31 import java.awt.geom.Point2D; 32 import java.awt.geom.Rectangle2D; 33 34 /* 35 * performance: 36 * it seems expensive that when using a composite font for 37 * every char you have to find which "slot" can display it. 38 * Just the fact that you need to check at all .. 39 * A composite glyph code ducks this by encoding the slot into the 40 * glyph code, but you still need to get from char to glyph code. 41 */ 42 public final class CompositeStrike extends FontStrike { 43 44 static final int SLOTMASK = 0xffffff; 45 46 private CompositeFont compFont; 47 private PhysicalStrike[] strikes; 48 int numGlyphs = 0; 49 CompositeStrike(CompositeFont font2D, FontStrikeDesc desc)50 CompositeStrike(CompositeFont font2D, FontStrikeDesc desc) { 51 this.compFont = font2D; 52 this.desc = desc; 53 this.disposer = new FontStrikeDisposer(compFont, desc); 54 if (desc.style != compFont.style) { 55 algoStyle = true; 56 if ((desc.style & Font.BOLD) == Font.BOLD && 57 ((compFont.style & Font.BOLD) == 0)) { 58 boldness = 1.33f; 59 } 60 if ((desc.style & Font.ITALIC) == Font.ITALIC && 61 (compFont.style & Font.ITALIC) == 0) { 62 italic = 0.7f; 63 } 64 } 65 strikes = new PhysicalStrike[compFont.numSlots]; 66 } 67 68 /* do I need this (see Strike::compositeStrikeForGlyph) */ getStrikeForGlyph(int glyphCode)69 PhysicalStrike getStrikeForGlyph(int glyphCode) { 70 return getStrikeForSlot(glyphCode >>> 24); 71 } 72 getStrikeForSlot(int slot)73 PhysicalStrike getStrikeForSlot(int slot) { 74 if (slot >= strikes.length) { 75 slot = 0; 76 } 77 PhysicalStrike strike = strikes[slot]; 78 if (strike == null) { 79 strike = 80 (PhysicalStrike)(compFont.getSlotFont(slot).getStrike(desc)); 81 82 strikes[slot] = strike; 83 } 84 return strike; 85 } 86 getNumGlyphs()87 public int getNumGlyphs() { 88 return compFont.getNumGlyphs(); 89 } 90 getFontMetrics()91 StrikeMetrics getFontMetrics() { 92 if (strikeMetrics == null) { 93 StrikeMetrics compMetrics = new StrikeMetrics(); 94 for (int s=0; s<compFont.numMetricsSlots; s++) { 95 compMetrics.merge(getStrikeForSlot(s).getFontMetrics()); 96 } 97 strikeMetrics = compMetrics; 98 } 99 return strikeMetrics; 100 } 101 102 103 /* Performance tweak: Slot 0 can often return all the glyphs 104 * Note slot zero doesn't need to be masked. 105 * Could go a step further and support getting a run of glyphs. 106 * This would help many locales a little. 107 * 108 * Note that if a client constructs an invalid a composite glyph that 109 * references an invalid slot, that the behaviour is currently 110 * that this slot index falls through to CompositeFont.getSlotFont(int) 111 * which will substitute a default font, from which to obtain the 112 * strike. If its an invalid glyph code for a valid slot, then the 113 * physical font for that slot will substitute the missing glyph. 114 */ getGlyphImagePtrs(int[] glyphCodes, long[] images, int len)115 void getGlyphImagePtrs(int[] glyphCodes, long[] images, int len) { 116 PhysicalStrike strike = getStrikeForSlot(0); 117 int numptrs = strike.getSlot0GlyphImagePtrs(glyphCodes, images, len); 118 if (numptrs == len) { 119 return; 120 } 121 for (int i=numptrs; i< len; i++) { 122 strike = getStrikeForGlyph(glyphCodes[i]); 123 images[i] = strike.getGlyphImagePtr(glyphCodes[i] & SLOTMASK); 124 } 125 } 126 127 getGlyphImagePtr(int glyphCode)128 long getGlyphImagePtr(int glyphCode) { 129 PhysicalStrike strike = getStrikeForGlyph(glyphCode); 130 return strike.getGlyphImagePtr(glyphCode & SLOTMASK); 131 } 132 getGlyphImageBounds(int glyphCode, Point2D.Float pt, Rectangle result)133 void getGlyphImageBounds(int glyphCode, Point2D.Float pt, Rectangle result) { 134 PhysicalStrike strike = getStrikeForGlyph(glyphCode); 135 strike.getGlyphImageBounds(glyphCode & SLOTMASK, pt, result); 136 } 137 getGlyphMetrics(int glyphCode)138 Point2D.Float getGlyphMetrics(int glyphCode) { 139 PhysicalStrike strike = getStrikeForGlyph(glyphCode); 140 return strike.getGlyphMetrics(glyphCode & SLOTMASK); 141 } 142 getCharMetrics(char ch)143 Point2D.Float getCharMetrics(char ch) { 144 return getGlyphMetrics(compFont.getMapper().charToGlyph(ch)); 145 } 146 getGlyphAdvance(int glyphCode)147 float getGlyphAdvance(int glyphCode) { 148 PhysicalStrike strike = getStrikeForGlyph(glyphCode); 149 return strike.getGlyphAdvance(glyphCode & SLOTMASK); 150 } 151 152 /* REMIND where to cache? 153 * The glyph advance is already cached by physical strikes and that's a lot 154 * of the work. 155 * Also FontDesignMetrics maintains a latin char advance cache, so don't 156 * cache advances here as apps tend to hold onto metrics objects when 157 * performance is sensitive to it. Revisit this assumption later. 158 */ getCodePointAdvance(int cp)159 float getCodePointAdvance(int cp) { 160 return getGlyphAdvance(compFont.getMapper().charToGlyph(cp)); 161 } 162 getGlyphOutlineBounds(int glyphCode)163 Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) { 164 PhysicalStrike strike = getStrikeForGlyph(glyphCode); 165 return strike.getGlyphOutlineBounds(glyphCode & SLOTMASK); 166 } 167 getGlyphOutline(int glyphCode, float x, float y)168 GeneralPath getGlyphOutline(int glyphCode, float x, float y) { 169 170 PhysicalStrike strike = getStrikeForGlyph(glyphCode); 171 GeneralPath path = strike.getGlyphOutline(glyphCode & SLOTMASK, x, y); 172 if (path == null) { 173 return new GeneralPath(); 174 } else { 175 return path; 176 } 177 } 178 179 /* The physical font slot for each glyph is encoded in the glyph ID 180 * To be as efficient as possible we find a run of glyphs from the 181 * same slot and create a temporary array of these glyphs decoded 182 * to the slot. The slot font is then queried for the GeneralPath 183 * for that run of glyphs. GeneralPaths from each run are appended 184 * to create the shape for the whole glyph array. 185 */ getGlyphVectorOutline(int[] glyphs, float x, float y)186 GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) { 187 GeneralPath path = null; 188 GeneralPath gp; 189 int glyphIndex = 0; 190 int[] tmpGlyphs; 191 192 while (glyphIndex < glyphs.length) { 193 int start = glyphIndex; 194 int slot = glyphs[glyphIndex] >>> 24; 195 while (glyphIndex < glyphs.length && 196 (glyphs[glyphIndex+1] >>> 24) == slot) { 197 glyphIndex++; 198 } 199 int tmpLen = glyphIndex-start+1; 200 tmpGlyphs = new int[tmpLen]; 201 for (int i=0;i<tmpLen;i++) { 202 tmpGlyphs[i] = glyphs[i] & SLOTMASK; 203 } 204 gp = getStrikeForSlot(slot).getGlyphVectorOutline(tmpGlyphs, x, y); 205 if (path == null) { 206 path = gp; 207 } else if (gp != null) { 208 path.append(gp, false); 209 } 210 } 211 if (path == null) { 212 return new GeneralPath(); 213 } else { 214 return path; 215 } 216 } 217 } 218