microvg  8.0.3
microvg
vg_freetype_path.c
Go to the documentation of this file.
1 /*
2  * C
3  *
4  * Copyright 2020-2026 MicroEJ Corp. All rights reserved.
5  * MicroEJ Corp. PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  *
7  * Build: 7E4D1F7C
8  */
9 
17 // -----------------------------------------------------------------------------
18 // Includes
19 // -----------------------------------------------------------------------------
20 
21 #include "vg_configuration.h"
22 
23 #if defined VG_FEATURE_FONT && (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_VECTOR)
24 
25 #include <math.h>
26 #include <inttypes.h>
27 
28 #include <freetype/internal/ftobjs.h>
29 #if defined VG_FEATURE_FREETYPE_COLORED_EMOJI && (VG_FEATURE_FREETYPE_COLORED_EMOJI == 1)
30 #include <freetype/ftcolor.h>
31 #endif // VG_FEATURE_FREETYPE_COLORED_EMOJI
32 #include "ftvector/ftvector.h"
33 
34 #include <LLVG_FONT_impl.h>
35 #include <LLVG_PATH_impl.h>
36 #include <LLVG_GRADIENT_impl.h>
37 #include <LLVG_MATRIX_impl.h>
38 #include <sni.h>
39 
40 #include "vg_freetype.h"
41 #include "vg_helper.h"
42 #include "bsp_util.h"
43 
45 
46 // -----------------------------------------------------------------------------
47 // Macros and Defines
48 // -----------------------------------------------------------------------------
49 
50 #if defined VG_FEATURE_FREETYPE_COLORED_EMOJI && (VG_FEATURE_FREETYPE_COLORED_EMOJI == 1)
51 #define FT_COLOR_TO_INT(x) (*((int *)&(x)))
52 #endif // VG_FEATURE_FREETYPE_COLORED_EMOJI
53 
54 #define DIRECTION_CLOCK_WISE 0
55 
56 // -----------------------------------------------------------------------------
57 // Extern Variables
58 // -----------------------------------------------------------------------------
59 
60 extern FT_Library library;
61 extern FT_Renderer renderer;
62 
63 // -----------------------------------------------------------------------------
64 // Internal functions
65 // -----------------------------------------------------------------------------
66 
67 /*
68  * @brief Sets renderer parameters.
69  */
70 static void __set_renderer(FTVECTOR_draw_glyph_data_t *data) {
71  FT_Parameter params[1];
72 
73  params[0].tag = FT_PARAM_TAG_DRAWER;
74  // cppcheck-suppress [misra-c2012-11.1] pointer conversion to store the drawer
75  params[0].data = (void *)data;
76 
77  FT_Set_Renderer(library, renderer, 1, &params[0]);
78 }
79 
80 /*
81  * @brief Updates the angle to use for the next glyph when drawn on an arc.
82  * When drawing on an arc, the glyph position is defined by its angle. We thus
83  * convert the advance (distance to the next glyph) to an angle.
84  */
85 static float __get_angle(float advance, float radius) {
86  float angle = advance / radius;
87  angle *= 180.0f;
88  angle /= M_PI;
89  return angle;
90 }
91 
92 #if defined VG_FEATURE_FREETYPE_COLORED_EMOJI && (VG_FEATURE_FREETYPE_COLORED_EMOJI == 1)
93 
108 static FT_Error __render_glyph(FT_Face face, FT_UInt glyph_index, FT_Color *palette,
109  FTVECTOR_draw_glyph_data_t *drawer_data) {
110  FT_Error error;
111 
112  FT_UInt layer_glyph_index = 0;
113  FT_UInt layer_color_index = 0;
114  FT_LayerIterator iterator;
115  iterator.p = NULL;
116 
117  if ((NULL == palette) ||
118  (0U == FT_Get_Color_Glyph_Layer(face, glyph_index, &layer_glyph_index, &layer_color_index, &iterator))) {
119  // convert to an anti-aliased bitmap
120  error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
121  } else {
122  uint32_t default_color = drawer_data->color;
123  bool has_next_layer;
124 
125  do {
126  // Update renderer color with layer_color
127  if (layer_color_index != 0xFFFF) {
128  drawer_data->color = VG_FREETYPE_IMPL_convert_color(FT_COLOR_TO_INT(palette[layer_color_index]));
129  }
130 
131  error = FT_Load_Glyph(face, layer_glyph_index, FT_LOAD_NO_SCALE);
132  if (FT_ERR(Ok) == error) {
133  // convert to an anti-aliased bitmap
134  error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
135  } else {
136  VG_LOG_ERROR("Error while loading glyphid %d: 0x%x, refer to fterrdef.h", layer_glyph_index,
137  error);
138  }
139 
140  has_next_layer = (FT_ERR(Ok) == error) &&
141  (0U != FT_Get_Color_Glyph_Layer(face, glyph_index, &layer_glyph_index,
142  &layer_color_index, &iterator));
143  } while (has_next_layer);
144 
145  // Revert renderer color to original color.
146  drawer_data->color = default_color;
147  }
148 
149  return error;
150 }
151 
152 #endif // VG_FEATURE_FREETYPE_COLORED_EMOJI
153 
154 // -----------------------------------------------------------------------------
155 // vg_freetype.h painter functions
156 // -----------------------------------------------------------------------------
157 
158 // See the header file for the function documentation
159 jint VG_FREETYPE_draw_string(VG_FREETYPE_draw_glyph_t drawer, const jchar *text, jint length, jint faceHandle,
160  jfloat size, const jfloat *matrix, uint32_t color, jfloat letterSpacing, jfloat radius,
161  jint direction, void *user_data) {
162  jint result = LLVG_SUCCESS;
163 
164  if (0 < length) {
165  FT_Face face = (FT_Face)faceHandle;
166 #if defined VG_FEATURE_FREETYPE_COLORED_EMOJI && (VG_FEATURE_FREETYPE_COLORED_EMOJI == 1)
167  FT_Color *palette;
168 
169  // Select palette
170  if (0 != FT_Palette_Select(face, 0, &palette)) {
171  palette = NULL;
172  }
173 #endif // VG_FEATURE_FREETYPE_COLORED_EMOJI
174 
175  float scale = VG_FREETYPE_get_scale(faceHandle, size);
176  float letterSpacingFontUnits = letterSpacing / scale;
177  float radiusScaled = radius / scale;
178  short baselineposition = face->ascender;
179 
180  // transformation to apply on all glyphs
181  float scaled_matrix[LLVG_MATRIX_SIZE];
182  LLVG_MATRIX_IMPL_copy(scaled_matrix, matrix);
183  LLVG_MATRIX_IMPL_scale(scaled_matrix, scale, scale);
184 
185  float working_matrix[LLVG_MATRIX_SIZE];
186 
187  FTVECTOR_draw_glyph_data_t drawer_data;
188  drawer_data.drawer = drawer;
189  drawer_data.matrix = working_matrix;
190  drawer_data.color = color;
191  drawer_data.user_data = user_data;
192  drawer_data.destination_error = LLVG_SUCCESS;
193 
194  // give drawing parameters to freetype
195  __set_renderer(&drawer_data);
196 
197  int glyph_index; // current glyph index
198  int glyph_offset_y;
199  int glyph_advance_x;
200  int glyph_advance_y;
201  int glyph_offset_x;
202  float advance_x = 0.f;
203  int advance_y = 0;
204 
205  // The string starts on the leftmost ink of the whole string, not on the first glyph's:
206  // the two differ as soon as a later glyph reaches further left, and the measure is the
207  // width of that same box.
208  float span_left = 0.f;
209  if (VG_FREETYPE_string_span(text, length, faceHandle, letterSpacingFontUnits, &span_left, NULL)) {
210  advance_x = -span_left;
211  }
212 
213  VG_HELPER_layout_configure(faceHandle, text, length);
214 
215  while ((LLVG_SUCCESS == result) && (VG_HELPER_layout_load_glyph((uint32_t *)&glyph_index, &glyph_advance_x,
216  &glyph_advance_y, &glyph_offset_x,
217  &glyph_offset_y))) {
218  // At that point the current glyph has been loaded by Freetype
219 
220  int charWidth = glyph_advance_x;
221 
222  // reset drawer's matrix
223  LLVG_MATRIX_IMPL_copy(working_matrix, scaled_matrix);
224 
225  if (0.f == radius) {
226  LLVG_MATRIX_IMPL_translate(working_matrix, advance_x + (float)glyph_offset_x,
227  (float)(baselineposition + advance_y + glyph_offset_y));
228  } else {
229  float sign = (DIRECTION_CLOCK_WISE != direction) ? -1.f : 1.f;
230 
231  // Space characters joining bboxes at baseline
232  float angleDegrees = 90 + __get_angle(advance_x + (float)glyph_offset_x,
233  radiusScaled) + __get_angle((float)(charWidth / 2), radiusScaled);
234 
235  // Rotate to angle
236  LLVG_MATRIX_IMPL_rotate(working_matrix, sign * angleDegrees);
237 
238  // Translate left to center of bbox
239  // Translate baseline over circle
240  LLVG_MATRIX_IMPL_translate(working_matrix, -charWidth / 2, -sign * radiusScaled);
241  }
242 
243  // Draw the glyph
244 #if defined VG_FEATURE_FREETYPE_COLORED_EMOJI && (VG_FEATURE_FREETYPE_COLORED_EMOJI == 1)
245  FT_Error error = __render_glyph(face, glyph_index, palette, &drawer_data);
246 #else
247  // convert to an anti-aliased bitmap
248  FT_Error error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
249 #endif // VG_FEATURE_FREETYPE_COLORED_EMOJI
250  if (FT_ERR(Ok) != error) {
251  if (LLVG_SUCCESS != drawer_data.destination_error) {
252  // the drawing destination refused: FreeType only relayed its error
253  result = drawer_data.destination_error;
254  VG_LOG_ERROR("String cut at glyphid %d: the drawing destination refused (error %" PRId32 ")",
255  glyph_index, result);
256  } else {
257  VG_LOG_ERROR("Error while rendering glyphid %d: 0x%x, refer to fterrdef.h", glyph_index,
258  error);
259  result = (FT_ERR(Out_Of_Memory) == error) ? LLVG_OUT_OF_MEMORY : LLVG_DATA_INVALID;
260  }
261  continue;
262  }
263 
264  // Compute advance to next glyph
265  advance_x += (float)charWidth;
266  advance_x += letterSpacingFontUnits;
267  advance_y += glyph_advance_y;
268  }
269  }
270 
271  return result;
272 }
273 
274 // See the header file for the function documentation
275 BSP_DECLARE_WEAK_FCNT jint VG_FREETYPE_IMPL_convert_color(jint color) {
276  return color;
277 }
278 
279 #endif // defined VG_FEATURE_FONT && (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_VECTOR)
280 
281 // -----------------------------------------------------------------------------
282 // EOF
283 // -----------------------------------------------------------------------------
MicroEJ MicroVG library low level API: enable some features according to the hardware capacities.
#define VG_LOG_DECLARE_MODULE()
Declares the log module, once at the top of each source file that logs.
MicroEJ MicroVG library low level API: implementation over FreeType.
bool VG_FREETYPE_string_span(const jchar *text, jint length, jint face_handle, jfloat letter_spacing_font_units, jfloat *left, jfloat *right)
Folds the ink of a string and returns its two extreme edges.
jfloat VG_FREETYPE_get_scale(jint face_handle, jfloat size)
Computes the scale that converts font units to pixels at the given size.
jint VG_FREETYPE_draw_string(VG_FREETYPE_draw_glyph_t drawer, const jchar *text, jint length, jint face_handle, jfloat size, const jfloat *matrix, uint32_t color, jfloat letter_spacing, jfloat radius, jint direction, void *user_data)
Draws a string using the Freetype engine along a line or a circle, with a color or a linear gradient....
jint(* VG_FREETYPE_draw_glyph_t)(VG_PATH_HEADER_t *path, jfloat *matrix, uint32_t color, bool fill_rule_even_odd, void *user_data)
Function to draw a character element: a glyph. A glyph is a vectorial path.
Definition: vg_freetype.h:56
MicroEJ MicroVG library low level API: helper to implement library natives methods.
void VG_HELPER_layout_configure(int faceHandle, const unsigned short *text, int length)
Configures the font layouter with a font and a text.
#define VG_LOG_ERROR(fmt,...)
Logs an error. The format has no trailing line return.
Definition: vg_helper.h:42
bool VG_HELPER_layout_load_glyph(uint32_t *glyph_idx, int *x_advance, int *y_advance, int *x_offset, int *y_offset)
Loads the next layouted glyph and gets index and positions.