microvg  8.0.3
microvg
vg_helper.c
Go to the documentation of this file.
1 /*
2  * C
3  *
4  * Copyright 2022-2026 MicroEJ Corp. All rights reserved.
5  * MicroEJ Corp. PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  *
7  * Build: 7E4D1F7C
8  */
9 
18 #include "vg_configuration.h"
19 
20 // -----------------------------------------------------------------------------
21 // VG Pack Sanity Check
22 // -----------------------------------------------------------------------------
23 
24 /*
25  * Sanity check between the expected version of the VG Pack used by the VEE Port
26  * and the actual version of this file (MicroVG Abstraction Layer's file).
27  *
28  * If an error is raised here, it means that a new version of the VG Pack has been
29  * installed in the VEE Port or the MicroVG Abstraction Layer has been updated without any change
30  * in the VEE Port. In both cases, the versions must be coherent (see the Release
31  * Notes: https://docs.microej.com/en/latest/VEEPortingGuide/vgReleaseNotes.html).
32  */
33 
34 #if (defined(LLVG_MAJOR_VERSION) && (LLVG_MAJOR_VERSION != 1)) || (defined(LLVG_MINOR_VERSION) && \
35  (LLVG_MINOR_VERSION < 8))
36 #error "This Abstraction Layer is only compatible with VG Pack [1.8.0,2.0.0["
37 #endif
38 
39 // -----------------------------------------------------------------------------
40 // Includes
41 // -----------------------------------------------------------------------------
42 
43 #include <LLVG_MATRIX_impl.h>
44 
45 #include "vg_helper.h"
46 #include "vg_trace.h"
47 #include "vg_drawing.h"
48 #include "bsp_util.h"
49 
50 #if defined VG_FEATURE_PATH
51 #include "vg_path.h"
52 #endif
53 
54 #if defined VG_FEATURE_FONT
55 #include <freetype/internal/ftobjs.h>
56 #include <inttypes.h>
57 #include "vg_freetype.h"
58 
60 #endif
61 
62 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
63 #include "hb.h"
64 #include "hb-ft.h"
65 #endif
66 
67 // -----------------------------------------------------------------------------
68 // Defines
69 // -----------------------------------------------------------------------------
70 
71 #define MIN_HIGH_SURROGATE ((unsigned short)0xD800)
72 #define MAX_HIGH_SURROGATE ((unsigned short)0xDBFF)
73 #define MIN_LOW_SURROGATE ((unsigned short)0xDC00)
74 #define MAX_LOW_SURROGATE ((unsigned short)0xDFFF)
75 #define MIN_SUPPLEMENTARY_CODE_POINT 0x010000
76 
77 #define GET_NEXT_CHARACTER(t, l, o) ((o) >= (l) ? (unsigned short)0 : (t)[o])
78 
79 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
80 #define IS_SIMPLE_LAYOUT (!(face->face_flags & FT_FACE_FLAG_COMPLEX_LAYOUT))
81 #else
82 #define IS_SIMPLE_LAYOUT true
83 #endif // VG_FEATURE_FONT_COMPLEX_LAYOUT
84 
85 // -----------------------------------------------------------------------------
86 // Public Globals
87 // -----------------------------------------------------------------------------
88 
89 /*
90  * @brief Identifies the MicroVG group to trace an event.
91  */
93 
94 // -----------------------------------------------------------------------------
95 // Private Globals
96 // -----------------------------------------------------------------------------
97 
98 static jfloat g_identity_matrix[LLVG_MATRIX_SIZE];
99 
100 #if defined VG_FEATURE_FONT
101 static FT_Face face;
102 
103 // Freetype layout variables
104 static const unsigned short *current_text;
105 static unsigned int current_length;
106 static int current_offset;
107 static FT_UInt previous_glyph_index; // previous glyph index for kerning
108 #endif
109 
110 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
111 // Harfbuzz layout variables
112 static hb_glyph_info_t *glyph_info;
113 static hb_glyph_position_t *glyph_pos;
114 static unsigned int glyph_count;
115 static int current_glyph;
116 static hb_buffer_t *buf;
117 // The shaper built from the font face named by current_faceHandle, and that face's handle. A
118 // handle of 0 means no shaper is held.
119 static hb_font_t *hb_font;
120 static jint current_faceHandle;
121 #endif
122 
123 // -----------------------------------------------------------------------------
124 // LLVG_impl.h functions
125 // -----------------------------------------------------------------------------
126 
127 // See the header file for the function documentation
128 void LLVG_IMPL_initialize(jint trace_group) {
129  // initializes the tracer
130  LLVG_TRACE_group = trace_group;
131 
132  // configures the matrix used as identity matrix (immutable)
133  LLVG_MATRIX_IMPL_identity(g_identity_matrix);
134 
135  // Configures the drawing engine
137 
138  // configures the path engine
139 #ifdef VG_FEATURE_PATH
141 #endif
142 
143  // configures the font engine
144 #if defined VG_FEATURE_FONT && \
145  (defined VG_FEATURE_FONT_FREETYPE_VECTOR || defined VG_FEATURE_FONT_FREETYPE_BITMAP) && \
146  (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_VECTOR || VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_BITMAP)
147 
149 #endif
150 }
151 
152 // --------------------------------------------------------------------------------
153 // UI Pack > 14.5.1 function
154 // --------------------------------------------------------------------------------
155 
156 // See the header file for the function documentation
157 BSP_DECLARE_WEAK_FCNT void LLUI_DISPLAY_waitAsynchronousDrawingEnd(void) {
158  // cannot wait the end of drawing with UI packs [14.4.0-14.5.1]
159 }
160 
161 // -----------------------------------------------------------------------------
162 // vg_helper.h functions
163 // -----------------------------------------------------------------------------
164 
165 // See the header file for the function documentation
166 int VG_HELPER_get_utf(const unsigned short *textCharRam, int length, int *offset) {
167  unsigned short highPart = GET_NEXT_CHARACTER(textCharRam, length, *offset);
168  int ret = 0; // means "error" (see doc)
169 
170  if ((highPart >= MIN_HIGH_SURROGATE) && (highPart <= MAX_HIGH_SURROGATE)) {
171  if (*offset < (length - 1)) {
172  unsigned short lowPart = GET_NEXT_CHARACTER(textCharRam, length, *(offset) + 1);
173 
174  if ((lowPart >= MIN_LOW_SURROGATE) && (lowPart <= MAX_LOW_SURROGATE)) {
175  *offset += 2;
176 
177  ret = 0;
178  ret += ((int)highPart - (int)MIN_HIGH_SURROGATE);
179  ret <<= (int)10;
180  ret += ((int)lowPart - (int)MIN_LOW_SURROGATE);
181  ret += (int)MIN_SUPPLEMENTARY_CODE_POINT;
182  }
183  // else: invalid surrogate pair
184  }
185  // else: missing second part of surrogate pair
186  } else {
187  *offset += 1;
188 
189  // standard character
190  ret = 0x0000FFFF & (int)highPart;
191  }
192 
193  return ret;
194 }
195 
196 #if defined VG_FEATURE_FONT
197 // See the header file for the function documentation
198 void VG_HELPER_layout_configure(int faceHandle, const unsigned short *text, int length) {
199  // Configuring starts a new iteration, so whatever a caller that stopped before the end of its own
200  // iteration left open is released here.
202 
203  face = (FT_Face)faceHandle;
204  // For Misra rule 2.7
205  (void)text;
206  (void)length;
207 
208  if (IS_SIMPLE_LAYOUT) {
209  // Freetype variables initialisation
210  current_text = text;
211  current_length = length;
212  current_offset = 0;
213  previous_glyph_index = 0;
214  } else {
215 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
216  // load font in Harfbuzz only when faceHandle changes
217  if (faceHandle != current_faceHandle) {
218  if (0 != current_faceHandle) {
219  hb_font_destroy(hb_font);
220  }
221  // FT_Set_Pixel_Sizes() must be called before hb_ft_font_create()
222  FT_Set_Pixel_Sizes(face, 0, face->units_per_EM); /* set character size */
223  hb_font = hb_ft_font_create(face, NULL);
224  current_faceHandle = faceHandle;
225  }
226 
227  buf = hb_buffer_create();
228  hb_buffer_add_utf16(buf, (const uint16_t *)text, length, 0, -1);
229 
230  hb_buffer_guess_segment_properties(buf);
231 
232  hb_shape(hb_font, buf, NULL, 0);
233 
234  glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
235  glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
236 
237  current_glyph = 0;
238 #endif // VG_FEATURE_FONT_COMPLEX_LAYOUT
239  }
240 }
241 
242 // See the header file for the function documentation
243 void VG_HELPER_layout_dispose(int faceHandle) {
244 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
245  if (faceHandle == current_faceHandle) {
246  hb_font_destroy(hb_font);
247  hb_font = NULL;
248  current_faceHandle = 0;
249  }
250 #else
251  (void)faceHandle;
252 #endif // VG_FEATURE_FONT_COMPLEX_LAYOUT
253 }
254 
255 #endif /* if defined VG_FEATURE_FONT */
256 
257 #if defined VG_FEATURE_FONT
258 // See the header file for the function documentation
259 bool VG_HELPER_layout_load_glyph(uint32_t *glyph_idx, int *x_advance, int *y_advance, int *x_offset, int *y_offset) {
260  // Initiate return value with default values
261  *glyph_idx = 0;
262  *x_advance = 0;
263  *y_advance = 0;
264  *x_offset = 0;
265  *y_offset = 0;
266 
267  bool ret = false;
268 
269  if (IS_SIMPLE_LAYOUT) {
270  // Freetype layout
271  FT_ULong next_char = VG_HELPER_get_utf(current_text, current_length, &current_offset);
272  if (0 != next_char) {
273  FT_UInt glyph_index = FT_Get_Char_Index(face, next_char);
274 
275  int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE);
276  if (FT_ERR(Ok) != error) {
277  VG_LOG_ERROR("Error while loading glyphid %u: 0x%x, refer to fterrdef.h", glyph_index,
278  error);
279  }
280 
281  *x_advance = face->glyph->advance.x;
282 
283  // Compute Kerning
284  if (FT_HAS_KERNING(face) && previous_glyph_index && glyph_index) {
285  FT_Vector delta;
286  FT_Get_Kerning(face, previous_glyph_index, glyph_index, FT_KERNING_UNSCALED, &delta);
287 
288  *x_offset = delta.x;
289  *x_advance += delta.x;
290  }
291 
292  previous_glyph_index = glyph_index;
293 
294  *glyph_idx = glyph_index;
295 
296  ret = true;
297  }
298  } else {
299 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
300  // Harfbuzz layout
301  if (((unsigned int)0) != glyph_count) {
302  *glyph_idx = glyph_info[current_glyph].codepoint;
303  *x_advance = glyph_pos[current_glyph].x_advance / 64;
304  *y_advance = glyph_pos[current_glyph].y_advance / 64;
305  *x_offset = glyph_pos[current_glyph].x_offset / 64;
306  *y_offset = glyph_pos[current_glyph].y_offset / 64;
307 
308  glyph_count--;
309  current_glyph++;
310 
311  // Load glyph
312  int error = FT_Load_Glyph(face, *glyph_idx, FT_LOAD_NO_SCALE);
313  if (FT_ERR(Ok) != error) {
314  VG_LOG_ERROR("Error while loading glyphid %" PRIu32 ": 0x%x, refer to fterrdef.h", *glyph_idx, error);
315  }
316 
317  ret = true;
318  } else {
319  if (NULL != buf) {
320  hb_buffer_destroy(buf);
321  buf = NULL;
322  }
323  ret = false;
324  }
325 #endif // VG_FEATURE_FONT_COMPLEX_LAYOUT
326  }
327 
328  return ret;
329 }
330 
331 // See the header file for the function documentation
332 void VG_HELPER_layout_stop(void) {
333 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
334  if (NULL != buf) {
335  // The buffer, not the remaining count, is what says an iteration is still open: the count
336  // reaches zero when the last glyph is handed out, one call before the iteration ends.
337  hb_buffer_destroy(buf);
338  buf = NULL;
339  glyph_count = 0;
340  }
341 #endif // VG_FEATURE_FONT_COMPLEX_LAYOUT
342 }
343 
344 #endif /* if defined VG_FEATURE_FONT */
345 
346 // See the header file for the function documentation
347 const jfloat * VG_HELPER_check_matrix(const jfloat *matrix) {
348  return (NULL == matrix) ? g_identity_matrix : matrix;
349 }
350 
351 // See the header file for the function documentation
352 uint32_t VG_HELPER_apply_alpha(uint32_t color, uint32_t alpha) {
353  uint32_t color_alpha = (((color >> 24) & (uint32_t)0xff) * alpha) / (uint32_t)255;
354  return (color & (uint32_t)0xffffff) | (color_alpha << 24);
355 }
356 
357 // See the header file for the function documentation
358 void VG_HELPER_prepare_matrix(jfloat *dest, jfloat x, jfloat y, const jfloat *matrix) {
359  const jfloat *local_matrix = VG_HELPER_check_matrix(matrix);
360 
361  if ((0 != x) || (0 != y)) {
362  // Create translate matrix for initial x,y translation from graphicscontext.
363  LLVG_MATRIX_IMPL_setTranslate(dest, x, y);
364  LLVG_MATRIX_IMPL_concatenate(dest, local_matrix);
365  } else {
366  // use original matrix
367  LLVG_MATRIX_IMPL_copy(dest, local_matrix);
368  }
369 }
370 
371 // -----------------------------------------------------------------------------
372 // EOF
373 // -----------------------------------------------------------------------------
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.
Provides drawing functions called by MicroVG native drawing functions.
void VG_DRAWING_initialize(void)
Called when initializing MicroVG.
MicroEJ MicroVG library low level API: implementation over FreeType.
void VG_FREETYPE_initialize(void)
Initializes the lowlevel font library.
uint32_t VG_HELPER_apply_alpha(uint32_t color, uint32_t alpha)
Applies the global opacity on given color.
Definition: vg_helper.c:352
BSP_DECLARE_WEAK_FCNT void LLUI_DISPLAY_waitAsynchronousDrawingEnd(void)
Waits until the end of current asynchronous drawing.
Definition: vg_helper.c:157
int32_t LLVG_TRACE_group
Identifies the MicroVG group to trace an event.
Definition: vg_helper.c:92
void VG_HELPER_prepare_matrix(jfloat *dest, jfloat x, jfloat y, const jfloat *matrix)
Converts a MicroVG matrix in another MicroVG matrix applying a translation.
Definition: vg_helper.c:358
const jfloat * VG_HELPER_check_matrix(const jfloat *matrix)
Checks if the matrix is null. In that case, returns an identity matrix. This allows to prevent to mak...
Definition: vg_helper.c:347
int VG_HELPER_get_utf(const unsigned short *textCharRam, int length, int *offset)
Gets the UTF character from a text buffer at the given offset and updates the offset to point to the ...
Definition: vg_helper.c:166
MicroEJ MicroVG library low level API: helper to implement library natives methods.
void VG_HELPER_layout_dispose(int faceHandle)
Releases the font layouter's state built from a font face, when that face is about to be freed....
void VG_HELPER_layout_stop(void)
Releases what the layouter still holds for the current iteration. Does nothing when there is nothing ...
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.
MicroEJ MicroVG library low level API: implementation of Path.
void VG_PATH_initialize(void)
Initializes the path builder.