long _PGFT_Font_GetDescenderSized(FreeTypeInstance *ft, PgFontObject *fontobj, FT_UInt16 ptsize) { FT_Face font = _PGFT_GetFontSized(ft, fontobj, ptsize); if (!font) { RAISE(PyExc_RuntimeError, _PGFT_GetError(ft)); return 0; } return (long)FX6_TRUNC(FX6_FLOOR(font->size->metrics.descender)); }
long _PGFT_Font_GetGlyphHeightSized(FreeTypeInstance *ft, PgFontObject *fontobj, FT_UInt16 ptsize) { /* * Based on the SDL_ttf height calculation. */ FT_Face font = _PGFT_GetFontSized(ft, fontobj, ptsize); FT_Size_Metrics *metrics; if (!font) { RAISE(PyExc_RuntimeError, _PGFT_GetError(ft)); return 0; } metrics = &font->size->metrics; return (long)FX6_TRUNC(FX6_CEIL(metrics->ascender) - FX6_FLOOR(metrics->descender)) + /* baseline */ 1; }
int _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) { FontText *ftext = &(PGFT_INTERNALS(fontobj)->active_text); FontGlyph *glyph = 0; TextContext context; FT_Face font; /* load our sized font */ font = _PGFT_GetFontSized(ft, fontobj, mode->pt_size); if (!font) { return -1; } /* cleanup the cache */ _PGFT_Cache_Cleanup(&ftext->glyph_cache); fill_context(&context, ft, fontobj, mode, font); glyph = _PGFT_Cache_FindGlyph(character, mode, &PGFT_INTERNALS(fontobj)->active_text.glyph_cache, &context); if (!glyph) { return -1; } *gindex = glyph->glyph_index; *minx = (long)glyph->image->left; *maxx = (long)(glyph->image->left + glyph->image->bitmap.width); *maxy = (long)glyph->image->top; *miny = (long)(glyph->image->top - glyph->image->bitmap.rows); *advance_x = (double)(glyph->h_metrics.advance_rotated.x / 64.0); *advance_y = (double)(glyph->h_metrics.advance_rotated.y / 64.0); return 0; }
int _PGFT_BuildRenderMode(FreeTypeInstance *ft, PgFontObject *fontobj, FontRenderMode *mode, Scale_t face_size, int style, Angle_t rotation) { FT_Face font = 0; if (face_size.x == 0) { if (fontobj->face_size.x == 0) { PyErr_SetString(PyExc_ValueError, "No font point size specified" " and no default font size in typeface"); return -1; } face_size = fontobj->face_size; } mode->face_size = face_size; if (style == FT_STYLE_DEFAULT) { mode->style = fontobj->style; } else { if (_PGFT_CheckStyle((FT_UInt32)style)) { PyErr_SetString(PyExc_ValueError, "Invalid style value"); return -1; } mode->style = (FT_UInt16)style; } if ((mode->style & FT_STYLES_SCALABLE_ONLY) && !fontobj->is_scalable ) { PyErr_SetString(PyExc_ValueError, "Unsupported style(s) for a bitmap font"); return -1; } mode->strength = DBL_TO_FX16(fontobj->strength); mode->underline_adjustment = DBL_TO_FX16(fontobj->underline_adjustment); mode->render_flags = fontobj->render_flags; mode->rotation_angle = rotation; mode->transform = fontobj->transform; if (mode->rotation_angle != 0) { if (!fontobj->is_scalable) { PyErr_SetString(PyExc_ValueError, "rotated text is unsupported for a bitmap font"); return -1; } if (mode->style & FT_STYLE_WIDE) { PyErr_SetString(PyExc_ValueError, "the wide style is unsupported for rotated text"); return -1; } if (mode->style & FT_STYLE_UNDERLINE) { PyErr_SetString(PyExc_ValueError, "the underline style is unsupported for rotated text"); return -1; } if (mode->render_flags & FT_RFLAG_PAD) { PyErr_SetString(PyExc_ValueError, "padding is unsupported for rotated text"); return -1; } } if (mode->render_flags & FT_RFLAG_VERTICAL) { if (mode->style & FT_STYLE_UNDERLINE) { PyErr_SetString(PyExc_ValueError, "the underline style is unsupported for vertical text"); return -1; } } if (mode->render_flags & FT_RFLAG_KERNING) { font = _PGFT_GetFontSized(ft, fontobj, mode->face_size); PyErr_SetString(PyExc_SDLError, _PGFT_GetError(ft)); return -1; if (!FT_HAS_KERNING(font)) { mode->render_flags &= ~FT_RFLAG_KERNING; } } return 0; }
FontText * _PGFT_LoadFontText(FreeTypeInstance *ft, PgFontObject *fontobj, const FontRenderMode *mode, PGFT_String *text) { Py_ssize_t string_length = PGFT_String_GET_LENGTH(text); PGFT_char * buffer = PGFT_String_GET_DATA(text); PGFT_char * buffer_end; PGFT_char * ch; FontText *ftext = &(PGFT_INTERNALS(fontobj)->active_text); FontGlyph *glyph = 0; FontGlyph **glyph_array = 0; FontMetrics *metrics; FT_BitmapGlyph image; TextContext context; FT_Face font; FT_Size_Metrics *sz_metrics; FT_Vector pen = {0, 0}; /* untransformed origin */ FT_Vector pen1 = {0, 0}; FT_Vector pen2; FT_Vector *next_pos; int vertical = mode->render_flags & FT_RFLAG_VERTICAL; int use_kerning = mode->render_flags & FT_RFLAG_KERNING; int pad = mode->render_flags & FT_RFLAG_PAD; FT_UInt prev_glyph_index = 0; /* All these are 16.16 precision */ FT_Angle rotation_angle = mode->rotation_angle; /* All these are 26.6 precision */ FT_Vector kerning; FT_Pos min_x = FX6_MAX; FT_Pos max_x = FX6_MIN; FT_Pos min_y = FX6_MAX; FT_Pos max_y = FX6_MIN; FT_Pos glyph_width; FT_Pos glyph_height; FT_Pos top = FX6_MIN; FT_Fixed y_scale; FT_Error error = 0; /* load our sized font */ font = _PGFT_GetFontSized(ft, fontobj, mode->pt_size); if (!font) { PyErr_SetString(PyExc_SDLError, _PGFT_GetError(ft)); return 0; } sz_metrics = &font->size->metrics; y_scale = sz_metrics->y_scale; /* cleanup the cache */ _PGFT_Cache_Cleanup(&ftext->glyph_cache); /* create the text struct */ if (string_length > ftext->buffer_size) { _PGFT_free(ftext->glyphs); ftext->glyphs = (FontGlyph **) _PGFT_malloc((size_t)string_length * sizeof(FontGlyph *)); if (!ftext->glyphs) { PyErr_NoMemory(); return 0; } _PGFT_free(ftext->posns); ftext->posns = (FT_Vector *) _PGFT_malloc((size_t)string_length * sizeof(FT_Vector)); if (!ftext->posns) { PyErr_NoMemory(); return 0; } ftext->buffer_size = string_length; } ftext->length = string_length; ftext->ascender = sz_metrics->ascender; ftext->underline_pos = -FT_MulFix(font->underline_position, y_scale); ftext->underline_size = FT_MulFix(font->underline_thickness, y_scale); if (mode->style & FT_STYLE_STRONG) { FT_Fixed bold_str = mode->strength * sz_metrics->x_ppem; ftext->underline_size = FT_MulFix(ftext->underline_size, FX16_ONE + bold_str / 4); } /* fill it with the glyphs */ fill_context(&context, ft, fontobj, mode, font); glyph_array = ftext->glyphs; next_pos = ftext->posns; for (ch = buffer, buffer_end = ch + string_length; ch < buffer_end; ++ch) { pen2.x = pen1.x; pen2.y = pen1.y; pen1.x = pen.x; pen1.y = pen.y; /* * Load the corresponding glyph from the cache */ glyph = _PGFT_Cache_FindGlyph(*((FT_UInt32 *)ch), mode, &ftext->glyph_cache, &context); if (!glyph) { --ftext->length; continue; } image = glyph->image; glyph_width = glyph->width; glyph_height = glyph->height; /* * Do size calculations for all the glyphs in the text */ if (use_kerning && prev_glyph_index) { error = FT_Get_Kerning(font, prev_glyph_index, glyph->glyph_index, FT_KERNING_UNFITTED, &kerning); if (error) { _PGFT_SetError(ft, "Loading glyphs", error); PyErr_SetString(PyExc_SDLError, _PGFT_GetError(ft)); return 0; } if (rotation_angle != 0) { FT_Vector_Rotate(&kerning, rotation_angle); } pen.x += FX6_ROUND(kerning.x); pen.y += FX6_ROUND(kerning.y); if (FT_Vector_Length(&pen2) > FT_Vector_Length(&pen)) { pen.x = pen2.x; pen.y = pen2.y; } } prev_glyph_index = glyph->glyph_index; metrics = vertical ? &glyph->v_metrics : &glyph->h_metrics; if (metrics->bearing_rotated.y > top) { top = metrics->bearing_rotated.y; } if (pen.x + metrics->bearing_rotated.x < min_x) { min_x = pen.x + metrics->bearing_rotated.x; } if (pen.x + metrics->bearing_rotated.x + glyph_width > max_x) { max_x = pen.x + metrics->bearing_rotated.x + glyph_width; } next_pos->x = pen.x + metrics->bearing_rotated.x; pen.x += metrics->advance_rotated.x; if (vertical) { if (pen.y + metrics->bearing_rotated.y < min_y) { min_y = pen.y + metrics->bearing_rotated.y; } if (pen.y + metrics->bearing_rotated.y + glyph_height > max_y) { max_y = pen.y + metrics->bearing_rotated.y + glyph_height; } next_pos->y = pen.y + metrics->bearing_rotated.y; pen.y += metrics->advance_rotated.y; } else { if (pen.y - metrics->bearing_rotated.y < min_y) { min_y = pen.y - metrics->bearing_rotated.y; } if (pen.y - metrics->bearing_rotated.y + glyph_height > max_y) { max_y = pen.y - metrics->bearing_rotated.y + glyph_height; } next_pos->y = pen.y - metrics->bearing_rotated.y; pen.y -= metrics->advance_rotated.y; } *glyph_array++ = glyph; ++next_pos; } if (ftext->length == 0) { min_x = 0; max_x = 0; if (vertical) { ftext->min_y = 0; max_y = sz_metrics->height; } else { FT_Size_Metrics *sz_metrics = &font->size->metrics; min_y = -sz_metrics->ascender; max_y = -sz_metrics->descender; } } if (pad) { FT_Size_Metrics *sz_metrics = &font->size->metrics; if (pen.x > max_x) { max_x = pen.x; } else if (pen.x < min_x) { min_x = pen.x; } if (pen.y > max_y) { max_y = pen.y; } else if (pen.y < min_y) { min_y = pen.y; } if (vertical) { FT_Fixed right = sz_metrics->max_advance / 2; if (max_x < right) { max_x = right; } if (min_x > -right) { min_x = -right; } if (min_y > 0) { min_y = 0; } else if (max_y < pen.y) { max_y = pen.y; } } else { FT_Fixed ascender = sz_metrics->ascender; FT_Fixed descender = sz_metrics->descender; if (min_x > 0) { min_x = 0; } if (max_x < pen.x) { max_x = pen.x; } if (min_y > -ascender) { min_y = -ascender; } if (max_y <= -descender) { max_y = -descender + /* baseline */ FX6_ONE; } } } ftext->left = FX6_TRUNC(FX6_FLOOR(min_x)); ftext->top = FX6_TRUNC(FX6_CEIL(top)); ftext->min_x = min_x; ftext->max_x = max_x; ftext->min_y = min_y; ftext->max_y = max_y; ftext->advance.x = pen.x; ftext->advance.y = pen.y; return ftext; }