microvg  6.0.1
microvg
vg_helper.c
Go to the documentation of this file.
1 /*
2  * C
3  *
4  * Copyright 2022-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 
16 #include "vg_configuration.h"
17 
18 // -----------------------------------------------------------------------------
19 // VG Pack Sanity Check
20 // -----------------------------------------------------------------------------
21 
22 /*
23  * Sanity check between the expected version of the VG Pack used by the VEE Port
24  * and the actual version of this file (MicroVG CCO's file).
25  *
26  * If an error is raised here, it means that a new version of the VG Pack has been
27  * installed in the VEE Port or the MicroVG CCO has been updated without any change
28  * in the VEE Port. In both cases, the versions must be coherent (see the Release
29  * Notes: https://docs.microej.com/en/latest/VEEPortingGuide/vgReleaseNotes.html).
30  */
31 
32 #if (defined(LLVG_MAJOR_VERSION) && (LLVG_MAJOR_VERSION != 1)) || (defined(LLVG_MINOR_VERSION) && \
33  (LLVG_MINOR_VERSION < 3))
34 #error "This CCO is only compatible with VG Pack [1.3.0,2.0.0["
35 #endif
36 
37 // -----------------------------------------------------------------------------
38 // Configuration Sanity Check
39 // -----------------------------------------------------------------------------
40 
41 /*
42  * Sanity check between the expected version of the configuration and the actual
43  * version of the configuration.
44  *
45  * If an error is raised here, it means that a new version of the CCO has been
46  * installed and the configuration vg_configuration.h must be updated based
47  * on the one provided by the new CCO version.
48  */
49 
50 #if !defined MICROVG_CONFIGURATION_VERSION
51  #error "Undefined MICROVG_CONFIGURATION_VERSION, it must be defined in vg_configuration.h"
52 #endif
53 
54 #if defined MICROVG_CONFIGURATION_VERSION && MICROVG_CONFIGURATION_VERSION != 3
55  #error "Version of the configuration file vg_configuration.h is not compatible with this implementation."
56 #endif
57 
58 // -----------------------------------------------------------------------------
59 // Includes
60 // -----------------------------------------------------------------------------
61 
62 #include <LLVG_MATRIX_impl.h>
63 
64 #include "vg_helper.h"
65 #include "vg_trace.h"
66 #include "vg_drawing.h"
67 
68 #if defined VG_FEATURE_PATH
69 #include "vg_path.h"
70 #endif
71 
72 #if defined VG_FEATURE_FONT
73 #include <freetype/internal/ftobjs.h>
74 #include "vg_freetype.h"
75 #endif
76 
77 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT
78 #include "hb.h"
79 #include "hb-ft.h"
80 #endif
81 
82 // -----------------------------------------------------------------------------
83 // Defines
84 // -----------------------------------------------------------------------------
85 
86 #define MIN_HIGH_SURROGATE ((unsigned short)0xD800)
87 #define MAX_HIGH_SURROGATE ((unsigned short)0xDBFF)
88 #define MIN_LOW_SURROGATE ((unsigned short)0xDC00)
89 #define MAX_LOW_SURROGATE ((unsigned short)0xDFFF)
90 #define MIN_SUPPLEMENTARY_CODE_POINT 0x010000
91 
92 #define GET_NEXT_CHARACTER(t, l, o) ((o) >= (l) ? (unsigned short)0 : (t)[o])
93 
94 #ifdef VG_FEATURE_FONT_COMPLEX_LAYOUT
95 #define IS_SIMPLE_LAYOUT (!(face->face_flags & FT_FACE_FLAG_COMPLEX_LAYOUT))
96 #else
97 #define IS_SIMPLE_LAYOUT true
98 #endif // VG_FEATURE_FONT_COMPLEX_LAYOUT
99 
100 // -----------------------------------------------------------------------------
101 // Public Globals
102 // -----------------------------------------------------------------------------
103 
104 /*
105  * vg_trace.h logs group identifier
106  */
107 int32_t VG_TRACE_group_id;
108 
109 // -----------------------------------------------------------------------------
110 // Private Globals
111 // -----------------------------------------------------------------------------
112 
113 static jfloat g_identity_matrix[LLVG_MATRIX_SIZE];
114 
115 #if defined VG_FEATURE_FONT
116 static FT_Face face;
117 
118 // Freetype layout variables
119 static const unsigned short *current_text;
120 static unsigned int current_length;
121 static int current_offset;
122 static FT_UInt previous_glyph_index; // previous glyph index for kerning
123 #endif
124 
125 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT
126 // Harfbuzz layout variables
127 static hb_glyph_info_t *glyph_info;
128 static hb_glyph_position_t *glyph_pos;
129 static unsigned int glyph_count;
130 static int current_glyph;
131 static hb_buffer_t *buf;
132 #endif
133 
134 // -----------------------------------------------------------------------------
135 // LLVG_impl.h functions
136 // -----------------------------------------------------------------------------
137 
138 // See the header file for the function documentation
139 void VG_HELPER_initialize(void) {
140  // initializes the logger
141  VG_TRACE_group_id = LLTRACE_IMPL_declare_event_group("MicroVG", LOG_MICROVG_EVENTS);
142 
143  // configures the matrix used as identity matrix (immutable)
144  LLVG_MATRIX_IMPL_identity(g_identity_matrix);
145 
146  // Configures the drawing engine
147  VG_DRAWING_initialize();
148 
149  // configures the path engine
150 #ifdef VG_FEATURE_PATH
151  VG_PATH_initialize();
152 #endif
153 
154  // configures the font engine
155 #if defined VG_FEATURE_FONT && \
156  (defined VG_FEATURE_FONT_FREETYPE_VECTOR || defined VG_FEATURE_FONT_FREETYPE_BITMAP) && \
157  (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_VECTOR || VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_BITMAP)
158 
159  VG_FREETYPE_initialize();
160 #endif
161 }
162 
163 // See the header file for the function documentation
164 int VG_HELPER_get_utf(const unsigned short *textCharRam, int length, int *offset) {
165  unsigned short highPart = GET_NEXT_CHARACTER(textCharRam, length, *offset);
166  int ret = 0; // means "error" (see doc)
167 
168  if ((highPart >= MIN_HIGH_SURROGATE) && (highPart <= MAX_HIGH_SURROGATE)) {
169  if (*offset < (length - 1)) {
170  unsigned short lowPart = GET_NEXT_CHARACTER(textCharRam, length, *(offset) + 1);
171 
172  if ((lowPart >= MIN_LOW_SURROGATE) && (lowPart <= MAX_LOW_SURROGATE)) {
173  *offset += 2;
174 
175  ret = 0;
176  ret += ((int)highPart - (int)MIN_HIGH_SURROGATE);
177  ret <<= (int)10;
178  ret += ((int)lowPart - (int)MIN_LOW_SURROGATE);
179  ret += (int)MIN_SUPPLEMENTARY_CODE_POINT;
180  }
181  // else: invalid surrogate pair
182  }
183  // else: missing second part of surrogate pair
184  } else {
185  *offset += 1;
186 
187  // standard character
188  ret = 0x0000FFFF & (int)highPart;
189  }
190 
191  return ret;
192 }
193 
194 #if defined VG_FEATURE_FONT
195 // See the header file for the function documentation
196 void VG_HELPER_layout_configure(int faceHandle, const unsigned short *text, int length) {
197  face = (FT_Face)faceHandle;
198  // For Misra rule 2.7
199  (void)text;
200  (void)length;
201 
202  if (IS_SIMPLE_LAYOUT) {
203  // Freetype variables initialisation
204  current_text = text;
205  current_length = length;
206  current_offset = 0;
207  previous_glyph_index = 0;
208  } else {
209 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT
210  static hb_font_t *hb_font;
211  static jint current_faceHandle = 0;
212  // load font in Harfbuzz only when faceHandle changes
213  if (faceHandle != current_faceHandle) {
214  if (0 != current_faceHandle) {
215  hb_font_destroy(hb_font);
216  }
217  // FT_Set_Pixel_Sizes() must be called before hb_ft_font_create() see issue M0092MEJAUI-2643
218  FT_Set_Pixel_Sizes(face, 0, face->units_per_EM); /* set character size */
219  hb_font = hb_ft_font_create(face, NULL);
220  current_faceHandle = faceHandle;
221  }
222 
223  buf = hb_buffer_create();
224  hb_buffer_add_utf16(buf, (const uint16_t *)text, length, 0, -1);
225 
226  hb_buffer_guess_segment_properties(buf);
227 
228  hb_shape(hb_font, buf, NULL, 0);
229 
230  glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
231  glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
232 
233  current_glyph = 0;
234 #endif // VG_FEATURE_FONT_COMPLEX_LAYOUT
235  }
236 }
237 
238 #endif /* if defined VG_FEATURE_FONT */
239 
240 #if defined VG_FEATURE_FONT
241 // See the header file for the function documentation
242 bool VG_HELPER_layout_load_glyph(int *glyph_idx, int *x_advance, int *y_advance, int *x_offset, int *y_offset) {
243  // Initiate return value with default values
244  *glyph_idx = 0;
245  *x_advance = 0;
246  *y_advance = 0;
247  *x_offset = 0;
248  *y_offset = 0;
249 
250  bool ret = false;
251 
252  if (IS_SIMPLE_LAYOUT) {
253  // Freetype layout
254  FT_ULong next_char = VG_HELPER_get_utf(current_text, current_length, &current_offset);
255  if (0 != next_char) {
256  FT_UInt glyph_index = FT_Get_Char_Index(face, next_char);
257 
258  int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE);
259  if (FT_ERR(Ok) != error) {
260  MEJ_LOG_ERROR_MICROVG("Error while loading glyphid %d: 0x%x, refer to fterrdef.h\n", glyph_index,
261  error);
262  }
263 
264  *x_advance = face->glyph->advance.x;
265 
266  // Compute Kerning
267  if (FT_HAS_KERNING(face) && previous_glyph_index && glyph_index) {
268  FT_Vector delta;
269  FT_Get_Kerning(face, previous_glyph_index, glyph_index, FT_KERNING_UNSCALED, &delta);
270 
271  *x_offset = delta.x;
272  *x_advance += delta.x;
273  }
274 
275  previous_glyph_index = glyph_index;
276 
277  *glyph_idx = glyph_index;
278 
279  ret = true;
280  }
281  } else {
282 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT
283  // Harfbuzz layout
284  if (((unsigned int)0) != glyph_count) {
285  *glyph_idx = glyph_info[current_glyph].codepoint;
286  *x_advance = glyph_pos[current_glyph].x_advance / 64;
287  *y_advance = glyph_pos[current_glyph].y_advance / 64;
288  *x_offset = glyph_pos[current_glyph].x_offset / 64;
289  *y_offset = glyph_pos[current_glyph].y_offset / 64;
290 
291  glyph_count--;
292  current_glyph++;
293 
294  // Load glyph
295  int error = FT_Load_Glyph(face, *glyph_idx, FT_LOAD_NO_SCALE);
296  if (FT_ERR(Ok) != error) {
297  MEJ_LOG_ERROR_MICROVG("Error while loading glyphid %d: 0x%x, refer to fterrdef.h\n", *glyph_idx, error);
298  }
299 
300  ret = true;
301  } else {
302  hb_buffer_destroy(buf);
303  ret = false;
304  }
305 #endif // VG_FEATURE_FONT_COMPLEX_LAYOUT
306  }
307 
308  return ret;
309 }
310 
311 #endif /* if defined VG_FEATURE_FONT */
312 
313 // See the header file for the function documentation
314 const jfloat * VG_HELPER_check_matrix(const jfloat *matrix) {
315  return (NULL == matrix) ? g_identity_matrix : matrix;
316 }
317 
318 // See the header file for the function documentation
319 uint32_t VG_HELPER_apply_alpha(uint32_t color, uint32_t alpha) {
320  uint32_t color_alpha = (((color >> 24) & (uint32_t)0xff) * alpha) / (uint32_t)255;
321  return (color & (uint32_t)0xffffff) | (color_alpha << 24);
322 }
323 
324 // See the header file for the function documentation
325 void VG_HELPER_prepare_matrix(jfloat *dest, jfloat x, jfloat y, const jfloat *matrix) {
326  const jfloat *local_matrix = VG_HELPER_check_matrix(matrix);
327 
328  if ((0 != x) || (0 != y)) {
329  // Create translate matrix for initial x,y translation from graphicscontext.
330  LLVG_MATRIX_IMPL_setTranslate(dest, x, y);
331  LLVG_MATRIX_IMPL_concatenate(dest, local_matrix);
332  } else {
333  // use original matrix
334  LLVG_MATRIX_IMPL_copy(dest, local_matrix);
335  }
336 }
337 
338 // -----------------------------------------------------------------------------
339 // EOF
340 // -----------------------------------------------------------------------------
MicroEJ MicroVG library low level API: enable some features according to the hardware capacities.
MicroEJ MicroVG library low level API: implementation over FreeType.
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:164
MicroEJ MicroVG library low level API: helper to implement library natives methods.
MicroEJ MicroVG library low level API: implementation of Path.