]> git.saurik.com Git - apple/icu.git/blob - icuSources/samples/layout/GnomeFontInstance.cpp
ICU-8.11.4.tar.gz
[apple/icu.git] / icuSources / samples / layout / GnomeFontInstance.cpp
1
2 /*
3 *******************************************************************************
4 *
5 * Copyright (C) 1999-2005, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 *
8 *******************************************************************************
9 * file name: GnomeFontInstance.cpp
10 *
11 * created on: 08/30/2001
12 * created by: Eric R. Mader
13 */
14
15 #include <gnome.h>
16 #include "freetype/freetype.h"
17
18 #include "layout/LETypes.h"
19 #include "layout/LESwaps.h"
20
21 #include "GnomeFontInstance.h"
22 #include "sfnt.h"
23 #include "cmaps.h"
24
25 GnomeSurface::GnomeSurface(GtkWidget *theWidget)
26 : fWidget(theWidget)
27 {
28 // nothing else to do
29 }
30
31 GnomeSurface::~GnomeSurface()
32 {
33 // nothing to do
34 }
35
36 void GnomeSurface::drawGlyphs(const LEFontInstance *font, const LEGlyphID *glyphs, le_int32 count,
37 const float *positions, le_int32 x, le_int32 y, le_int32 /*width*/, le_int32 /*height*/)
38 {
39 GnomeFontInstance *gFont = (GnomeFontInstance *) font;
40 TT_Instance instance = gFont->getFont();
41 le_int32 *dx = LE_NEW_ARRAY(le_int32, count);
42 le_int32 *dy = LE_NEW_ARRAY(le_int32, count);
43 le_int32 xOffset, yOffset;
44 TT_Raster_Map *raster;
45 // TT_Error error;
46
47 for (le_int32 g = 0; g < count; g += 1) {
48 dx[g] = (le_int32) (positions[g * 2 + 2] - positions[g * 2]);
49 dy[g] = (le_int32) - positions[g * 2 + 1];
50 }
51
52 raster = gFont->rasterizeGlyphs(glyphs, count, dx, dy, xOffset, yOffset);
53
54 if (raster->width > 0 && raster->rows > 0) {
55 GdkBitmap *bitmap = gdk_bitmap_create_from_data(NULL, (const gchar *) raster->bitmap, raster->width, raster->rows);
56
57 gint bitsx = x + (gint) positions[0] + xOffset;
58 gint bitsy = y - yOffset;
59
60 gdk_gc_set_clip_origin(fWidget->style->black_gc, bitsx, bitsy);
61 gdk_gc_set_clip_mask(fWidget->style->black_gc, bitmap);
62
63 gdk_draw_rectangle(fWidget->window,
64 fWidget->style->black_gc,
65 TRUE,
66 bitsx, bitsy,
67 raster->width, raster->rows);
68
69 gdk_gc_set_clip_origin(fWidget->style->black_gc, 0, 0);
70 gdk_gc_set_clip_mask(fWidget->style->black_gc, NULL);
71
72 gdk_bitmap_unref(bitmap);
73 }
74
75 gFont->freeRaster(raster);
76 LE_DELETE_ARRAY(dy);
77 LE_DELETE_ARRAY(dx);
78 }
79
80 GnomeFontInstance::GnomeFontInstance(TT_Engine engine, const TT_Text *fontPathName, le_int16 pointSize, LEErrorCode &status)
81 : FontTableCache(), fPointSize(pointSize), fUnitsPerEM(0), fAscent(0), fDescent(0), fLeading(0),
82 fDeviceScaleX(1), fDeviceScaleY(1), fMapper(NULL)
83 {
84 TT_Error error;
85 TT_Face_Properties faceProperties;
86
87 fFace.z = NULL;
88
89 error = TT_Open_Face(engine, fontPathName, &fFace);
90
91 if (error != 0) {
92 status = LE_FONT_FILE_NOT_FOUND_ERROR;
93 return;
94 }
95
96 error = TT_New_Instance(fFace, &fInstance);
97
98 if (error != 0) {
99 status = LE_MEMORY_ALLOCATION_ERROR;
100 return;
101 }
102
103 // FIXME: what about the display resolution?
104 // TT_Set_Instance_Resolutions(fInstance, 72, 72);
105 fDeviceScaleX = ((float) 96) / 72;
106 fDeviceScaleY = ((float) 96) / 72;
107
108 TT_Set_Instance_CharSize(fInstance, pointSize << 6);
109
110 TT_Get_Face_Properties(fFace, &faceProperties);
111
112 fUnitsPerEM = faceProperties.header->Units_Per_EM;
113
114 fAscent = (le_int32) (yUnitsToPoints(faceProperties.horizontal->Ascender) * fDeviceScaleY);
115 fDescent = (le_int32) -(yUnitsToPoints(faceProperties.horizontal->Descender) * fDeviceScaleY);
116 fLeading = (le_int32) (yUnitsToPoints(faceProperties.horizontal->Line_Gap) * fDeviceScaleY);
117
118 // printf("Face = %s, unitsPerEM = %d, ascent = %d, descent = %d\n", fontPathName, fUnitsPerEM, fAscent, fDescent);
119
120 error = TT_New_Glyph(fFace, &fGlyph);
121
122 if (error != 0) {
123 status = LE_MEMORY_ALLOCATION_ERROR;
124 return;
125 }
126
127 status = initMapper();
128 }
129
130 GnomeFontInstance::~GnomeFontInstance()
131 {
132 if (fFace.z != NULL) {
133 TT_Close_Face(fFace);
134 }
135 }
136
137 LEErrorCode GnomeFontInstance::initMapper()
138 {
139 LETag cmapTag = LE_CMAP_TABLE_TAG;
140 const CMAPTable *cmap = (const CMAPTable *) readFontTable(cmapTag);
141
142 if (cmap == NULL) {
143 return LE_MISSING_FONT_TABLE_ERROR;
144 }
145
146 fMapper = CMAPMapper::createUnicodeMapper(cmap);
147
148 if (fMapper == NULL) {
149 return LE_MISSING_FONT_TABLE_ERROR;
150 }
151
152 return LE_NO_ERROR;
153 }
154
155 const void *GnomeFontInstance::getFontTable(LETag tableTag) const
156 {
157 return FontTableCache::find(tableTag);
158 }
159
160 const void *GnomeFontInstance::readFontTable(LETag tableTag) const
161 {
162 TT_Long len = 0;
163 void *result = NULL;
164
165 TT_Get_Font_Data(fFace, tableTag, 0, NULL, &len);
166
167 if (len > 0) {
168 result = LE_NEW_ARRAY(char, len);
169 TT_Get_Font_Data(fFace, tableTag, 0, result, &len);
170 }
171
172 return result;
173 }
174
175 void GnomeFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
176 {
177 advance.fX = 0;
178 advance.fY = 0;
179
180 if (glyph >= 0xFFFE) {
181 return;
182 }
183
184 TT_Glyph_Metrics metrics;
185 TT_Error error;
186
187 error = TT_Load_Glyph(fInstance, fGlyph, glyph, TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
188
189 if (error != 0) {
190 return;
191 }
192
193 TT_Get_Glyph_Metrics(fGlyph, &metrics);
194
195 advance.fX = metrics.advance >> 6;
196 return;
197 }
198
199 le_bool GnomeFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const
200 {
201 TT_Outline outline;
202 TT_Error error;
203
204 error = TT_Load_Glyph(fInstance, fGlyph, glyph, TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
205
206 if (error != 0) {
207 return FALSE;
208 }
209
210 error = TT_Get_Glyph_Outline(fGlyph, &outline);
211
212 if (error != 0 || pointNumber >= outline.n_points) {
213 return FALSE;
214 }
215
216 point.fX = outline.points[pointNumber].x >> 6;
217 point.fY = outline.points[pointNumber].y >> 6;
218
219 return TRUE;
220 }
221
222 // This table was generated by a little Java program.
223 const char bitReverse[256] = {
224 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
225 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
226 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
227 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
228 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
229 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
230 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
231 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
232 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
233 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
234 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
235 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
236 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
237 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
238 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
239 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
240 };
241
242 // FIXME: this would be much faster if we cached the TT_Glyph objects based on the glyph ID...
243 TT_Raster_Map *GnomeFontInstance::rasterizeGlyphs(const LEGlyphID *glyphs, le_int32 glyphCount,
244 const le_int32 *dx, const le_int32 *dy, le_int32 &xOffset, le_int32 &yOffset) const
245 {
246 le_int32 i, xx = 0, yy = 0, zz;
247 le_int32 minx = 0, maxx = 0, miny = 0, maxy = 0;
248 TT_Raster_Map *raster = new TT_Raster_Map;
249 TT_Glyph_Metrics metrics;
250 TT_Error error;
251
252 for (i = 0; i < glyphCount; i += 1) {
253 error = TT_Load_Glyph(fInstance, fGlyph, (TT_UShort) LE_GET_GLYPH(glyphs[i]), TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
254 if (error == 0) {
255 TT_Get_Glyph_Metrics(fGlyph, &metrics);
256
257 zz = xx + metrics.bbox.xMin;
258 if (minx > zz) {
259 minx = zz;
260 }
261
262 zz = xx + metrics.bbox.xMax;
263 if (maxx < zz) {
264 maxx = zz;
265 }
266
267 yy = dy[i] * 64;
268 zz = yy + metrics.bbox.yMin;
269 if (miny > zz) {
270 miny = zz;
271 }
272
273 zz = yy + metrics.bbox.yMax;
274 if (maxy < zz) {
275 maxy = zz;
276 }
277 }
278
279 xx += (dx[i] * 64);
280 }
281
282
283 minx = (minx & -64) >> 6;
284 miny = (miny & -64) >> 6;
285
286 maxx = ((maxx + 63) & -64) >> 6;
287 maxy = ((maxy + 63) & -64) >> 6;
288
289 //printf("minx = %d, maxx = %d, miny = %d, maxy = %d\n", minx, maxx, miny, maxy);
290
291 unsigned char *bits;
292
293 raster->flow = TT_Flow_Down;
294 raster->width = maxx - minx;
295 raster->rows = maxy - miny;
296 raster->cols = (raster->width + 7) / 8;
297 raster->size = raster->cols * raster->rows;
298
299 raster->bitmap = bits = LE_NEW_ARRAY(unsigned char, raster->size);
300
301 for (i = 0; i < raster->size; i += 1) {
302 bits[i] = 0;
303 }
304
305 xx = (-minx) * 64; yy = (-miny) * 64;
306
307 for (i = 0; i < glyphCount; i += 1) {
308 if (glyphs[i] < 0xFFFE) {
309 error = TT_Load_Glyph(fInstance, fGlyph, (TT_UShort) LE_GET_GLYPH(glyphs[i]), TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);
310
311 if (error == 0) {
312 TT_Get_Glyph_Bitmap(fGlyph, raster, xx, yy + (dy[i] * 64));
313 }
314 }
315
316 xx += (dx[i] * 64);
317 }
318
319 for (i = 0; i < raster->size; i += 1) {
320 bits[i] = bitReverse[bits[i]];
321 }
322
323 xOffset = minx;
324 yOffset = maxy;
325
326 return raster;
327 }
328
329 void GnomeFontInstance::freeRaster(TT_Raster_Map *raster)
330 {
331 LE_DELETE_ARRAY(raster->bitmap);
332 delete raster;
333 }