History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/font/GlyphList.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/font/GlyphList.java+506−0
@@ -0,0 +1,506 @@
1+/*
2+ * Copyright (c) 2000, 2006, 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.font.GlyphVector;
30+import java.awt.font.FontRenderContext;
31+import sun.java2d.loops.FontInfo;
32+
33+/*
34+ * This class represents a list of actual renderable glyphs.
35+ * It can be constructed from a number of text sources, representing
36+ * the various ways in which a programmer can ask a Graphics2D object
37+ * to render some text. Once constructed, it provides a way of iterating
38+ * through the device metrics and graybits of the individual glyphs that
39+ * need to be rendered to the screen.
40+ *
41+ * Note that this class holds pointers to native data which must be
42+ * disposed. It is not marked as finalizable since it is intended
43+ * to be very lightweight and finalization is a comparitively expensive
44+ * procedure. The caller must specifically use try{} finally{} to
45+ * manually ensure that the object is disposed after use, otherwise
46+ * native data structures might be leaked.
47+ *
48+ * Here is a code sample for using this class:
49+ *
50+ * public void drawString(String str, FontInfo info, float x, float y) {
51+ * GlyphList gl = GlyphList.getInstance();
52+ * try {
53+ * gl.setFromString(info, str, x, y);
54+ * int strbounds[] = gl.getBounds();
55+ * int numglyphs = gl.getNumGlyphs();
56+ * for (int i = 0; i < numglyphs; i++) {
57+ * gl.setGlyphIndex(i);
58+ * int metrics[] = gl.getMetrics();
59+ * byte bits[] = gl.getGrayBits();
60+ * int glyphx = metrics[0];
61+ * int glyphy = metrics[1];
62+ * int glyphw = metrics[2];
63+ * int glyphh = metrics[3];
64+ * int off = 0;
65+ * for (int j = 0; j < glyphh; j++) {
66+ * for (int i = 0; i < glyphw; i++) {
67+ * int dx = glyphx + i;
68+ * int dy = glyphy + j;
69+ * int alpha = bits[off++];
70+ * drawPixel(alpha, dx, dy);
71+ * }
72+ * }
73+ * }
74+ * } finally {
75+ * gl.dispose();
76+ * }
77+ * }
78+ */
79+public final class GlyphList {
80+ private static final int MINGRAYLENGTH = 1024;
81+ private static final int MAXGRAYLENGTH = 8192;
82+ private static final int DEFAULT_LENGTH = 32;
83+
84+ int glyphindex;
85+ int metrics[];
86+ byte graybits[];
87+
88+ /* A reference to the strike is needed for the case when the GlyphList
89+ * may be added to a queue for batch processing, (e.g. OpenGL) and we need
90+ * to be completely certain that the strike is still valid when the glyphs
91+ * images are later referenced. This does mean that if such code discards
92+ * GlyphList and places only the data it contains on the queue, that the
93+ * strike needs to be part of that data held by a strong reference.
94+ * In the cases of drawString() and drawChars(), this is a single strike,
95+ * although it may be a composite strike. In the case of
96+ * drawGlyphVector() it may be a single strike, or a list of strikes.
97+ */
98+ Object strikelist; // hold multiple strikes during rendering of complex gv
99+
100+ /* In normal usage, the same GlyphList will get recycled, so
101+ * it makes sense to allocate arrays that will get reused along with
102+ * it, rather than generating garbage. Garbage will be generated only
103+ * in MP envts where multiple threads are executing. Throughput should
104+ * still be higher in those cases.
105+ */
106+ int len = 0;
107+ int maxLen = 0;
108+ int maxPosLen = 0;
109+ int glyphData[];
110+ char chData[];
111+ long images[];
112+ float positions[];
113+ float x, y;
114+ float gposx, gposy;
115+ boolean usePositions;
116+
117+ /* lcdRGBOrder is used only by LCD text rendering. Its here because
118+ * the Graphics may have a different hint value than the one used
119+ * by a GlyphVector, so it has to be stored here - and is obtained
120+ * from the right FontInfo. Another approach would have been to have
121+ * install a separate pipe for that case but that's a lot of extra
122+ * code when a simple boolean will suffice. The overhead to non-LCD
123+ * text is a redundant boolean assign per call.
124+ */
125+ boolean lcdRGBOrder;
126+
127+ /*
128+ * lcdSubPixPos is used only by LCD text rendering. Its here because
129+ * the Graphics may have a different hint value than the one used
130+ * by a GlyphVector, so it has to be stored here - and is obtained
131+ * from the right FontInfo. Its also needed by the code which
132+ * calculates glyph positions which already needs to access this
133+ * GlyphList and would otherwise need the FontInfo.
134+ * This is true only if LCD text and fractional metrics hints
135+ * are selected on the graphics.
136+ * When this is true and the glyph positions as determined by the
137+ * advances are non-integral, it requests adjustment of the positions.
138+ * Setting this for surfaces which do not support it through accelerated
139+ * loops may cause a slow-down as software loops are invoked instead.
140+ */
141+ boolean lcdSubPixPos;
142+
143+ /* This scheme creates a singleton GlyphList which is checked out
144+ * for use. Callers who find its checked out create one that after use
145+ * is discarded. This means that in a MT-rendering environment,
146+ * there's no need to synchronise except for that one instance.
147+ * Fewer threads will then need to synchronise, perhaps helping
148+ * throughput on a MP system. If for some reason the reusable
149+ * GlyphList is checked out for a long time (or never returned?) then
150+ * we would end up always creating new ones. That situation should not
151+ * occur and if if did, it would just lead to some extra garbage being
152+ * created.
153+ */
154+ private static GlyphList reusableGL = new GlyphList();
155+ private static boolean inUse;
156+
157+
158+ void ensureCapacity(int len) {
159+ /* Note len must not be -ve! only setFromChars should be capable
160+ * of passing down a -ve len, and this guards against it.
161+ */
162+ if (len < 0) {
163+ len = 0;
164+ }
165+ if (usePositions && len > maxPosLen) {
166+ positions = new float[len * 2 + 2];
167+ maxPosLen = len;
168+ }
169+
170+ if (maxLen == 0 || len > maxLen) {
171+ glyphData = new int[len];
172+ chData = new char[len];
173+ images = new long[len];
174+ maxLen = len;
175+ }
176+ }
177+
178+ private GlyphList() {
179+// ensureCapacity(DEFAULT_LENGTH);
180+ }
181+
182+// private GlyphList(int arraylen) {
183+// ensureCapacity(arraylen);
184+// }
185+
186+ public static GlyphList getInstance() {
187+ /* The following heuristic is that if the reusable instance is
188+ * in use, it probably still will be in a micro-second, so avoid
189+ * synchronising on the class and just allocate a new instance.
190+ * The cost is one extra boolean test for the normal case, and some
191+ * small number of cases where we allocate an extra object when
192+ * in fact the reusable one would be freed very soon.
193+ */
194+ if (inUse) {
195+ return new GlyphList();
196+ } else {
197+ synchronized(GlyphList.class) {
198+ if (inUse) {
199+ return new GlyphList();
200+ } else {
201+ inUse = true;
202+ return reusableGL;
203+ }
204+ }
205+ }
206+ }
207+
208+ /* In some cases the caller may be able to estimate the size of
209+ * array needed, and it will usually be long enough. This avoids
210+ * the unnecessary reallocation that occurs if our default
211+ * values are too small. This is useful because this object
212+ * will be discarded so the re-allocation overhead is high.
213+ */
214+// public static GlyphList getInstance(int sz) {
215+// if (inUse) {
216+// return new GlyphList(sz);
217+// } else {
218+// synchronized(GlyphList.class) {
219+// if (inUse) {
220+// return new GlyphList();
221+// } else {
222+// inUse = true;
223+// return reusableGL;
224+// }
225+// }
226+// }
227+// }
228+
229+ /* GlyphList is in an invalid state until setFrom* method is called.
230+ * After obtaining a new GlyphList it is the caller's responsibility
231+ * that one of these methods is executed before handing off the
232+ * GlyphList
233+ */
234+
235+ public boolean setFromString(FontInfo info, String str, float x, float y) {
236+ this.x = x;
237+ this.y = y;
238+ this.strikelist = info.fontStrike;
239+ this.lcdRGBOrder = info.lcdRGBOrder;
240+ this.lcdSubPixPos = info.lcdSubPixPos;
241+ len = str.length();
242+ ensureCapacity(len);
243+ str.getChars(0, len, chData, 0);
244+ return mapChars(info, len);
245+ }
246+
247+ public boolean setFromChars(FontInfo info, char[] chars, int off, int alen,
248+ float x, float y) {
249+ this.x = x;
250+ this.y = y;
251+ this.strikelist = info.fontStrike;
252+ this.lcdRGBOrder = info.lcdRGBOrder;
253+ this.lcdSubPixPos = info.lcdSubPixPos;
254+ len = alen;
255+ if (alen < 0) {
256+ len = 0;
257+ } else {
258+ len = alen;
259+ }
260+ ensureCapacity(len);
261+ System.arraycopy(chars, off, chData, 0, len);
262+ return mapChars(info, len);
263+ }
264+
265+ private final boolean mapChars(FontInfo info, int len) {
266+ /* REMIND.Is it worthwhile for the iteration to convert
267+ * chars to glyph ids to directly map to images?
268+ */
269+ if (info.font2D.getMapper().charsToGlyphsNS(len, chData, glyphData)) {
270+ return false;
271+ }
272+ info.fontStrike.getGlyphImagePtrs(glyphData, images, len);
273+ glyphindex = -1;
274+ return true;
275+ }
276+
277+
278+ public void setFromGlyphVector(FontInfo info, GlyphVector gv,
279+ float x, float y) {
280+ this.x = x;
281+ this.y = y;
282+ this.lcdRGBOrder = info.lcdRGBOrder;
283+ this.lcdSubPixPos = info.lcdSubPixPos;
284+ /* A GV may be rendered in different Graphics. It is possible it is
285+ * used for one case where LCD text is available, and another where
286+ * it is not. Pass in the "info". to ensure get a suitable one.
287+ */
288+ StandardGlyphVector sgv = StandardGlyphVector.getStandardGV(gv, info);
289+ // call before ensureCapacity :-
290+ usePositions = sgv.needsPositions(info.devTx);
291+ len = sgv.getNumGlyphs();
292+ ensureCapacity(len);
293+ strikelist = sgv.setupGlyphImages(images,
294+ usePositions ? positions : null,
295+ info.devTx);
296+ glyphindex = -1;
297+ }
298+
299+ public int[] getBounds() {
300+ /* We co-opt the 5 element array that holds per glyph metrics in order
301+ * to return the bounds. So a caller must copy the data out of the
302+ * array before calling any other methods on this GlyphList
303+ */
304+ if (glyphindex >= 0) {
305+ throw new InternalError("calling getBounds after setGlyphIndex");
306+ }
307+ if (metrics == null) {
308+ metrics = new int[5];
309+ }
310+ /* gposx and gposy are used to accumulate the advance.
311+ * Add 0.5f for consistent rounding to pixel position. */
312+ gposx = x + 0.5f;
313+ gposy = y + 0.5f;
314+ fillBounds(metrics);
315+ return metrics;
316+ }
317+
318+ /* This method now assumes "state", so must be called 0->len
319+ * The metrics it returns are accumulated on the fly
320+ * So it could be renamed "nextGlyph()".
321+ * Note that a laid out GlyphVector which has assigned glyph positions
322+ * doesn't have this stricture..
323+ */
324+ public void setGlyphIndex(int i) {
325+ glyphindex = i;
326+ float gx =
327+ StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftXOffset);
328+ float gy =
329+ StrikeCache.unsafe.getFloat(images[i]+StrikeCache.topLeftYOffset);
330+
331+ if (usePositions) {
332+ metrics[0] = (int)Math.floor(positions[(i<<1)] + gposx + gx);
333+ metrics[1] = (int)Math.floor(positions[(i<<1)+1] + gposy + gy);
334+ } else {
335+ metrics[0] = (int)Math.floor(gposx + gx);
336+ metrics[1] = (int)Math.floor(gposy + gy);
337+ /* gposx and gposy are used to accumulate the advance */
338+ gposx += StrikeCache.unsafe.getFloat
339+ (images[i]+StrikeCache.xAdvanceOffset);
340+ gposy += StrikeCache.unsafe.getFloat
341+ (images[i]+StrikeCache.yAdvanceOffset);
342+ }
343+ metrics[2] =
344+ StrikeCache.unsafe.getChar(images[i]+StrikeCache.widthOffset);
345+ metrics[3] =
346+ StrikeCache.unsafe.getChar(images[i]+StrikeCache.heightOffset);
347+ metrics[4] =
348+ StrikeCache.unsafe.getChar(images[i]+StrikeCache.rowBytesOffset);
349+ }
350+
351+ public int[] getMetrics() {
352+ return metrics;
353+ }
354+
355+ public byte[] getGrayBits() {
356+ int len = metrics[4] * metrics[3];
357+ if (graybits == null) {
358+ graybits = new byte[Math.max(len, MINGRAYLENGTH)];
359+ } else {
360+ if (len > graybits.length) {
361+ graybits = new byte[len];
362+ }
363+ }
364+ long pixelDataAddress;
365+ if (StrikeCache.nativeAddressSize == 4) {
366+ pixelDataAddress = 0xffffffff &
367+ StrikeCache.unsafe.getInt(images[glyphindex] +
368+ StrikeCache.pixelDataOffset);
369+ } else {
370+ pixelDataAddress =
371+ StrikeCache.unsafe.getLong(images[glyphindex] +
372+ StrikeCache.pixelDataOffset);
373+ }
374+ if (pixelDataAddress == 0L) {
375+ return graybits;
376+ }
377+ /* unsafe is supposed to be fast, but I doubt if this loop can beat
378+ * a native call which does a getPrimitiveArrayCritical and a
379+ * memcpy for the typical amount of image data (30-150 bytes)
380+ * Consider a native method if there is a performance problem (which
381+ * I haven't seen so far).
382+ */
383+ for (int i=0; i<len; i++) {
384+ graybits[i] = StrikeCache.unsafe.getByte(pixelDataAddress+i);
385+ }
386+ return graybits;
387+ }
388+
389+ public long[] getImages() {
390+ return images;
391+ }
392+
393+ public boolean usePositions() {
394+ return usePositions;
395+ }
396+
397+ public float[] getPositions() {
398+ return positions;
399+ }
400+
401+ public float getX() {
402+ return x;
403+ }
404+
405+ public float getY() {
406+ return y;
407+ }
408+
409+ public Object getStrike() {
410+ return strikelist;
411+ }
412+
413+ public boolean isSubPixPos() {
414+ return lcdSubPixPos;
415+ }
416+
417+ public boolean isRGBOrder() {
418+ return lcdRGBOrder;
419+ }
420+
421+ /* There's a reference equality test overhead here, but it allows us
422+ * to avoid synchronizing for GL's that will just be GC'd. This
423+ * helps MP throughput.
424+ */
425+ public void dispose() {
426+ if (this == reusableGL) {
427+ if (graybits != null && graybits.length > MAXGRAYLENGTH) {
428+ graybits = null;
429+ }
430+ usePositions = false;
431+ strikelist = null; // remove reference to the strike list
432+ inUse = false;
433+ }
434+ }
435+
436+ /* The value here is for use by the rendering engine as it reflects
437+ * the number of glyphs in the array to be blitted. Surrogates pairs
438+ * may have two slots (the second of these being a dummy entry of the
439+ * invisible glyph), whereas an application client would expect only
440+ * one glyph. In other words don't propagate this value up to client code.
441+ *
442+ * {dlf} an application client should have _no_ expectations about the
443+ * number of glyphs per char. This ultimately depends on the font
444+ * technology and layout process used, which in general clients will
445+ * know nothing about.
446+ */
447+ public int getNumGlyphs() {
448+ return len;
449+ }
450+
451+ /* We re-do all this work as we iterate through the glyphs
452+ * but it seems unavoidable without re-working the Java TextRenderers.
453+ */
454+ private void fillBounds(int[] bounds) {
455+ /* Faster to access local variables in the for loop? */
456+ int xOffset = StrikeCache.topLeftXOffset;
457+ int yOffset = StrikeCache.topLeftYOffset;
458+ int wOffset = StrikeCache.widthOffset;
459+ int hOffset = StrikeCache.heightOffset;
460+ int xAdvOffset = StrikeCache.xAdvanceOffset;
461+ int yAdvOffset = StrikeCache.yAdvanceOffset;
462+
463+ if (len == 0) {
464+ bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0;
465+ return;
466+ }
467+ float bx0, by0, bx1, by1;
468+ bx0 = by0 = Float.POSITIVE_INFINITY;
469+ bx1 = by1 = Float.NEGATIVE_INFINITY;
470+
471+ int posIndex = 0;
472+ float glx = x + 0.5f;
473+ float gly = y + 0.5f;
474+ char gw, gh;
475+ float gx, gy, gx0, gy0, gx1, gy1;
476+ for (int i=0; i<len; i++) {
477+ gx = StrikeCache.unsafe.getFloat(images[i]+xOffset);
478+ gy = StrikeCache.unsafe.getFloat(images[i]+yOffset);
479+ gw = StrikeCache.unsafe.getChar(images[i]+wOffset);
480+ gh = StrikeCache.unsafe.getChar(images[i]+hOffset);
481+
482+ if (usePositions) {
483+ gx0 = positions[posIndex++] + gx + glx;
484+ gy0 = positions[posIndex++] + gy + gly;
485+ } else {
486+ gx0 = glx + gx;
487+ gy0 = gly + gy;
488+ glx += StrikeCache.unsafe.getFloat(images[i]+xAdvOffset);
489+ gly += StrikeCache.unsafe.getFloat(images[i]+yAdvOffset);
490+ }
491+ gx1 = gx0 + gw;
492+ gy1 = gy0 + gh;
493+ if (bx0 > gx0) bx0 = gx0;
494+ if (by0 > gy0) by0 = gy0;
495+ if (bx1 < gx1) bx1 = gx1;
496+ if (by1 < gy1) by1 = gy1;
497+ }
498+ /* floor is safe and correct because all glyph widths, heights
499+ * and offsets are integers
500+ */
501+ bounds[0] = (int)Math.floor(bx0);
502+ bounds[1] = (int)Math.floor(by0);
503+ bounds[2] = (int)Math.floor(bx1);
504+ bounds[3] = (int)Math.floor(by1);
505+ }
506+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t