2 * Based on the code from the ft2.library from MorphOS and the ttf.library by
5 #include "ftglyphengine.h"
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
)
32 ge
->matrix
= ge
->shear_matrix
;
33 FT_Matrix_Multiply(&ge
->rotate_matrix
, &ge
->matrix
);
34 FT_Set_Transform(ge
->face
, &ge
->matrix
, NULL
);
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
);
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
],
60 return ge
->glyph_code
;
64 int SetInstance(FT_GlyphEngine
*ge
)
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
);
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
)
87 alt_point
= ge
->point_size
- 1;
88 ge
->corrected_upem
= ge
->face
->units_per_EM
;
94 if (ge
->metric_source
== METRIC_TYPOASCEND
||
95 ge
->metric_source
== METRIC_USWINASCEND
)
97 os2
= FT_Get_Sfnt_Table(ge
->face
, ft_sfnt_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
;
112 case METRIC_TYPOASCEND
: /* Typo */
113 yMax
= os2
->sTypoAscender
;
114 yMin
= os2
->sTypoDescender
;
117 case METRIC_USWINASCEND
: /* usWin */
118 yMax
= os2
->usWinAscent
;
119 yMin
= os2
->usWinDescent
;
122 case METRIC_CUSTOMBBOX
: /* custom bbox */
123 yMin
=(WORD
)ge
->metric_custom
;
124 yMax
=ge
->metric_custom
>> 16;
129 yMax
=ge
->face
->height
;
133 case METRIC_GLOBALBBOX
: /* global bbox */
134 yMin
=ge
->face
->bbox
.yMin
;
135 yMax
=ge
->face
->bbox
.yMax
;
139 D(bug("yMin %d yMax %d\n", yMin
, yMax
));
141 /* normalize, provide defaults for bad fonts */
144 /* not set, default */
145 yMin
=ge
->face
->bbox
.yMin
;
146 yMax
=ge
->face
->bbox
.yMax
;
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);
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 );
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
)
193 FT_Glyph_Metrics
*metrics
;
195 FT_Raster_Params params
;
197 struct GlyphMap
*GMap
= ge
->GMap
;
199 /* these two values indicate no glyph rendered */
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
,
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
));
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
));
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
;
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
));
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
, ¶ms
);
268 D(bug("Error rendering glyph %ld code = %ld.\n",
269 (LONG
)ge
->request_char
, (LONG
) error
));
270 FreeVec(bitmap
.buffer
);
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
);
288 if (GMap
->glm_X0
< 0)
290 D(bug("####### X0 < 0\n"));
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"));
311 /* horizontal pixels per EM square as 16.16 */
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
;
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
));
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
));
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
)
368 /*if(ge->cmap_index==NO_CMAP_SET)
370 //if(ChooseEncoding(ge)!=0)
375 if(ge
->request_char
>255) { /* out of range */
381 UnicodeToGlyphIndex(ge
);
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
);
388 RenderGlyph(ge
, glyph_8bits
);
392 set_last_error(ge
,OTERR_UnknownGlyph
);
396 /* odd ball glyph (includes SPACE, arrrgghhh) mimic bullet */
397 if (ge
->GMap
->glm_Width
== 0)
399 set_last_error(ge
,OTERR_UnknownGlyph
);
408 /* muck which has to do with opening a face */
409 static int OpenFace(FT_GlyphEngine
*ge
, char *new_ft_filename
)
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
);
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
);
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
)
460 /* switch files for family support if needed */
461 pick_bi
=engine
->bold_sig
+ engine
->italic_sig
;
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"));
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"));
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"));
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"));
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"));
526 /* just incase we slip through */
527 if(engine
->face_established
==FALSE
)
528 OpenFace(engine
,engine
->base_filename
);