revert between 56095 -> 55830 in arch
[AROS.git] / workbench / libs / freetype2 / glyph.c
blob5f4c735d2a0c0ff69f07e92c41a4d33304b99f6b
1 /*
2 * Based on the code from the ft2.library from MorphOS and the ttf.library by
3 * Richard Griffith
4 */
5 #include "ftglyphengine.h"
6 #include "glyph.h"
8 //#define DEBUG 1
9 #include <aros/debug.h>
10 #include <diskfont/oterrors.h>
11 #include <diskfont/glyph.h>
12 #include <exec/memory.h>
13 #include <clib/alib_protos.h>
15 /* convert freetype FT_F26Dot6 to Amiga FIXED */
16 #define F266toFX(x) (((x)<<10))
18 /* convert freetype FT_F26Dot6 to Integer */
19 //#define F266Round(x) (((x)+32>>6))
20 //#define F266Floor(x) (((x)>>6))
21 //#define F266Ceil(x) ((((x)+63)>>6))
22 #define F266Round(x) ((((x)+0x10000000+32)>>6)-0x00400000)
23 #define F266Floor(x) ((((x)+0x10000000)>>6)-0x00400000)
24 #define F266Ceil(x) ((((x)+0x10000000+63)>>6)-0x00400000)
26 void set_transform(FT_GlyphEngine *ge)
28 if (ge->do_shear)
30 if (ge->do_rotate)
32 ge->matrix = ge->shear_matrix;
33 FT_Matrix_Multiply(&ge->rotate_matrix, &ge->matrix);
34 FT_Set_Transform(ge->face, &ge->matrix, NULL);
36 else
37 FT_Set_Transform(ge->face, &ge->shear_matrix, NULL);
39 else if (ge->do_rotate)
40 FT_Set_Transform(ge->face, &ge->rotate_matrix, NULL);
41 else
42 FT_Set_Transform(ge->face, NULL, NULL);
46 int char_to_glyph(FT_GlyphEngine *ge,int charcode)
48 return FT_Get_Char_Index(ge->face, charcode & 0xffffff00 ? charcode : ge->codepage[charcode]);
52 int UnicodeToGlyphIndex(FT_GlyphEngine *ge)
54 ge->glyph_code = FT_Get_Char_Index(ge->face,
55 ge->request_char & 0xffffff00 ? ge->request_char : ge->codepage[ge->request_char]);
56 D(bug("Unicode(%d)=index(%d)=%d\n", ge->request_char,
57 ge->request_char & 0xffffff00 ? ge->request_char : ge->codepage[ge->request_char],
58 ge->glyph_code));
60 return ge->glyph_code;
64 int SetInstance(FT_GlyphEngine *ge)
66 FT_Error error;
67 long yMin, yMax, alt_point, a, d;
69 /* set instance characteristics */
70 error = FT_Set_Char_Size( ge->face, 0, ge->point_size * 64, ge->xres, ge->yres );
71 if (error)
73 D(bug("Could not set resolution.\n"));
74 return set_last_error(ge,OTERR_Failure);
77 D(bug("units_per_EM %d metric source %d\n", ge->face->units_per_EM, ge->metric_source));
79 ge->corrected_upem = ge->face->units_per_EM;
81 /* adjust point size according to chosen metric source
82 * each has pros and cons, so user gets to decide
84 if(ge->metric_source==METRIC_RAW_EM)
86 /* (nearly) raw em */
87 alt_point = ge->point_size - 1;
88 ge->corrected_upem = ge->face->units_per_EM;
90 else
92 TT_OS2 *os2 = NULL;
94 if (ge->metric_source == METRIC_TYPOASCEND ||
95 ge->metric_source == METRIC_USWINASCEND)
97 os2 = FT_Get_Sfnt_Table(ge->face, ft_sfnt_os2);
98 if (!os2)
100 D(bug("No os2 table\n"));
101 ge->metric_source = METRIC_GLOBALBBOX;
105 switch(ge->metric_source)
107 case METRIC_ASCEND: /* Horizontal Header */
108 yMax = ge->face->ascender;
109 yMin = ge->face->descender;
110 break;
112 case METRIC_TYPOASCEND: /* Typo */
113 yMax = os2->sTypoAscender;
114 yMin = os2->sTypoDescender;
115 break;
117 case METRIC_USWINASCEND: /* usWin */
118 yMax = os2->usWinAscent;
119 yMin = os2->usWinDescent;
120 break;
122 case METRIC_CUSTOMBBOX: /* custom bbox */
123 yMin=(WORD)ge->metric_custom;
124 yMax=ge->metric_custom >> 16;
125 break;
127 case METRIC_BMSIZE:
128 yMin=0;
129 yMax=ge->face->height;
130 break;
132 default:
133 case METRIC_GLOBALBBOX: /* global bbox */
134 yMin=ge->face->bbox.yMin;
135 yMax=ge->face->bbox.yMax;
136 break;
139 D(bug("yMin %d yMax %d\n", yMin, yMax));
141 /* normalize, provide defaults for bad fonts */
142 if(yMax==0)
144 /* not set, default */
145 yMin=ge->face->bbox.yMin;
146 yMax=ge->face->bbox.yMax;
148 if(yMin>0)
149 yMin = -yMin;
151 D(bug("yMin %d yMax %d\n", yMin, yMax));
153 /* split min/max to whole units on each side of baseline */
154 ge->corrected_upem = yMax-yMin;
156 D(bug("corrected_upem %d\n", ge->corrected_upem));
158 alt_point = (ge->face->units_per_EM * ge->point_size) / (yMax-yMin);
160 a= alt_point * yMax / (yMax-yMin);
161 d= alt_point * (0-yMin) / (yMax-yMin);
162 alt_point = alt_point - (alt_point - a - d);
165 D(bug("alt_point %d\n", alt_point));
167 error = FT_Set_Pixel_Sizes(ge->face, alt_point, 0);
168 if (error)
170 D(bug("Could not set point size.\n"));
171 return set_last_error(ge,OTERR_Failure);
174 //FT_Get_Instance_Metrics(ge->instance, &ge->imetrics );
176 set_transform(ge);
178 ge->instance_changed=FALSE;
180 //FT_Select_Charmap(ge->face, ft_encoding_unicode);
181 //ChooseEncoding(ge);
183 return set_last_error(ge,OTERR_Success);
186 /* render a glyph into GMap of engine
187 caller is expected to have allocated GMap space (but not bitmap)
189 void RenderGlyph(FT_GlyphEngine *ge, int glyph_8bits)
191 FT_Error error;
192 FT_Vector offset;
193 FT_Glyph_Metrics *metrics;
194 FT_Bitmap bitmap;
195 FT_Raster_Params params;
196 FT_BBox bbox;
197 struct GlyphMap *GMap = ge->GMap;
199 /* these two values indicate no glyph rendered */
200 GMap->glm_Width = 0;
201 GMap->glm_BitMap = NULL;
203 D(bug("RenderGlyph(%d, %d, %d)\n", ge->request_char, ge->glyph_code, glyph_8bits));
205 error = FT_Load_Glyph(ge->face,
206 ge->glyph_code,
207 FT_LOAD_NO_BITMAP);
208 /*TTLOAD_SCALE_GLYPH); */ /* test disable hinting */
210 if(error || ge->face->glyph->format != ft_glyph_format_outline)
212 D(bug("Error loading glyph %ld code = %ld.\n",
213 (LONG)ge->request_char, (LONG)error ));
214 return;
217 FT_Outline_Get_CBox(&ge->face->glyph->outline, &bbox);
219 metrics = &ge->face->glyph->metrics;
221 /* how big is glyph */
222 bitmap.width = F266Ceil(bbox.xMax) - F266Floor(bbox.xMin);
223 bitmap.rows = F266Ceil(bbox.yMax) - F266Floor(bbox.yMin);
225 D(bug("BBox %f %f %f %f bitmap %d×%d\n",
226 bbox.xMin/64.0, bbox.yMin/64.0, bbox.xMax/64.0, bbox.yMax/64.0,
227 bitmap.width, bitmap.rows));
229 if (glyph_8bits)
231 bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
232 bitmap.pitch = bitmap.width;
233 bitmap.num_grays = 256;
234 params.flags = FT_RASTER_FLAG_AA;
236 else
238 /* adjust bitmap to 4 byte (32 bit) alignment for width */
239 bitmap.width = (bitmap.width + 31) & ~31;
240 bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
241 bitmap.pitch = bitmap.width >> 3; /* byte count */
242 params.flags = FT_RASTER_FLAG_DEFAULT;
245 /*bitmap.bitmap= AllocPooled(ge->GlyphPool,(ULONG)bitmap.size); */
247 /* stegerg: Always add 1 to allocation size to prevent debugging tools
248 to warn about AllocVec(0) calls */
250 bitmap.buffer = AllocVec(bitmap.rows*bitmap.pitch+1, MEMF_PUBLIC | MEMF_CLEAR);
252 if (bitmap.buffer == NULL)
254 D(bug("bitmap allocation for %ld bytes failed\n", bitmap.rows*bitmap.pitch));
255 return;
258 offset.x = -F266Floor(bbox.xMin) << 6;
259 offset.y = -F266Floor(bbox.yMin) << 6;
261 FT_Outline_Translate(&ge->face->glyph->outline, offset.x, offset.y);
263 params.target = &bitmap;
265 error = FT_Outline_Render(ge->engine, &ge->face->glyph->outline, &params);
266 if(error)
268 D(bug("Error rendering glyph %ld code = %ld.\n",
269 (LONG)ge->request_char, (LONG) error ));
270 FreeVec(bitmap.buffer);
271 return;
274 GMap->glm_BMModulo = bitmap.pitch;
275 GMap->glm_BMRows = bitmap.rows;
276 GMap->glm_BlackLeft = 0;
277 GMap->glm_BlackTop = 0;
278 GMap->glm_BlackWidth = F266Ceil(bbox.xMax) - F266Floor(bbox.xMin);
279 GMap->glm_BlackHeight = bitmap.rows;
280 GMap->glm_XOrigin = F266toFX(-bbox.xMin);
281 GMap->glm_YOrigin = F266toFX(bbox.yMax);
282 GMap->glm_X0 = offset.x >> 6;//F266Ceil(-bbox.xMin);
283 GMap->glm_Y0 = F266Ceil(bbox.yMax);
284 GMap->glm_X1 = F266Ceil(ge->face->glyph->advance.x - bbox.xMin);
285 GMap->glm_Y1 = F266Ceil(-ge->face->glyph->advance.y + bbox.yMax);
287 #if 0
288 if (GMap->glm_X0 < 0)
290 D(bug("####### X0 < 0\n"));
291 GMap->glm_X0 = 0;
293 if (GMap->glm_X0 > GMap->glm_BlackWidth)
295 D(bug("####### X0 > W\n"));
296 GMap->glm_X0 = GMap->glm_BlackWidth;
298 if (GMap->glm_Y0 >= GMap->glm_BlackHeight)
300 D(bug("####### Y0 > H\n"));
301 GMap->glm_Y0 = GMap->glm_BlackHeight -1;
302 GMap->glm_Y1 = GMap->glm_BlackHeight -1;
304 if (GMap->glm_Y0 < 0)
306 D(bug("####### Y0 < 0\n"));
307 GMap->glm_Y0 = 0;
309 #endif
311 /* horizontal pixels per EM square as 16.16 */
312 GMap->glm_Width =
313 (metrics->horiAdvance << 10) /
314 (( ge->face->size->metrics.x_ppem
315 * ge->corrected_upem)
316 / ge->face->units_per_EM);
319 GMap->glm_BitMap = bitmap.buffer;
321 #if 0
322 D(bug("render glyph %ld to %ld\n",(LONG)ge->glyph_code,(LONG)ge->request_char));
324 //D(bug(" bbox.xMin=%lx ",(LONG)ge->metrics.bbox.xMin));
325 //D(bug("bbox.yMin=%lx ",(LONG)ge->metrics.bbox.yMin));
326 //D(bug("bbox.xMax=%lx ",(LONG)ge->metrics.bbox.xMax));
327 //D(bug("bbox.yMax=%lx\n",(LONG)ge->metrics.bbox.yMax));
329 D(bug(" horiBearingX=%lx ",(LONG)metrics->horiBearingX));
330 D(bug("horiBearingY=%lx\n",(LONG)metrics->horiBearingY));
332 D(bug(" vertBearingX=%lx ",(LONG)metrics->vertBearingX));
333 D(bug("vertBearingY=%lx\n",(LONG)metrics->vertBearingY));
335 D(bug(" horiAdvance=%lx ",(LONG)metrics->horiAdvance));
336 D(bug("vertAdvance=%lx\n",(LONG)metrics->vertAdvance));
337 #endif
338 #if 1
339 D(bug(" glm_BMModulo = %lx\n",(LONG)GMap->glm_BMModulo));
340 D(bug(" glm_BMRows = %lx\n",(LONG)GMap->glm_BMRows));
341 D(bug(" glm_BlackLeft = %lx\n",(LONG)GMap->glm_BlackLeft));
342 D(bug(" glm_BlackTop = %lx\n",(LONG)GMap->glm_BlackTop));
343 D(bug(" glm_BlackWidth = %lx\n",(LONG)GMap->glm_BlackWidth));
344 D(bug(" glm_BlackHeight = %lx\n",(LONG)GMap->glm_BlackHeight));
346 D(bug(" glm_XOrigin = %lx\n",(LONG)GMap->glm_XOrigin));
347 D(bug(" glm_YOrigin = %lx\n",(LONG)GMap->glm_YOrigin));
348 D(bug(" glm_X0 = %lx\n",(LONG)GMap->glm_X0));
349 D(bug(" glm_Y0 = %lx\n",(LONG)GMap->glm_Y0));
351 D(bug(" glm_X1 = %lx\n",(LONG)GMap->glm_X1));
352 D(bug(" glm_Y1 = %lx\n",(LONG)GMap->glm_Y1));
353 D(bug(" glm_Width = %lx\n",(LONG)GMap->glm_Width));
354 #endif
358 /* given an Amiga character, return a filled in GlyphMap */
359 struct GlyphMap *GetGlyph(FT_GlyphEngine *ge, int glyph_8bits)
361 if (ge->instance_changed)
363 /* reset everything first */
364 if(SetInstance(ge)!=OTERR_Success)
365 return NULL;
368 /*if(ge->cmap_index==NO_CMAP_SET)
370 //if(ChooseEncoding(ge)!=0)
371 return NULL;
374 #if 0
375 if(ge->request_char>255) { /* out of range */
376 XeroGlyph(ge);
377 return ge->GMap;
379 #endif
381 UnicodeToGlyphIndex(ge);
382 if(ge->glyph_code)
383 { /* has code, try to render */
384 /* first, get a GlyphMap structure to fill in */
385 ge->GMap=AllocVec((ULONG)sizeof(struct GlyphMap),
386 MEMF_PUBLIC | MEMF_CLEAR);
387 if(ge->GMap)
388 RenderGlyph(ge, glyph_8bits);
390 else
392 set_last_error(ge,OTERR_UnknownGlyph);
393 return NULL;
396 /* odd ball glyph (includes SPACE, arrrgghhh) mimic bullet */
397 if (ge->GMap->glm_Width == 0)
399 set_last_error(ge,OTERR_UnknownGlyph);
400 FreeVec(ge->GMap);
401 ge->GMap = NULL;
402 return NULL;
405 return ge->GMap;
408 /* muck which has to do with opening a face */
409 static int OpenFace(FT_GlyphEngine *ge, char *new_ft_filename)
411 FT_Error error;
413 ge->instance_changed=TRUE; /* instance needs to be changed */
415 if(ge->face_established)
417 /* we have an existing face, if same file keep it */
418 if(stricmp(ge->ft_filename,new_ft_filename)==0)
419 return set_last_error(ge,OTERR_Success);
421 /* it is different, free the old one first */
422 FT_Done_Face( ge->face );
423 //ge->KernPairs = -1;
426 ge->face_established=FALSE;
428 strcpy(ge->ft_filename,new_ft_filename);
429 D(bug("OpenFace %ls.\n",ge->ft_filename));
431 error = FT_New_Face(ge->engine, ge->ft_filename, ge->face_num, &ge->face);
432 if (error)
434 D(bug("Error while opening %s, error code = %lx.\n",
435 ge->ft_filename, (LONG)error));
436 return set_last_error(ge,OTERR_BadFace);
439 if (ge->afm_filename[0])
441 error = FT_Attach_File(ge->face, ge->afm_filename);
442 if (error)
444 D(bug("Error %d while attaching %s\n", error, ge->afm_filename));
445 FT_Done_Face(ge->face);
446 return set_last_error(ge,OTERR_BadFace);
450 ge->face_established=TRUE;
452 return set_last_error(ge,OTERR_Success);
455 void switch_family(FT_GlyphEngine *engine)
457 #if 0
458 int pick_bi;
460 /* switch files for family support if needed */
461 pick_bi=engine->bold_sig + engine->italic_sig;
463 switch(pick_bi)
465 case 0: /* normal */
466 /* make sure we are set to base name */
467 if(strcmp(engine->base_filename,engine->ft_filename))
469 OpenFace(engine,engine->base_filename);
470 D(bug("switch_family: revert to base\n"));
472 break;
474 case 1: /* just italic */
475 if(strlen(engine->italic_filename))
477 if(strcmp(engine->italic_filename,engine->ft_filename))
479 OpenFace(engine,engine->italic_filename);
480 D(bug("switch_family: set italic\n"));
482 engine->do_shear=0;
484 break;
486 case 2: /* just bold */
487 if(strlen(engine->bold_filename))
489 if(strcmp(engine->bold_filename,engine->ft_filename))
491 OpenFace(engine,engine->bold_filename);
492 D(bug("switch_family: set bold\n"));
494 engine->do_embold=0;
496 break;
498 case 3: /* bold and italic */
499 if(strlen(engine->bold_italic_filename))
501 if(strcmp(engine->bold_italic_filename,engine->ft_filename))
503 OpenFace(engine,engine->bold_italic_filename);
504 D(bug("switch_family: set bold italic\n"));
506 engine->do_shear=0;
507 engine->do_embold=0;
509 else
510 { /* no file, choose other as basis? */
511 /* we have a bold, use it and keep transform */
512 if(strlen(engine->bold_filename))
514 if(strcmp(engine->bold_filename,engine->ft_filename))
516 OpenFace(engine,engine->bold_filename);
517 D(bug("switch_family: set bold, algo italic\n"));
519 engine->do_embold=0;
522 break;
524 #endif
526 /* just incase we slip through */
527 if(engine->face_established==FALSE)
528 OpenFace(engine,engine->base_filename);
530 return;