1 /*
2 pygame - Python Game Library
3 Copyright (C) 2009 Vicent Marti
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 */
20
21 #define PYGAME_FREETYPE_INTERNAL
22
23 #include "ft_wrap.h"
24 #include FT_MODULE_H
25 #include FT_TRIGONOMETRY_H
26 #include FT_OUTLINE_H
27 #include FT_BITMAP_H
28 #include FT_CACHE_H
29
30 /* Multiply the font's x ppem by this factor to get the x strength
31 * factor in 16.16 Fixed.
32 */
33 #define FX16_WIDE_FACTOR (FX16_ONE / 12)
34
35 #define SLANT_FACTOR 0.22
36 static FT_Matrix slant_matrix = {
37 FX16_ONE, (FT_Fixed)(SLANT_FACTOR * FX16_ONE),
38 0, FX16_ONE
39 };
40
41 static FT_Matrix unit_matrix = {
42 FX16_ONE, 0,
43 0, FX16_ONE
44 };
45
46 typedef struct textcontext_ {
47 FT_Library lib;
48 FTC_FaceID id;
49 FT_Face font;
50 FTC_CMapCache charmap;
51 int do_transform;
52 FT_Matrix transform;
53 } TextContext;
54
55 #if 0
56 #define BOLD_STRENGTH_D (0.65)
57 #define PIXEL_SIZE ((FT_Fixed)64)
58 #define BOLD_STRENGTH ((FT_Fixed)(BOLD_STRENGTH_D * PIXEL_SIZE))
59 #define BOLD_ADVANCE (BOLD_STRENGTH * (FT_Fixed)4)
60 #endif
61 #define FX16_BOLD_FACTOR (FX16_ONE / 36)
62 #define UNICODE_SPACE ((PGFT_char)' ')
63
64 typedef enum {
65 UPDATE_NONE,
66 UPDATE_LAYOUT,
67 UPDATE_GLYPHS
68 } UpdateLevel_t;
69
70 /** render modes requiring glyph reloading and repositioning */
71 static const FT_UInt16 GLYPH_RENDER_FLAGS = (FT_RFLAG_ANTIALIAS |
72 FT_RFLAG_AUTOHINT |
73 FT_RFLAG_TRANSFORM |
74 FT_RFLAG_USE_BITMAP_STRIKES);
75 /** render modes requiring only glyph repositioning */
76 static const FT_UInt16 LAYOUT_RENDER_FLAGS = (FT_RFLAG_VERTICAL |
77 FT_RFLAG_HINTED |
78 FT_RFLAG_KERNING |
79 FT_RFLAG_PAD);
80 /** render styles requiring glyph reloading and repositioning */
81 static const FT_UInt16 GLYPH_STYLE_FLAGS = (FT_STYLE_OBLIQUE |
82 FT_STYLE_STRONG |
83 FT_STYLE_WIDE);
84
85 static FT_UInt32 get_load_flags(const FontRenderMode *);
86 static void fill_metrics(FontMetrics *, FT_Pos, FT_Pos,
87 FT_Vector *, FT_Vector *);
88 static void fill_context(TextContext *,
89 const FreeTypeInstance *,
90 const pgFontObject *,
91 const FontRenderMode *,
92 const FT_Face);
93 static int size_text(Layout *,
94 FreeTypeInstance *,
95 TextContext *,
96 const PGFT_String *);
97 static int load_glyphs(Layout *, TextContext *, FontCache *);
98 static void position_glyphs(Layout *);
99 static void fill_text_bounding_box(Layout *,
100 FT_Vector,
101 FT_Pos, FT_Pos, FT_Pos, FT_Pos, FT_Pos);
102 static UpdateLevel_t mode_compare(const FontRenderMode *,
103 const FontRenderMode *);
104 static int same_sizes(const Scale_t *, const Scale_t * );
105 static int same_transforms(const FT_Matrix *, const FT_Matrix *);
106 static void copy_mode(FontRenderMode *, const FontRenderMode *);
107
108
109 int
_PGFT_LayoutInit(FreeTypeInstance * ft,pgFontObject * fontobj)110 _PGFT_LayoutInit(FreeTypeInstance *ft, pgFontObject *fontobj)
111 {
112 Layout *ftext = &fontobj->_internals->active_text;
113 FontCache *cache = &fontobj->_internals->glyph_cache;
114
115 ftext->buffer_size = 0;
116 ftext->glyphs = 0;
117
118 if (_PGFT_Cache_Init(ft, cache)) {
119 PyErr_NoMemory();
120 return -1;
121 }
122
123 return 0;
124 }
125
126 void
_PGFT_LayoutFree(pgFontObject * fontobj)127 _PGFT_LayoutFree(pgFontObject *fontobj)
128 {
129 Layout *ftext = &(fontobj->_internals->active_text);
130 FontCache *cache = &fontobj->_internals->glyph_cache;
131
132 if (ftext->buffer_size > 0) {
133 _PGFT_free(ftext->glyphs);
134 ftext->glyphs = 0;
135 }
136 _PGFT_Cache_Destroy(cache);
137 }
138
139 Layout *
_PGFT_LoadLayout(FreeTypeInstance * ft,pgFontObject * fontobj,const FontRenderMode * mode,PGFT_String * text)140 _PGFT_LoadLayout(FreeTypeInstance *ft, pgFontObject *fontobj,
141 const FontRenderMode *mode, PGFT_String *text)
142 {
143 Layout *ftext = &fontobj->_internals->active_text;
144 FontCache *cache = &fontobj->_internals->glyph_cache;
145 UpdateLevel_t level = (text ?
146 UPDATE_GLYPHS : mode_compare(&ftext->mode, mode));
147 FT_Face font = 0;
148 TextContext context;
149
150 if (level != UPDATE_NONE) {
151 copy_mode(&ftext->mode, mode);
152 font = _PGFT_GetFontSized(ft, fontobj, mode->face_size);
153 if (!font) {
154 PyErr_SetString(pgExc_SDLError, _PGFT_GetError(ft));
155 return 0;
156 }
157 }
158
159 switch (level) {
160
161 case UPDATE_GLYPHS:
162 _PGFT_Cache_Cleanup(cache);
163 fill_context(&context, ft, fontobj, mode, font);
164 if (text) {
165 if (size_text(ftext, ft, &context, text)) {
166 return 0;
167 }
168 }
169 if (load_glyphs(ftext, &context, cache)) {
170 return 0;
171 }
172 /* fall through */
173
174 case UPDATE_LAYOUT:
175 position_glyphs(ftext);
176 break;
177
178 default:
179 assert(level == UPDATE_NONE);
180 break;
181 }
182
183 return ftext;
184 }
185
186 static int
size_text(Layout * ftext,FreeTypeInstance * ft,TextContext * context,const PGFT_String * text)187 size_text(Layout *ftext,
188 FreeTypeInstance *ft,
189 TextContext *context,
190 const PGFT_String *text)
191 {
192 FT_Face font = context->font;
193 const FT_Size_Metrics *sz_metrics = &font->size->metrics;
194 Py_ssize_t string_length = PGFT_String_GET_LENGTH(text);
195 const PGFT_char *chars = PGFT_String_GET_DATA(text);
196 FT_Fixed y_scale = sz_metrics->y_scale;
197 int have_kerning = FT_HAS_KERNING(font);
198 int length = 0;
199 GlyphSlot *slots;
200 GlyphIndex_t id;
201 GlyphIndex_t prev_id = 0;
202 FT_UInt32 ch;
203 Py_ssize_t i;
204 FT_Error error = 0;
205
206 assert(!(ftext->mode.render_flags & FT_RFLAG_KERNING) || have_kerning);
207
208 /* create the text struct */
209 if (string_length > ftext->buffer_size) {
210 _PGFT_free(ftext->glyphs);
211 ftext->glyphs = (GlyphSlot *)
212 _PGFT_malloc((size_t)string_length * sizeof(GlyphSlot));
213 if (!ftext->glyphs) {
214 PyErr_NoMemory();
215 return -1;
216 }
217 ftext->buffer_size = string_length;
218 }
219
220 /* Retrieve the glyph indices of recognized text characters */
221 slots = ftext->glyphs;
222 for (i = 0; i < string_length; ++i) {
223 ch = chars[i];
224 id = FTC_CMapCache_Lookup(context->charmap, context->id, -1, ch);
225 slots[length].id = id;
226 if (have_kerning) {
227 error = FT_Get_Kerning(font, prev_id, id, FT_KERNING_UNFITTED,
228 &slots[length].kerning);
229 if (error) {
230 _PGFT_SetError(ft, "Loading glyphs", error);
231 PyErr_SetString(pgExc_SDLError, _PGFT_GetError(ft));
232 return -1;
233 }
234 }
235 prev_id = id;
236 ++length;
237 }
238 ftext->length = length;
239
240 /* Fill in generate font parameters */
241 ftext->ascender = sz_metrics->ascender;
242 ftext->descender = sz_metrics->descender;
243 ftext->height = sz_metrics->height;
244 ftext->max_advance = sz_metrics->max_advance;
245 ftext->underline_pos = -FT_MulFix(font->underline_position, y_scale);
246 ftext->underline_size = FT_MulFix(font->underline_thickness, y_scale);
247 if (ftext->mode.style & FT_STYLE_STRONG) {
248 FT_Fixed bold_str = ftext->mode.strength * sz_metrics->x_ppem;
249
250 ftext->underline_size = FT_MulFix(ftext->underline_size,
251 FX16_ONE + bold_str / 4);
252 }
253 return 0;
254 }
255
256 static int
load_glyphs(Layout * ftext,TextContext * context,FontCache * cache)257 load_glyphs(Layout *ftext, TextContext *context, FontCache *cache)
258 {
259 GlyphSlot *slot = ftext->glyphs;
260 Py_ssize_t length = ftext->length;
261 FontRenderMode *mode = &ftext->mode;
262 FontGlyph *glyph;
263 Py_ssize_t i;
264
265 for (i = 0; i < length; ++i) {
266 glyph = _PGFT_Cache_FindGlyph(slot[i].id, mode, cache, context);
267 if (!glyph) {
268 PyErr_Format(pgExc_SDLError, "Unable to load glyph for id %lu",
269 (unsigned long)slot[i].id);
270 return -1;
271 }
272 slot[i].glyph = glyph;
273 }
274 return 0;
275 }
276
277 static void
position_glyphs(Layout * ftext)278 position_glyphs(Layout *ftext)
279 {
280 GlyphSlot *glyph_array = ftext->glyphs;
281 GlyphSlot *slot;
282 FontGlyph *glyph = 0;
283 Py_ssize_t n_glyphs = ftext->length;
284
285 FontMetrics *metrics;
286
287 FT_Vector pen = {0, 0}; /* untransformed origin */
288 FT_Vector pen1 = {0, 0};
289 FT_Vector pen2;
290
291 int vertical = ftext->mode.render_flags & FT_RFLAG_VERTICAL;
292 int use_kerning = ftext->mode.render_flags & FT_RFLAG_KERNING;
293
294 /* All these are 16.16 precision */
295 FT_Angle rotation_angle = ftext->mode.rotation_angle;
296
297 /* All these are 26.6 precision */
298 FT_Vector kerning;
299 FT_Pos min_x = FX6_MAX;
300 FT_Pos max_x = FX6_MIN;
301 FT_Pos min_y = FX6_MAX;
302 FT_Pos max_y = FX6_MIN;
303 FT_Pos glyph_width;
304 FT_Pos glyph_height;
305 FT_Pos top = FX6_MIN;
306
307 Py_ssize_t i;
308
309 assert(n_glyphs == 0 || glyph_array);
310
311 for (i = 0; i != n_glyphs; ++i) {
312 slot = &glyph_array[i];
313 glyph = slot->glyph;
314
315 pen2.x = pen1.x;
316 pen2.y = pen1.y;
317 pen1.x = pen.x;
318 pen1.y = pen.y;
319 glyph_width = glyph->width;
320 glyph_height = glyph->height;
321
322 /*
323 * Do size calculations for the glyph
324 */
325 if (use_kerning) {
326 kerning.x = slot->kerning.x;
327 kerning.y = slot->kerning.y;
328 if (rotation_angle != 0) {
329 FT_Vector_Rotate(&kerning, rotation_angle);
330 }
331 pen.x += FX6_ROUND(kerning.x);
332 pen.y += FX6_ROUND(kerning.y);
333 if (FT_Vector_Length(&pen2) > FT_Vector_Length(&pen)) {
334 pen.x = pen2.x;
335 pen.y = pen2.y;
336 }
337 }
338
339 metrics = vertical ? &glyph->v_metrics : &glyph->h_metrics;
340 if (metrics->bearing_rotated.y > top) {
341 top = metrics->bearing_rotated.y;
342 }
343 if (pen.x + metrics->bearing_rotated.x < min_x) {
344 min_x = pen.x + metrics->bearing_rotated.x;
345 }
346 if (pen.x + metrics->bearing_rotated.x + glyph_width > max_x) {
347 max_x = pen.x + metrics->bearing_rotated.x + glyph_width;
348 }
349 slot->posn.x = pen.x + metrics->bearing_rotated.x;
350 pen.x += metrics->advance_rotated.x;
351 if (vertical) {
352 if (pen.y + metrics->bearing_rotated.y < min_y) {
353 min_y = pen.y + metrics->bearing_rotated.y;
354 }
355 if (pen.y + metrics->bearing_rotated.y + glyph_height > max_y) {
356 max_y = pen.y + metrics->bearing_rotated.y + glyph_height;
357 }
358 slot->posn.y = pen.y + metrics->bearing_rotated.y;
359 pen.y += metrics->advance_rotated.y;
360 }
361 else {
362 if (pen.y - metrics->bearing_rotated.y < min_y) {
363 min_y = pen.y - metrics->bearing_rotated.y;
364 }
365 if (pen.y - metrics->bearing_rotated.y + glyph_height > max_y) {
366 max_y = pen.y - metrics->bearing_rotated.y + glyph_height;
367 }
368 slot->posn.y = pen.y - metrics->bearing_rotated.y;
369 pen.y -= metrics->advance_rotated.y;
370 }
371
372 }
373
374 /* Deal with the special case of a trailing space.
375 *
376 * In determining the bounding box of the text, the above loop omits
377 * the advance of the last character from the calculation. This is
378 * intensional. For a printing character with a bitmap, it avoids
379 * padding of the boundary. But a space is nothing but padding, so
380 * a trailing space gets left out. This adds it in.
381 */
382 if (n_glyphs > 0 && /* conditional && */
383 (glyph_array + n_glyphs - 1)->glyph->image->bitmap.width == 0) {
384 if (pen.x < min_x) {
385 min_x = pen.x;
386 }
387 else if (pen.x > max_x) {
388 max_x = pen.x;
389 }
390 if (pen.y < min_y) {
391 min_y = pen.y;
392 }
393 else if (pen.y > max_y) {
394 max_y = pen.y;
395 }
396 }
397
398 fill_text_bounding_box(ftext, pen, min_x, max_x, min_y, max_y, top);
399 }
400
401 static void
fill_text_bounding_box(Layout * ftext,FT_Vector pen,FT_Pos min_x,FT_Pos max_x,FT_Pos min_y,FT_Pos max_y,FT_Pos top)402 fill_text_bounding_box(Layout *ftext,
403 FT_Vector pen,
404 FT_Pos min_x, FT_Pos max_x,
405 FT_Pos min_y, FT_Pos max_y,
406 FT_Pos top)
407 {
408 const FT_Fixed BASELINE = FX6_ONE;
409 FT_Fixed right = ftext->max_advance / 2;
410 FT_Fixed ascender = ftext->ascender;
411 FT_Fixed descender = ftext->descender;
412 FT_Fixed height = ftext->height;
413 int vertical = ftext->mode.render_flags & FT_RFLAG_VERTICAL;
414 int pad = ftext->mode.render_flags & FT_RFLAG_PAD;
415
416 if (ftext->length == 0) {
417 min_x = 0;
418 max_x = 0;
419 min_y = vertical ? 0 : -ascender;
420 max_y = vertical ? height : -descender;
421 }
422
423 ftext->left = FX6_TRUNC(FX6_FLOOR(min_x));
424 ftext->top = FX6_TRUNC(FX6_CEIL(top));
425 if (pad) {
426 if (pen.x > max_x) {
427 max_x = pen.x;
428 }
429 else if (pen.x < min_x) {
430 min_x = pen.x;
431 }
432 if (pen.y > max_y) {
433 max_y = pen.y;
434 }
435 else if (pen.y < min_y) {
436 min_y = pen.y;
437 }
438 if (vertical) {
439 if (max_x < right) {
440 max_x = right;
441 }
442 if (min_x > -right) {
443 min_x = -right;
444 }
445 if (min_y > 0) {
446 min_y = 0;
447 }
448 }
449 else {
450 if (min_x > 0) {
451 min_x = 0;
452 }
453 if (min_y > -ascender) {
454 min_y = -ascender;
455 }
456 if (max_y <= -descender) {
457 max_y = -descender + BASELINE;
458 }
459 }
460 }
461 ftext->min_x = min_x;
462 ftext->max_x = max_x;
463 ftext->min_y = min_y;
464 ftext->max_y = max_y;
465 ftext->advance.x = pen.x;
466 ftext->advance.y = pen.y;
467 }
468
_PGFT_GetMetrics(FreeTypeInstance * ft,pgFontObject * fontobj,PGFT_char character,const FontRenderMode * mode,FT_UInt * gindex,long * minx,long * maxx,long * miny,long * maxy,double * advance_x,double * advance_y)469 int _PGFT_GetMetrics(FreeTypeInstance *ft, pgFontObject *fontobj,
470 PGFT_char character, const FontRenderMode *mode,
471 FT_UInt *gindex, long *minx, long *maxx,
472 long *miny, long *maxy,
473 double *advance_x, double *advance_y)
474 {
475 FontCache *cache = &(fontobj->_internals->glyph_cache);
476 FT_UInt32 ch = (FT_UInt32)character;
477 GlyphIndex_t id;
478 FontGlyph *glyph = 0;
479 TextContext context;
480 FT_Face font;
481
482 /* load our sized font */
483 font = _PGFT_GetFontSized(ft, fontobj, mode->face_size);
484 if (!font) {
485 return -1;
486 }
487
488 /* cleanup the cache */
489 _PGFT_Cache_Cleanup(cache);
490
491 fill_context(&context, ft, fontobj, mode, font);
492 id = FTC_CMapCache_Lookup(context.charmap, context.id, -1, ch);
493 if (!id) {
494 return -1;
495 }
496 glyph = _PGFT_Cache_FindGlyph(id, mode, cache, &context);
497 if (!glyph) {
498 return -1;
499 }
500
501 *gindex = id;
502 *minx = (long)glyph->image->left;
503 *maxx = (long)(glyph->image->left + glyph->image->bitmap.width);
504 *maxy = (long)glyph->image->top;
505 *miny = (long)(glyph->image->top - glyph->image->bitmap.rows);
506 *advance_x = (double)(glyph->h_metrics.advance_rotated.x / 64.0);
507 *advance_y = (double)(glyph->h_metrics.advance_rotated.y / 64.0);
508
509 return 0;
510 }
511
512 int
_PGFT_LoadGlyph(FontGlyph * glyph,GlyphIndex_t id,const FontRenderMode * mode,void * internal)513 _PGFT_LoadGlyph(FontGlyph *glyph, GlyphIndex_t id,
514 const FontRenderMode *mode, void *internal)
515 {
516 static FT_Vector delta = {0, 0};
517
518 FT_Render_Mode rmode = ((mode->render_flags & FT_RFLAG_ANTIALIAS) ?
519 FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
520 FT_Vector strong_delta = {0, 0};
521 FT_Glyph image = 0;
522
523 FT_Glyph_Metrics *ft_metrics;
524 TextContext *context = (TextContext *)internal;
525
526 FT_UInt32 load_flags;
527
528 FT_Fixed rotation_angle = mode->rotation_angle;
529 /* FT_Matrix transform; */
530 FT_Vector h_bearing_rotated;
531 FT_Vector v_bearing_rotated;
532 FT_Vector h_advance_rotated;
533 FT_Vector v_advance_rotated;
534
535 FT_Error error = 0;
536
537 /*
538 * Get loading information
539 */
540 load_flags = get_load_flags(mode);
541
542 /*
543 * Load the glyph into the glyph slot
544 */
545 if (FT_Load_Glyph(context->font, id, (FT_Int)load_flags) ||
546 FT_Get_Glyph(context->font->glyph, &image))
547 goto cleanup;
548
549 /*
550 * Perform any outline transformations
551 */
552 if (mode->style & FT_STYLE_STRONG) {
553 FT_UShort x_ppem = context->font->size->metrics.x_ppem;
554 FT_Fixed bold_str;
555 FT_BBox before;
556 FT_BBox after;
557
558 bold_str = FX16_CEIL_TO_FX6(mode->strength * x_ppem);
559 FT_Outline_Get_CBox(&((FT_OutlineGlyph)image)->outline, &before);
560 if (FT_Outline_Embolden(&((FT_OutlineGlyph)image)->outline, bold_str))
561 goto cleanup;
562 FT_Outline_Get_CBox(&((FT_OutlineGlyph)image)->outline, &after);
563 strong_delta.x += ((after.xMax - after.xMin) -
564 (before.xMax - before.xMin));
565 strong_delta.y += ((after.yMax - after.yMin) -
566 (before.yMax - before.yMin));
567 }
568
569 if (context->do_transform) {
570 if (FT_Glyph_Transform(image, &context->transform, &delta)) {
571 goto cleanup;
572 }
573 }
574
575 /*
576 * Finished with outline transformations, now replace with a bitmap
577 */
578 error = FT_Glyph_To_Bitmap(&image, rmode, 0, 1);
579 if (error) {
580 goto cleanup;
581 }
582
583 if (mode->style & FT_STYLE_WIDE) {
584 FT_Bitmap *bitmap = &((FT_BitmapGlyph)image)->bitmap;
585 int w = bitmap->width;
586 FT_UShort x_ppem = context->font->size->metrics.x_ppem;
587 FT_Pos x_strength;
588
589 x_strength = FX16_CEIL_TO_FX6(mode->strength * x_ppem);
590
591 /* FT_Bitmap_Embolden returns an error for a zero width bitmap */
592 if (w > 0) {
593 error = FT_Bitmap_Embolden(context->lib, bitmap,
594 x_strength, (FT_Pos)0);
595 if (error) {
596 goto cleanup;
597 }
598 strong_delta.x += INT_TO_FX6(bitmap->width - w);
599 }
600 else {
601 strong_delta.x += x_strength;
602 }
603 }
604
605 /* Fill the glyph */
606 ft_metrics = &context->font->glyph->metrics;
607
608 h_advance_rotated.x = ft_metrics->horiAdvance + strong_delta.x;
609 h_advance_rotated.y = 0;
610 v_advance_rotated.x = 0;
611 v_advance_rotated.y = ft_metrics->vertAdvance + strong_delta.y;
612 if (rotation_angle != 0) {
613 FT_Angle counter_rotation = INT_TO_FX16(360) - rotation_angle;
614 FT_Vector_Rotate(&h_advance_rotated, rotation_angle);
615 FT_Vector_Rotate(&v_advance_rotated, counter_rotation);
616 }
617
618 glyph->image = (FT_BitmapGlyph)image;
619 glyph->width = INT_TO_FX6(glyph->image->bitmap.width);
620 glyph->height = INT_TO_FX6(glyph->image->bitmap.rows);
621 h_bearing_rotated.x = INT_TO_FX6(glyph->image->left);
622 h_bearing_rotated.y = INT_TO_FX6(glyph->image->top);
623 fill_metrics(&glyph->h_metrics,
624 ft_metrics->horiBearingX,
625 ft_metrics->horiBearingY,
626 &h_bearing_rotated, &h_advance_rotated);
627
628 if (rotation_angle == 0) {
629 v_bearing_rotated.x = ft_metrics->vertBearingX - strong_delta.x / 2;
630 v_bearing_rotated.y = ft_metrics->vertBearingY;
631 }
632 else {
633 /*
634 * Adjust the vertical metrics.
635 */
636 FT_Vector v_origin;
637
638 v_origin.x = (glyph->h_metrics.bearing_x -
639 ft_metrics->vertBearingX + strong_delta.x / 2);
640 v_origin.y = (glyph->h_metrics.bearing_y +
641 ft_metrics->vertBearingY);
642 FT_Vector_Rotate(&v_origin, rotation_angle);
643 v_bearing_rotated.x = glyph->h_metrics.bearing_rotated.x - v_origin.x;
644 v_bearing_rotated.y = v_origin.y - glyph->h_metrics.bearing_rotated.y;
645 }
646 fill_metrics(&glyph->v_metrics,
647 ft_metrics->vertBearingX,
648 ft_metrics->vertBearingY,
649 &v_bearing_rotated, &v_advance_rotated);
650
651 return 0;
652
653 /*
654 * Cleanup on error
655 */
656 cleanup:
657 if (image) {
658 FT_Done_Glyph(image);
659 }
660
661 return -1;
662 }
663
664 static void
fill_context(TextContext * context,const FreeTypeInstance * ft,const pgFontObject * fontobj,const FontRenderMode * mode,const FT_Face font)665 fill_context(TextContext *context,
666 const FreeTypeInstance *ft,
667 const pgFontObject *fontobj,
668 const FontRenderMode *mode,
669 const FT_Face font)
670 {
671 context->lib = ft->library;
672 context->id = (FTC_FaceID)&(fontobj->id);
673 context->font = font;
674 context->charmap = ft->cache_charmap;
675 context->do_transform = 0;
676
677 if (mode->style & FT_STYLE_OBLIQUE) {
678 context->transform = slant_matrix;
679 context->do_transform = 1;
680 }
681 else {
682 context->transform = unit_matrix;
683 }
684
685 if (mode->render_flags & FT_RFLAG_TRANSFORM) {
686 FT_Matrix_Multiply(&mode->transform, &context->transform);
687 context->do_transform = 1;
688 }
689
690 if (mode->rotation_angle != 0) {
691 FT_Vector unit;
692 FT_Matrix rotate;
693
694 FT_Vector_Unit(&unit, mode->rotation_angle);
695 rotate.xx = unit.x; /* cos(angle) */
696 rotate.xy = -unit.y; /* -sin(angle) */
697 rotate.yx = unit.y; /* sin(angle) */
698 rotate.yy = unit.x; /* cos(angle) */
699 FT_Matrix_Multiply(&rotate, &context->transform);
700 context->do_transform = 1;
701 }
702 }
703
704 static void
fill_metrics(FontMetrics * metrics,FT_Pos bearing_x,FT_Pos bearing_y,FT_Vector * bearing_rotated,FT_Vector * advance_rotated)705 fill_metrics(FontMetrics *metrics,
706 FT_Pos bearing_x, FT_Pos bearing_y,
707 FT_Vector *bearing_rotated,
708 FT_Vector *advance_rotated)
709 {
710 metrics->bearing_x = bearing_x;
711 metrics->bearing_y = bearing_y;
712 metrics->bearing_rotated.x = bearing_rotated->x;
713 metrics->bearing_rotated.y = bearing_rotated->y;
714 metrics->advance_rotated.x = advance_rotated->x;
715 metrics->advance_rotated.y = advance_rotated->y;
716 }
717
718 static FT_UInt32
get_load_flags(const FontRenderMode * mode)719 get_load_flags(const FontRenderMode *mode)
720 {
721 FT_UInt32 load_flags = FT_LOAD_DEFAULT;
722
723 load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
724
725 if (mode->render_flags & FT_RFLAG_AUTOHINT) {
726 load_flags |= FT_LOAD_FORCE_AUTOHINT;
727 }
728
729 if (mode->render_flags & FT_RFLAG_HINTED) {
730 load_flags |= FT_LOAD_TARGET_NORMAL;
731 }
732 else {
733 load_flags |= FT_LOAD_NO_HINTING;
734 }
735
736 if (!(mode->render_flags & FT_RFLAG_USE_BITMAP_STRIKES) ||
737 (mode->render_flags & FT_RFLAG_TRANSFORM) ||
738 (mode->rotation_angle != 0) ||
739 (mode->style & (FT_STYLE_STRONG | FT_STYLE_OBLIQUE))) {
740 load_flags |= FT_LOAD_NO_BITMAP;
741 }
742
743 return load_flags;
744 }
745
746 static UpdateLevel_t
mode_compare(const FontRenderMode * a,const FontRenderMode * b)747 mode_compare(const FontRenderMode *a, const FontRenderMode *b)
748 {
749 FT_UInt16 a_sflags = a->style;
750 FT_UInt16 b_sflags = b->style;
751 FT_UInt16 a_rflags = a->render_flags;
752 FT_UInt16 b_rflags = b->render_flags;
753
754 if (!same_sizes(&a->face_size, &b->face_size) ||
755 a->rotation_angle != b->rotation_angle ||
756 (a_sflags & GLYPH_STYLE_FLAGS) != (b_sflags & GLYPH_STYLE_FLAGS) ||
757 (a_rflags & GLYPH_RENDER_FLAGS) != (b_rflags & GLYPH_RENDER_FLAGS) ||
758 ((a_rflags & FT_RFLAG_TRANSFORM) &&
759 !same_transforms(&a->transform, &b->transform))) {
760 return UPDATE_GLYPHS;
761 }
762 if ((a_rflags & LAYOUT_RENDER_FLAGS) != (b_rflags & LAYOUT_RENDER_FLAGS)) {
763 return UPDATE_LAYOUT;
764 }
765 return UPDATE_NONE;
766 }
767
768 static int
same_sizes(const Scale_t * a,const Scale_t * b)769 same_sizes(const Scale_t *a, const Scale_t *b)
770 {
771 return a->x == b->x && a->y == b->y;
772 }
773
774 static int
same_transforms(const FT_Matrix * a,const FT_Matrix * b)775 same_transforms(const FT_Matrix *a, const FT_Matrix *b)
776 {
777 return a->xx == b->xx && a->xy == b->xy && a->yx == b->yx && a->yy == b->yy;
778 }
779
780 static void
copy_mode(FontRenderMode * d,const FontRenderMode * s)781 copy_mode(FontRenderMode *d, const FontRenderMode *s)
782 {
783 memcpy(d, s, sizeof(FontRenderMode));
784 }
785