/* FreeType font driver for Haiku Copyright (C) 2021 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include #include "haiku_support.h" #include #include #include #include #include #include #include #include #include #include #include #include FT_FREETYPE_H #include FT_SIZES_H #include FT_BITMAP_H #include FT_IMAGE_H #include FT_OUTLINE_H #define FLOAT_FROM_26_6(t) ((float) (t) / 64.0f) #define DOUBLE_TO_16_16(d) ((FT_Fixed) ((d) * 65536.0)) #define VECTOR_POINT(v) (BPoint (FLOAT_FROM_26_6 ((v)->x), \ FLOAT_FROM_26_6 ((v)->y))) static int tx; static int mty; struct ftbe_shape_cache { std::unordered_map shapes; }; static int move_to (FT_Vector *to, void *closure) { BShape *shape = (BShape *) closure; return shape->MoveTo (VECTOR_POINT (to)) != B_OK; } static int line_to (FT_Vector *to, void *closure) { BShape *shape = (BShape *) closure; return shape->LineTo (VECTOR_POINT (to)) != B_OK; } static int conic_to (FT_Vector *control, FT_Vector *to, void *closure) { BShape *shape = (BShape *) closure; BPoint pt_0 = shape->CurrentPosition (); return shape->BezierTo (BPoint (pt_0.x + 2.0f / 3.0f * (FLOAT_FROM_26_6 (control->x) - pt_0.x), pt_0.y + 2.0f / 3.0f * (FLOAT_FROM_26_6 (control->y) - pt_0.y)), BPoint (FLOAT_FROM_26_6 (to->x) + 2.0f / 3.0f * (FLOAT_FROM_26_6 (control->x) - FLOAT_FROM_26_6 (to->x)), FLOAT_FROM_26_6 (to->y) + 2.0f / 3.0f * (FLOAT_FROM_26_6 (control->y) - FLOAT_FROM_26_6 (to->y))), VECTOR_POINT (to)) != B_OK; } static int cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure) { BShape *shape = (BShape *) closure; return shape->BezierTo (VECTOR_POINT (control1), VECTOR_POINT (control2), VECTOR_POINT (to)) != B_OK; } static int digest_outline (FT_Outline *outline, FT_Face face, BShape *shape) { static const FT_Matrix invert_y = { DOUBLE_TO_16_16 (1.0), 0, 0, DOUBLE_TO_16_16 (-1.0), }; static const FT_Outline_Funcs outline_funcs = { (FT_Outline_MoveToFunc) move_to, (FT_Outline_LineToFunc) line_to, (FT_Outline_ConicToFunc) conic_to, (FT_Outline_CubicToFunc) cubic_to, 0, 0 }; FT_Outline_Translate (outline, tx * 64.0, -mty * 64.0); FT_Outline_Transform (outline, &invert_y); if (FT_Outline_Decompose (outline, &outline_funcs, shape) != FT_Err_Ok) return 1; if (shape->Close () != B_OK) return 1; return 0; } extern "C" { extern void emacs_abort (void); } extern void be_free_ft_shape_cache (void *c) { for (const std::pair &pair : ((struct ftbe_shape_cache *) c)->shapes) delete pair.second; delete (struct ftbe_shape_cache *) c; } extern void * be_make_ft_shape_cache (void) { return new struct ftbe_shape_cache; } extern void BView_FT_render_glyphs (FT_Face face, unsigned int *codes, int len, uint32_t color, int x, int y, void *view, void *ft_shape_cache) { FT_Error error = FT_Err_Ok; BView *vw = (BView *) find_appropriate_view_for_draw (view); struct ftbe_shape_cache *c = (struct ftbe_shape_cache *) ft_shape_cache; BShape gshape; gshape.Clear (); tx = 0, mty = 0; if (len >= 5) { vw->MovePenTo (x, y); x = 0, y = 0; } BView_SetHighColor (view, color); for (int i = 0; i < len; ++i) { error = FT_Load_Glyph (face, codes[i], FT_LOAD_DEFAULT); if (error != FT_Err_Ok) continue; BShape *shape; if (len < 5) shape = c->shapes[codes[i]]; if (len >= 5) tx = x, mty = y; if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && (!shape || len >= 5)) { if (len < 5) { shape = new BShape (); shape->Clear (); } digest_outline (&face->glyph->outline, face, len >= 5 ? &gshape : shape); if (len < 5) c->shapes[codes[i]] = shape; } if (len < 5) { vw->MovePenTo (x, y); vw->FillShape (shape); } x += face->glyph->advance.x >> 6; y += face->glyph->advance.y >> 6; } if (len >= 5) vw->FillShape (&gshape); }