microvg  6.0.1
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_helper.h"
36 #include "bsp_util.h"
37 
38 // -----------------------------------------------------------------------------
39 // Macros and Defines
40 // -----------------------------------------------------------------------------
41 
42 #define FT_COLOR_TO_INT(x) (*((int *)&(x)))
43 
44 #define DIRECTION_CLOCK_WISE 0
45 
46 // -----------------------------------------------------------------------------
47 // Extern Variables
48 // -----------------------------------------------------------------------------
49 
50 extern FT_Library library;
51 extern FT_Renderer renderer;
52 
53 // -----------------------------------------------------------------------------
54 // Internal functions
55 // -----------------------------------------------------------------------------
56 
57 /*
58  * @brief Computes the scale to apply to the font.
59  *
60  * @param[in] size: the font size
61  * @param[in] face: the face of the font
62  */
63 static inline float __get_scale(jfloat size, FT_Face face) {
64  return size / face->units_per_EM;
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 
102 static FT_Error __render_glyph(FT_Face face, FT_UInt glyph_index, FT_Color *palette,
103  FTVECTOR_draw_glyph_data_t *drawer_data) {
104  FT_Error error = FT_ERR(Ok);
105 
106  uint32_t default_color = drawer_data->color;
107  FT_UInt layer_glyph_index;
108  FT_UInt layer_color_index;
109  FT_LayerIterator iterator;
110  iterator.p = NULL;
111 
112  FT_Bool have_layers = palette && FT_Get_Color_Glyph_Layer(face, glyph_index, &layer_glyph_index, &layer_color_index,
113  &iterator);
114 
115  do {
116  if (have_layers) {
117  // Update renderer color with layer_color
118  if (layer_color_index != 0xFFFF) {
119  drawer_data->color = VG_FREETYPE_IMPL_convert_color(FT_COLOR_TO_INT(palette[layer_color_index]));
120  }
121  } else {
122  // Use main glyph_index as layer_glyph_index
123  layer_glyph_index = glyph_index;
124  }
125 
126  if (layer_glyph_index != glyph_index) {
127  error = FT_Load_Glyph(face, layer_glyph_index, FT_LOAD_NO_SCALE);
128  }
129 
130  if (FT_ERR(Ok) == error) {
131  // convert to an anti-aliased bitmap
132  error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
133  } else {
134  MEJ_LOG_ERROR_MICROVG("Error while loading glyphid %d: 0x%x, refer to fterrdef.h\n", layer_glyph_index,
135  error);
136  }
137  }while ((layer_glyph_index != glyph_index) && (FT_ERR(Ok) == error) && (FT_ERR(Ok) != FT_Get_Color_Glyph_Layer(face,
138  glyph_index,
139  &
140  layer_glyph_index,
141  &
142  layer_color_index,
143  &
144  iterator)));
145 
146  // Revert renderer color to original color in case it has been modified.
147  drawer_data->color = default_color;
148 
149  return error;
150 }
151 
152 // -----------------------------------------------------------------------------
153 // vg_freetype.h painter functions
154 // -----------------------------------------------------------------------------
155 
156 // See the header file for the function documentation
157 jint VG_FREETYPE_draw_string(VG_FREETYPE_draw_glyph_t drawer, const jchar *text, jint faceHandle, jfloat size,
158  const jfloat *matrix, uint32_t color, jfloat letterSpacing, jfloat radius, jint direction,
159  void *user_data) {
160  jint result = LLVG_SUCCESS;
161  int length = (int)SNI_getArrayLength(text);
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: helper to implement library natives methods.