microvg  7.0.0
microvg
vg_freetype_path.c
Go to the documentation of this file.
1 /*
2  * C
3  *
4  * Copyright 2020-2024 MicroEJ Corp. All rights reserved.
5  * Use of this source code is governed by a BSD-style license that can be found with this software.
6  */
7 
15 // -----------------------------------------------------------------------------
16 // Includes
17 // -----------------------------------------------------------------------------
18 
19 #include "vg_configuration.h"
20 
21 #if defined VG_FEATURE_FONT && (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_VECTOR)
22 
23 #include <math.h>
24 
25 #include <freetype/internal/ftobjs.h>
26 #include <freetype/ftcolor.h>
27 #include "ftvector/ftvector.h"
28 
29 #include <LLVG_FONT_impl.h>
30 #include <LLVG_PATH_impl.h>
31 #include <LLVG_GRADIENT_impl.h>
32 #include <LLVG_MATRIX_impl.h>
33 #include <sni.h>
34 
35 #include "vg_freetype.h"
36 #include "vg_helper.h"
37 #include "bsp_util.h"
38 
39 // -----------------------------------------------------------------------------
40 // Macros and Defines
41 // -----------------------------------------------------------------------------
42 
43 #define FT_COLOR_TO_INT(x) (*((int *)&(x)))
44 
45 #define DIRECTION_CLOCK_WISE 0
46 
47 // -----------------------------------------------------------------------------
48 // Extern Variables
49 // -----------------------------------------------------------------------------
50 
51 extern FT_Library library;
52 extern FT_Renderer renderer;
53 
54 // -----------------------------------------------------------------------------
55 // Internal functions
56 // -----------------------------------------------------------------------------
57 
58 /*
59  * @brief Computes the scale to apply to the font.
60  *
61  * @param[in] size: the font size
62  * @param[in] face: the face of the font
63  */
64 static inline float __get_scale(jfloat size, FT_Face face) {
65  return size / face->units_per_EM;
66 }
67 
68 /*
69  * @brief Sets renderer parameters.
70  */
71 static void __set_renderer(FTVECTOR_draw_glyph_data_t *data) {
72  FT_Parameter params[1];
73 
74  params[0].tag = FT_PARAM_TAG_DRAWER;
75  // cppcheck-suppress [misra-c2012-11.1] pointer conversion to store the drawer
76  params[0].data = (void *)data;
77 
78  FT_Set_Renderer(library, renderer, 1, &params[0]);
79 }
80 
81 /*
82  * @brief Updates the angle to use for the next glyph when drawn on an arc.
83  * When drawing on an arc, the glyph position is defined by its angle. We thus
84  * convert the advance (distance to the next glyph) to an angle.
85  */
86 static float __get_angle(float advance, float radius) {
87  float angle = advance / radius;
88  angle *= 180.0f;
89  angle /= M_PI;
90  return angle;
91 }
92 
103 static FT_Error __render_glyph(FT_Face face, FT_UInt glyph_index, FT_Color *palette,
104  FTVECTOR_draw_glyph_data_t *drawer_data) {
105  FT_Error error = FT_ERR(Ok);
106 
107  uint32_t default_color = drawer_data->color;
108  FT_UInt layer_glyph_index;
109  FT_UInt layer_color_index;
110  FT_LayerIterator iterator;
111  iterator.p = NULL;
112 
113  FT_Bool have_layers = palette && FT_Get_Color_Glyph_Layer(face, glyph_index, &layer_glyph_index, &layer_color_index,
114  &iterator);
115 
116  do {
117  if (have_layers) {
118  // Update renderer color with layer_color
119  if (layer_color_index != 0xFFFF) {
120  drawer_data->color = VG_FREETYPE_IMPL_convert_color(FT_COLOR_TO_INT(palette[layer_color_index]));
121  }
122  } else {
123  // Use main glyph_index as layer_glyph_index
124  layer_glyph_index = glyph_index;
125  }
126 
127  if (layer_glyph_index != glyph_index) {
128  error = FT_Load_Glyph(face, layer_glyph_index, FT_LOAD_NO_SCALE);
129  }
130 
131  if (FT_ERR(Ok) == error) {
132  // convert to an anti-aliased bitmap
133  error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
134  } else {
135  MEJ_LOG_ERROR_MICROVG("Error while loading glyphid %d: 0x%x, refer to fterrdef.h\n", layer_glyph_index,
136  error);
137  }
138  }while ((layer_glyph_index != glyph_index) && (FT_ERR(Ok) == error) && (FT_ERR(Ok) != FT_Get_Color_Glyph_Layer(face,
139  glyph_index,
140  &
141  layer_glyph_index,
142  &
143  layer_color_index,
144  &
145  iterator)));
146 
147  // Revert renderer color to original color in case it has been modified.
148  drawer_data->color = default_color;
149 
150  return error;
151 }
152 
153 // -----------------------------------------------------------------------------
154 // vg_freetype.h painter functions
155 // -----------------------------------------------------------------------------
156 
157 // See the header file for the function documentation
158 jint VG_FREETYPE_draw_string(VG_FREETYPE_draw_glyph_t drawer, const jchar *text, jint length, jint faceHandle,
159  jfloat size, const jfloat *matrix, uint32_t color, jfloat letterSpacing, jfloat radius,
160  jint direction, void *user_data) {
161  jint result = LLVG_SUCCESS;
162 
163  if (0 < length) {
164  FT_Face face = (FT_Face)faceHandle;
165  FT_Color *palette;
166 
167  // Select palette
168  if (0 != FT_Palette_Select(face, 0, &palette)) {
169  palette = NULL;
170  }
171 
172  float scale = __get_scale(size, face);
173  float letterSpacingScaled = letterSpacing / scale;
174  float radiusScaled = radius / scale;
175  short baselineposition = face->ascender;
176 
177  // transformation to apply on all glyphs
178  float scaled_matrix[LLVG_MATRIX_SIZE];
179  LLVG_MATRIX_IMPL_copy(scaled_matrix, matrix);
180  LLVG_MATRIX_IMPL_scale(scaled_matrix, scale, scale);
181 
182  float working_matrix[LLVG_MATRIX_SIZE];
183  LLVG_MATRIX_IMPL_copy(working_matrix, scaled_matrix); // TODO Is it necessary?
184 
185  FTVECTOR_draw_glyph_data_t drawer_data;
186  drawer_data.drawer = drawer;
187  drawer_data.matrix = working_matrix;
188  drawer_data.color = color;
189  drawer_data.user_data = user_data;
190 
191  // give drawing parameters to freetype
192  __set_renderer(&drawer_data);
193 
194  int glyph_index; // current glyph index
195  int glyph_offset_y;
196  int glyph_advance_x;
197  int glyph_advance_y;
198  int glyph_offset_x;
199  int advance_x = 0;
200  int advance_y = 0;
201  int previous_glyph_index = 0; // previous glyph index for kerning
202 
203  VG_HELPER_layout_configure(faceHandle, text, length);
204 
205  while ((LLVG_SUCCESS == result) && (VG_HELPER_layout_load_glyph(&glyph_index, &glyph_advance_x,
206  &glyph_advance_y, &glyph_offset_x,
207  &glyph_offset_y))) {
208  // At that point the current glyph has been loaded by Freetype
209 
210  int charWidth = glyph_advance_x;
211 
212  if (0 == previous_glyph_index) {
213  // first glyph: remove the first blank line
214  if (0 == face->glyph->metrics.width) {
215  advance_x -= charWidth;
216  } else {
217  advance_x -= face->glyph->metrics.horiBearingX;
218  }
219  }
220 
221  // reset drawer's matrix
222  LLVG_MATRIX_IMPL_copy(working_matrix, scaled_matrix);
223 
224  if (0.f == radius) {
225  LLVG_MATRIX_IMPL_translate(working_matrix, advance_x + glyph_offset_x,
226  baselineposition + advance_y + glyph_offset_y);
227  } else {
228  float sign = (DIRECTION_CLOCK_WISE != direction) ? -1.f : 1.f;
229 
230  // Space characters joining bboxes at baseline
231  float angleDegrees = 90 + __get_angle(advance_x + glyph_offset_x,
232  radiusScaled) + __get_angle(charWidth / 2, radiusScaled);
233 
234  // Rotate to angle
235  LLVG_MATRIX_IMPL_rotate(working_matrix, sign * angleDegrees);
236 
237  // Translate left to center of bbox
238  // Translate baseline over circle
239  LLVG_MATRIX_IMPL_translate(working_matrix, -charWidth / 2, -sign * radiusScaled);
240  }
241 
242  // Draw the glyph
243  FT_Error error = __render_glyph(face, glyph_index, palette, &drawer_data);
244  if (FT_ERR(Ok) != error) {
245  MEJ_LOG_ERROR_MICROVG("Error while rendering glyphid %d: 0x%x, refer to fterrdef.h\n", glyph_index,
246  error);
247  result = (FT_ERR(Out_Of_Memory) == error) ? LLVG_OUT_OF_MEMORY : LLVG_DATA_INVALID;
248  continue;
249  }
250 
251  // Compute advance to next glyph
252  advance_x += charWidth;
253  advance_x += (int)letterSpacingScaled;
254  advance_y += glyph_advance_y;
255 
256  previous_glyph_index = glyph_index;
257  }
258  }
259 
260  return result;
261 }
262 
263 // See the header file for the function documentation
264 BSP_DECLARE_WEAK_FCNT jint VG_FREETYPE_IMPL_convert_color(jint color) {
265  return color;
266 }
267 
268 #endif // defined VG_FEATURE_FONT && (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_VECTOR)
269 
270 // -----------------------------------------------------------------------------
271 // EOF
272 // -----------------------------------------------------------------------------
MicroEJ MicroVG library low level API: enable some features according to the hardware capacities.
MicroEJ MicroVG library low level API: implementation over FreeType.
MicroEJ MicroVG library low level API: helper to implement library natives methods.