blob: 1e1f3e04dd3b9f9c34e8bf369ec536d09896d3b6 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.font;
27
28import java.awt.Font;
29import java.awt.Rectangle;
30import java.awt.geom.GeneralPath;
31import java.awt.geom.Point2D;
32import 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 */
42public 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
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) */
69 PhysicalStrike getStrikeForGlyph(int glyphCode) {
70 return getStrikeForSlot(glyphCode >>> 24);
71 }
72
73 PhysicalStrike getStrikeForSlot(int slot) {
74
75 PhysicalStrike strike = strikes[slot];
76 if (strike == null) {
77 strike =
78 (PhysicalStrike)(compFont.getSlotFont(slot).getStrike(desc));
79
80 strikes[slot] = strike;
81 }
82 return strike;
83 }
84
85 public int getNumGlyphs() {
86 return compFont.getNumGlyphs();
87 }
88
89 StrikeMetrics getFontMetrics() {
90 if (strikeMetrics == null) {
91 StrikeMetrics compMetrics = new StrikeMetrics();
92 for (int s=0; s<compFont.numMetricsSlots; s++) {
93 compMetrics.merge(getStrikeForSlot(s).getFontMetrics());
94 }
95 strikeMetrics = compMetrics;
96 }
97 return strikeMetrics;
98 }
99
100
101 /* Performance tweak: Slot 0 can often return all the glyphs
102 * Note slot zero doesn't need to be masked.
103 * Could go a step further and support getting a run of glyphs.
104 * This would help many locales a little.
105 *
106 * Note that if a client constructs an invalid a composite glyph that
107 * references an invalid slot, that the behaviour is currently
108 * that this slot index falls through to CompositeFont.getSlotFont(int)
109 * which will substitute a default font, from which to obtain the
110 * strike. If its an invalid glyph code for a valid slot, then the
111 * physical font for that slot will substitute the missing glyph.
112 */
113 void getGlyphImagePtrs(int[] glyphCodes, long[] images, int len) {
114 PhysicalStrike strike = getStrikeForSlot(0);
115 int numptrs = strike.getSlot0GlyphImagePtrs(glyphCodes, images, len);
116 if (numptrs == len) {
117 return;
118 }
119 for (int i=numptrs; i< len; i++) {
120 strike = getStrikeForGlyph(glyphCodes[i]);
121 images[i] = strike.getGlyphImagePtr(glyphCodes[i] & SLOTMASK);
122 }
123 }
124
125
126 long getGlyphImagePtr(int glyphCode) {
127 PhysicalStrike strike = getStrikeForGlyph(glyphCode);
128 return strike.getGlyphImagePtr(glyphCode & SLOTMASK);
129 }
130
131 void getGlyphImageBounds(int glyphCode, Point2D.Float pt, Rectangle result) {
132 PhysicalStrike strike = getStrikeForGlyph(glyphCode);
133 strike.getGlyphImageBounds(glyphCode & SLOTMASK, pt, result);
134 }
135
136 Point2D.Float getGlyphMetrics(int glyphCode) {
137 PhysicalStrike strike = getStrikeForGlyph(glyphCode);
138 return strike.getGlyphMetrics(glyphCode & SLOTMASK);
139 }
140
141 Point2D.Float getCharMetrics(char ch) {
142 return getGlyphMetrics(compFont.getMapper().charToGlyph(ch));
143 }
144
145 float getGlyphAdvance(int glyphCode) {
146 PhysicalStrike strike = getStrikeForGlyph(glyphCode);
147 return strike.getGlyphAdvance(glyphCode & SLOTMASK);
148 }
149
150 /* REMIND where to cache?
151 * The glyph advance is already cached by physical strikes and that's a lot
152 * of the work.
153 * Also FontDesignMetrics maintains a latin char advance cache, so don't
154 * cache advances here as apps tend to hold onto metrics objects when
155 * performance is sensitive to it. Revisit this assumption later.
156 */
157 float getCodePointAdvance(int cp) {
158 return getGlyphAdvance(compFont.getMapper().charToGlyph(cp));
159 }
160
161 Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) {
162 PhysicalStrike strike = getStrikeForGlyph(glyphCode);
163 return strike.getGlyphOutlineBounds(glyphCode & SLOTMASK);
164 }
165
166 GeneralPath getGlyphOutline(int glyphCode, float x, float y) {
167
168 PhysicalStrike strike = getStrikeForGlyph(glyphCode);
169 GeneralPath path = strike.getGlyphOutline(glyphCode & SLOTMASK, x, y);
170 if (path == null) {
171 return new GeneralPath();
172 } else {
173 return path;
174 }
175 }
176
177 /* The physical font slot for each glyph is encoded in the glyph ID
178 * To be as efficient as possible we find a run of glyphs from the
179 * same slot and create a temporary array of these glyphs decoded
180 * to the slot. The slot font is then queried for the GeneralPath
181 * for that run of glyphs. GeneralPaths from each run are appended
182 * to create the shape for the whole glyph array.
183 */
184 GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) {
185 GeneralPath path = null;
186 GeneralPath gp;
187 int glyphIndex = 0;
188 int[] tmpGlyphs;
189
190 while (glyphIndex < glyphs.length) {
191 int start = glyphIndex;
192 int slot = glyphs[glyphIndex] >>> 24;
193 while (glyphIndex < glyphs.length &&
194 (glyphs[glyphIndex+1] >>> 24) == slot) {
195 glyphIndex++;
196 }
197 int tmpLen = glyphIndex-start+1;
198 tmpGlyphs = new int[tmpLen];
199 for (int i=0;i<tmpLen;i++) {
200 tmpGlyphs[i] = glyphs[i] & SLOTMASK;
201 }
202 gp = getStrikeForSlot(slot).getGlyphVectorOutline(tmpGlyphs, x, y);
203 if (path == null) {
204 path = gp;
205 } else if (gp != null) {
206 path.append(gp, false);
207 }
208 }
209 if (path == null) {
210 return new GeneralPath();
211 } else {
212 return path;
213 }
214 }
215}