001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Ilya S. Okomin
019: * @version $Revision$
020: */package org.apache.harmony.awt.gl.font;
021:
022: import java.awt.font.GlyphMetrics;
023: import java.awt.geom.GeneralPath;
024: import java.awt.geom.Rectangle2D;
025:
026: import java.awt.Rectangle;
027: import java.awt.Shape;
028:
029: import java.awt.image.BufferedImage;
030: import java.awt.image.DataBufferByte;
031: import java.awt.image.IndexColorModel;
032: import java.awt.image.Raster;
033: import java.awt.image.WritableRaster;
034: import java.lang.Math;
035:
036: import org.apache.harmony.awt.ContextStorage;
037: import org.apache.harmony.awt.nativebridge.linux.*;
038: import org.apache.harmony.awt.nativebridge.Int16Pointer;
039: import org.apache.harmony.awt.nativebridge.Int8Pointer;
040: import org.apache.harmony.awt.gl.font.Glyph;
041: import org.apache.harmony.awt.gl.font.LinuxNativeFont;
042: import org.apache.harmony.awt.wtk.linux.LinuxWindowFactory;
043: import org.apache.harmony.awt.nativebridge.linux.LinuxNativeFontWrapper;
044:
045: /**
046: * Linux implementation of the Glyph class
047: */
048: public class LinuxGlyph extends Glyph {
049:
050: // Xft instance
051: private final Xft xft = Xft.getInstance();
052:
053: // LinuxNativeFontWrapper instance
054: private final LinuxNativeFontWrapper lnfw = LinuxNativeFontWrapper
055: .getInstance();
056:
057: // GlyphBitmap structure that stores bitmap of the glyph.
058: LinuxNativeFontWrapper.GlyphBitmap gBmp = null;
059:
060: /**
061: * Constructor
062: */
063: public LinuxGlyph(long pFnt, int fntSize, char c, int glyphIndex) {
064: // FIXME: all code related to the precise metrics array
065: // commented out because we have the same results as pxl metrics
066:
067: int[] pxlMetrics = new int[6];
068: // float[] metrics = new float[6];
069:
070: this .pFont = pFnt;
071: this .fontSize = fntSize;
072: long display = ((LinuxWindowFactory) ContextStorage
073: .getWindowFactory()).getDisplay();
074: switch (c) {
075: case '\t':
076: case '\r':
077: case '\n':
078: break;
079: default:
080: pxlMetrics = LinuxNativeFont.getGlyphPxlInfoNative(display,
081: this .pFont, c);
082: if (pxlMetrics == null) {
083: pxlMetrics = new int[6];
084: }
085: /* metrics = LinuxNativeFont.getGlyphInfoNative(this.pFont, c, fntSize);
086: if (metrics == null){
087: metrics = new float[6];
088: }
089: */
090: break;
091:
092: }
093:
094: /* metrics = LinuxNativeFont.getGlyphInfoNative(this.pFont, c, fntSize);
095:
096: Rectangle2D.Float rect = new Rectangle2D.Float(metrics[0],
097: -metrics[1],
098: metrics[4],
099: metrics[5]);
100: this.glPointMetrics = new GlyphMetrics((float)Math.ceil(metrics[2]), rect, (byte)1);
101: this.glMetrics = new GlyphMetrics((float)Math.ceil(metrics[2]), rect, (byte)1);
102: */
103: this .glCode = glyphIndex;
104: this .glChar = c;
105:
106: Rectangle rct = new Rectangle(pxlMetrics[0], -pxlMetrics[1],
107: pxlMetrics[4], pxlMetrics[5]);
108:
109: this .glPointMetrics = new GlyphMetrics(pxlMetrics[2], rct,
110: (byte) 1);
111: this .glMetrics = new GlyphMetrics((float) Math
112: .ceil(pxlMetrics[2]), rct, (byte) 0);
113:
114: }
115:
116: /**
117: * Default Glyph constructor
118: */
119: public LinuxGlyph(char c, int glyphIndex) {
120: float metrics[] = new float[6];
121: int[] pxlMetrics = new int[6];
122:
123: this .pFont = 0;
124: this .fontSize = 0;
125:
126: Rectangle2D.Float rect = new Rectangle2D.Float(metrics[0],
127: -metrics[1], metrics[4], metrics[5]);
128: this .glMetrics = new GlyphMetrics(
129: (float) Math.ceil(metrics[2]), rect, (byte) 0);
130:
131: this .glCode = glyphIndex;
132: this .glChar = c;
133:
134: Rectangle rct = new Rectangle(pxlMetrics[0], -pxlMetrics[1],
135: pxlMetrics[4], pxlMetrics[5]);
136: this .glPointMetrics = new GlyphMetrics(pxlMetrics[2], rct,
137: (byte) 1);
138: }
139:
140: /**
141: * Returns cached bitmap of the glyph's bitmap. Returns null if this
142: * Glyph object has height or width equal to zero.
143: */
144: public byte[] getBitmap() {
145: if ((this .getWidth() == 0) || (this .getHeight() == 0)) {
146: return null;
147: }
148:
149: if (this .bitmap == null) {
150: initFTBitmap();
151: }
152:
153: return this .bitmap;
154: }
155:
156: /**
157: * Returns cached GlyphBitmap object representing bitmap data of this glyph.
158: * If cached value is null - bitmap data is to be obtained from native code.
159: * @return GlyphBitmap data object
160: */
161: public LinuxNativeFontWrapper.GlyphBitmap initFTBitmap() {
162: if (this .gBmp == null) {
163: long ptr = LinuxNativeFont.NativeInitGlyphBitmap(
164: this .pFont, this .glChar);
165: if (ptr != 0) {
166: this .gBmp = lnfw.createGlyphBitmap(ptr);
167: Xft.FT_Bitmap ft_bitmap = gBmp.get_bitmap();
168: Int8Pointer buffer = ft_bitmap.get_buffer();
169: this .bmp_left = gBmp.get_left();
170: this .bmp_top = gBmp.get_top();
171: this .bmp_pitch = ft_bitmap.get_pitch();
172: this .bmp_rows = ft_bitmap.get_rows();
173: this .bmp_width = ft_bitmap.get_width();
174: int bufSize = bmp_pitch * bmp_rows; // size of buffer
175:
176: bitmap = new byte[bufSize];
177: buffer.get(bitmap, 0, bufSize);
178: LinuxNativeFont.NativeFreeGlyphBitmap(ptr);
179: }
180: }
181:
182: return this .gBmp;
183: }
184:
185: public BufferedImage getImage() {
186: if ((this .getWidth() == 0) || (this .getHeight() == 0)) {
187: return null;
188: }
189:
190: byte[] pixels;
191: int alignedWidth;
192: int width;
193: int height;
194: if (this .image == null) {
195: pixels = getBitmap();
196:
197: DataBufferByte dataBuffer = new DataBufferByte(pixels,
198: pixels.length);
199: /* Work around:
200: *
201: * Because of inability to create IndexedColorModel with data, represented as DataBuffer.TYPE_INT
202: * Raster with additional width is created to cover all bits, which are extending meaningful bits
203: * to the DWORD-aligning. When we want to take an image of the glyhp - we have to copy only rectangle
204: * that encloses the Glyph from the whole raster.
205: *
206: * */
207: height = (int) this .glPointMetrics.getBounds2D()
208: .getHeight();
209: alignedWidth = (pixels.length / height) << 3;
210: width = (int) this .glPointMetrics.getBounds2D().getWidth();
211:
212: WritableRaster wr = Raster.createPackedRaster(dataBuffer,
213: alignedWidth, height, 1, null);
214:
215: byte[] blackWhite = new byte[] { 0, (byte) 0xff };
216: IndexColorModel colorModel = new IndexColorModel(1, 2,
217: blackWhite, blackWhite, blackWhite);
218:
219: this .image = new BufferedImage(colorModel, wr
220: .createWritableChild(0, 0, width, height, 0, 0,
221: null), false, null);
222: }
223:
224: return this .image;
225: }
226:
227: public Shape initOutline(char c) {
228: GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
229: if ((this .getWidth() == 0) || (this .getHeight() == 0)) {
230: return gp;
231: }
232:
233: Shape shape = null;
234: long ptr;
235:
236: ptr = LinuxNativeFont.getGlyphOutline(this .pFont, c);
237: if (ptr == 0) {
238: return gp;
239: }
240:
241: Xft.FT_Outline outline = xft.createFT_Outline(ptr);
242:
243: int n_contours = outline.get_n_contours(); // number of contours in the glyph
244: if (n_contours == 0) {
245: LinuxNativeFont.freeGlyphOutline(ptr);
246: return gp;
247: }
248: Xft.FT_Vector pPoints = outline.get_points(); // array of outline points
249:
250: long pPointsPtr = pPoints.lock();
251: pPoints.unlock();
252:
253: int size = outline.get_n_points();
254: float points[] = LinuxNativeFont.getPointsFromFTVector(
255: pPointsPtr, size);
256:
257: Int16Pointer pContours = outline.get_contours(); // array of contour end points
258: Int8Pointer pTags = outline.get_tags(); // an array of point tags
259: int index = 0; // current point's index
260: int tag; // current tag
261: float x_start;
262: float y_start;
263: float x_finish;
264: float y_finish;
265: for (int i = 0; i < n_contours; i++) {
266: short end = pContours.get(i);// index of the last point
267:
268: // get start position
269: x_start = points[index * 2];
270: y_start = points[index * 2 + 1];
271:
272: // get finish position
273: x_finish = points[end * 2];
274: y_finish = points[end * 2 + 1];
275:
276: tag = pTags.get(index);// tag of the current point
277:
278: if (tag == LinuxNativeFontWrapper.FT_CURVE_TAG_CONIC) {
279: tag = pTags.get(end);// tag of the last point
280: if ((tag & LinuxNativeFontWrapper.FT_CURVE_TAG_ON) == 0) {
281: x_start = x_finish;
282: y_start = y_finish;
283: end--;
284: } else {
285: x_start = (x_start + x_finish) / 2;
286:
287: y_start = (y_start + y_finish) / 2;
288: x_finish = x_start;
289: y_finish = y_start;
290: index--;
291: }
292: }
293:
294: gp.moveTo(x_start, y_start);
295:
296: while (index < end) {
297: index++;
298:
299: tag = pTags.get(index);// tag of the current point
300: switch ((tag & 3)) {
301: case (LinuxNativeFontWrapper.FT_CURVE_TAG_ON):
302: float x = points[index * 2];
303: float y = points[index * 2 + 1];
304: gp.lineTo(x, y);
305: // System.out.println("AddPoint [" + x + "," + y + "]");
306: break;
307: case (LinuxNativeFontWrapper.FT_CURVE_TAG_CONIC):
308: float x1 = points[index * 2];
309: float y1 = points[index * 2 + 1];
310:
311: float x2;
312: float y2;
313: while (index < end) {
314: index++;
315: tag = pTags.get(index);// tag of the current point
316: x2 = points[index * 2];
317: y2 = points[index * 2 + 1];
318: if ((tag & LinuxNativeFontWrapper.FT_CURVE_TAG_ON) != 0) {
319: gp.quadTo(x1, y1, x2, y2);
320: // System.out.println("AddQSpline 1[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
321: break;
322: } else {
323: gp.quadTo(x1, y1, (x1 + x2) / 2,
324: (y1 + y2) / 2);
325: // System.out.println("AddQSpline 2[" + x1 + "," + y1 + "][" + (x1 + x2)/2 + "," + (y1 + y2)/2 + "]");
326: x1 = x2;
327: y1 = y2;
328: }
329: }
330: if ((index == end)
331: && ((tag & LinuxNativeFontWrapper.FT_CURVE_TAG_ON) == 0)) {
332: gp.quadTo(x1, y1, x_start, y_start);
333: // System.out.println("AddQSpline 3[" + x1 + "," + y1 + "][" + x_start + "," + y_start + "]");
334: }
335: break;
336: case (LinuxNativeFontWrapper.FT_CURVE_TAG_CUBIC):
337: x1 = points[index * 2];
338: y1 = points[index * 2 + 1];
339: index++;
340: x2 = points[index * 2];
341: y2 = points[index * 2 + 1];
342:
343: if (index < end) {
344: index++;
345:
346: float x3 = points[index * 2];
347: float y3 = points[index * 2 + 1];
348: gp.curveTo(x1, y1, x2, y2, x3, y3);
349: // System.out.println("AddCSpline 1[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "][" + x3 + "," + y3 + "]");
350: } else {
351: gp.curveTo(x1, y1, x2, y2, x_start, y_start);
352: // System.out.println("AddCSpline 2[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "][" + x_start + "," + y_start + "]");
353: }
354: break;
355: default:
356: LinuxNativeFont.freeGlyphOutline(ptr);
357: return new GeneralPath(GeneralPath.WIND_EVEN_ODD);
358: }
359:
360: }
361: gp.lineTo(x_start, y_start);
362: index++;
363: }
364:
365: shape = gp;
366: LinuxNativeFont.freeGlyphOutline(ptr);
367: return shape;
368: }
369: }
|