20 #if defined VG_FEATURE_FONT && \
21 (defined VG_FEATURE_FONT_FREETYPE_VECTOR || defined VG_FEATURE_FONT_FREETYPE_BITMAP) && \
22 (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_VECTOR || VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_BITMAP)
32 #include <LLVG_impl.h>
33 #include <LLVG_FONT_impl.h>
35 #if defined VG_FEATURE_FONT_EXTERNAL && (VG_FEATURE_FONT_EXTERNAL == 1)
36 #include <LLEXT_RES_impl.h>
37 #include <freetype/internal/ftmemory.h>
55 #define LOG_MICROVG_FONT_START(fn) LOG_MICROVG_START(LOG_MICROVG_FONT_ID, CONCAT_DEFINES(LOG_MICROVG_FONT_, fn))
56 #define LOG_MICROVG_FONT_END(fn) LOG_MICROVG_END(LOG_MICROVG_FONT_ID, CONCAT_DEFINES(LOG_MICROVG_FONT_, fn))
77 extern int32_t SNIX_get_resource(jchar *path, SNIX_resource *resource);
87 static void __dispose_registered_font(
void *faceHandle);
92 static void __dispose_font(
void *faceHandle);
105 static FT_Error __load_memory_font(FT_Face *face,
void *data,
int length);
117 static FT_Error __load_internal_font(FT_Face *face, jchar *font_name);
123 static void __register_font_description(
void *resource,
char *buffer, uint32_t bufferLength);
125 #if defined VG_FEATURE_FONT_EXTERNAL && (VG_FEATURE_FONT_EXTERNAL == 1)
137 static FT_Error __load_external_font(FT_Face *face, jchar *font_name);
151 static unsigned long __read_external_resource(FT_Stream stream,
unsigned long offset,
unsigned char *buffer,
152 unsigned long count);
161 static void __close_external_resource(FT_Stream stream);
170 FT_Renderer renderer;
172 #if defined VG_FEATURE_FONT && defined VG_FEATURE_FONT_FREETYPE_VECTOR && \
173 (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_VECTOR)
174 const char *renderer_name =
"microvg";
176 #if defined VG_FEATURE_FONT && defined VG_FEATURE_FONT_FREETYPE_BITMAP && \
177 (VG_FEATURE_FONT == VG_FEATURE_FONT_FREETYPE_BITMAP)
178 const char *renderer_name =
"smooth";
187 FT_Error error = FT_Init_FreeType(&library);
188 if (FT_ERR(Ok) == error) {
189 renderer = FT_RENDERER(FT_Get_Module(library, renderer_name));
191 VG_LOG_INFO(
"Freetype renderer: %s", FT_MODULE_CLASS(renderer)->module_name);
193 VG_LOG_ERROR(
"No renderer found with name %s", renderer_name);
196 VG_LOG_ERROR(
"Internal freetype error initializing library, ID = %d", error);
201 bool VG_FREETYPE_string_span(
const jchar *text, jint length, jint face_handle, jfloat letter_spacing_font_units,
202 jfloat *left, jfloat *right) {
203 FT_Face face = (FT_Face)face_handle;
204 bool has_drawn_glyph =
false;
206 float span_left = 0.f;
207 float span_right = 0.f;
210 FT_UInt glyph_index = 0;
222 bool stop_on_left = (NULL == right) && (letter_spacing_font_units >= 0.f);
223 const float unreachable_left = MIN((
float)face->bbox.xMin, 0.f) - (float)face->units_per_EM;
226 VG_OUTLINE_BOX box = { .
x_min = 0.f, .x_max = 0.f, .y_min = 0.f, .y_max = 0.f, .empty =
true };
237 float glyph_left = pen + (float)offset_x + box.x_min;
238 float glyph_right = pen + (
float)offset_x + box.x_max;
240 if (!has_drawn_glyph) {
241 span_left = glyph_left;
242 span_right = glyph_right;
243 has_drawn_glyph =
true;
245 span_left = MIN(glyph_left, span_left);
246 span_right = MAX(glyph_right, span_right);
250 float step = (float)advance_x + letter_spacing_font_units;
256 stop_on_left =
false;
259 if (stop_on_left && has_drawn_glyph && ((pen + unreachable_left) >= span_left)) {
267 if (has_drawn_glyph) {
274 return has_drawn_glyph;
279 FT_Face face = (FT_Face)face_handle;
280 return size / (float)face->units_per_EM;
285 float scaled_width = 0.f;
286 FT_Face face = (FT_Face)face_handle;
288 if ((size > 0) && (length > 0)) {
295 assert(right >= left);
296 scaled_width = scale * (right - left);
308 jint LLVG_FONT_IMPL_load_font(jchar *font_name, jboolean complex_layout) {
309 LOG_MICROVG_FONT_START(load);
312 jint ret = LLVG_FONT_UNLOADED;
315 if (complex_layout && !LLVG_FONT_IMPL_has_complex_layouter()) {
316 ret = LLVG_FONT_UNLOADED;
319 FT_Error error = __load_internal_font(&face, font_name);
321 #if defined VG_FEATURE_FONT_EXTERNAL && (VG_FEATURE_FONT_EXTERNAL == 1)
322 if (FT_ERR(Cannot_Open_Resource) == error) {
324 error = __load_external_font(&face, font_name);
328 if ((FT_ERR(Ok) == error) && (!FT_IS_SCALABLE(face) || (0U == face->units_per_EM))) {
331 VG_LOG_ERROR(
"Font not scalable: %s", (
const char *)font_name);
332 __dispose_font((
void *)face);
333 }
else if (FT_ERR(Ok) == error) {
335 FT_Select_Charmap(face, ft_encoding_unicode);
336 VG_LOG_INFO(
"Freetype font loaded: %s", (
const char *)font_name);
338 int32_t registered = SNI_registerResource((
void *)face, (SNI_closeFunction) & __dispose_registered_font,
339 &__register_font_description);
340 assert(SNI_OK == registered);
342 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
343 if (JTRUE == complex_layout) {
349 }
else if (FT_ERR(Cannot_Open_Resource) != error) {
350 VG_LOG_ERROR(
"An error occurred during font loading: 0x%x, refer to fterrdef.h", error);
352 VG_LOG_ERROR(
"Resource not found: %s", (
const char *)font_name);
356 LOG_MICROVG_FONT_END(load);
361 jfloat LLVG_FONT_IMPL_string_width(jchar *text, jint faceHandle, jfloat size, jfloat letterSpacing) {
362 LOG_MICROVG_FONT_START(stringWidth);
365 if (LLVG_FONT_UNLOADED == faceHandle) {
366 ret = (jfloat)LLVG_RESOURCE_CLOSED;
368 int length = (int)SNI_getArrayLength(text);
372 LOG_MICROVG_FONT_END(stringWidth);
377 jfloat LLVG_FONT_IMPL_string_height(jchar *text, jint faceHandle, jfloat size) {
378 LOG_MICROVG_FONT_START(stringHeight);
381 if (LLVG_FONT_UNLOADED == faceHandle) {
382 ret = (jfloat)LLVG_RESOURCE_CLOSED;
384 FT_Face face = (FT_Face)faceHandle;
385 float scaled_height = 0.f;
393 float drawn_y_top = 0.f;
394 float drawn_y_bottom = 0.f;
399 bool has_drawn_glyph =
false;
402 FT_UInt glyph_index = 0;
410 VG_OUTLINE_BOX box = { .
x_min = 0.f, .x_max = 0.f, .y_min = 0.f, .y_max = 0.f, .empty =
true };
412 int length = (int)SNI_getArrayLength(text);
422 if (!has_drawn_glyph) {
423 drawn_y_bottom = box.
y_min;
424 drawn_y_top = box.
y_max;
425 has_drawn_glyph =
true;
427 drawn_y_bottom = MIN(box.
y_min, drawn_y_bottom);
428 drawn_y_top = MAX(box.
y_max, drawn_y_top);
433 assert(drawn_y_top >= drawn_y_bottom);
434 scaled_height = scale * (drawn_y_top - drawn_y_bottom);
440 LOG_MICROVG_FONT_END(stringHeight);
445 jfloat LLVG_FONT_IMPL_get_baseline_position(jint faceHandle, jfloat size) {
446 LOG_MICROVG_FONT_START(baseline);
449 if (LLVG_FONT_UNLOADED == faceHandle) {
450 ret = (jfloat)LLVG_RESOURCE_CLOSED;
452 FT_Face face = (FT_Face)faceHandle;
453 float advance_y = 0.f;
457 advance_y = (face->ascender * scale);
462 LOG_MICROVG_FONT_END(baseline);
467 jfloat LLVG_FONT_IMPL_get_height(jint faceHandle, jfloat size) {
468 LOG_MICROVG_FONT_START(height);
471 if (LLVG_FONT_UNLOADED == faceHandle) {
472 ret = (jfloat)LLVG_RESOURCE_CLOSED;
474 FT_Face face = (FT_Face)faceHandle;
475 float scaled_height = 0.f;
484 LOG_MICROVG_FONT_END(height);
489 void LLVG_FONT_IMPL_dispose(jint faceHandle) {
491 int32_t unregistered = SNI_unregisterResource((
void *)faceHandle, (SNI_closeFunction) & __dispose_registered_font);
492 assert(SNI_OK == unregistered);
493 __dispose_font((
void *)faceHandle);
497 bool LLVG_FONT_IMPL_has_complex_layouter(
void) {
498 #if defined VG_FEATURE_FONT_COMPLEX_LAYOUT && (VG_FEATURE_FONT_COMPLEX_LAYOUT == 1)
509 static void __dispose_font(
void *faceHandle) {
510 FT_Face face = (FT_Face)faceHandle;
512 #if defined VG_FEATURE_FONT_EXTERNAL && (VG_FEATURE_FONT_EXTERNAL == 1)
516 FT_Stream stream = face->stream;
517 bool is_own_stream = (&__close_external_resource == stream->close);
525 #if defined VG_FEATURE_FONT_EXTERNAL && (VG_FEATURE_FONT_EXTERNAL == 1)
527 ft_mem_free(library->memory, stream);
536 static void __dispose_registered_font(
void *faceHandle) {
540 __dispose_font(faceHandle);
543 static FT_Error __load_memory_font(FT_Face *face,
void *data,
int length) {
544 return FT_New_Memory_Face(library, data, length, 0, face);
547 static FT_Error __load_internal_font(FT_Face *face, jchar *font_name) {
548 SNIX_resource font_resource;
551 if (0 == SNIX_get_resource(font_name, &font_resource)) {
552 error = __load_memory_font(face, font_resource.data, font_resource.size);
554 error = FT_ERR(Cannot_Open_Resource);
559 #if defined VG_FEATURE_FONT_EXTERNAL && (VG_FEATURE_FONT_EXTERNAL == 1)
561 static FT_Error __load_external_font(FT_Face *face, jchar *font_name) {
565 char const *ext_path = &(((
char const *)(font_name))[1]) ;
566 RES_ID resource_id = LLEXT_RES_open(ext_path);
568 if (0 <= resource_id) {
569 int32_t resource_size = LLEXT_RES_available(resource_id);
572 int32_t base_address = LLEXT_RES_getBaseAddress(resource_id);
574 if (-1 != base_address) {
577 error = __load_memory_font(face, (
void *)base_address, resource_size);
580 LLEXT_RES_close(resource_id);
585 args.flags = FT_OPEN_STREAM;
587 args.stream = (FT_StreamRec *)ft_mem_alloc(library->memory,
sizeof(FT_StreamRec), &error);
589 if (FT_ERR(Ok) == error) {
590 args.stream->base = NULL;
591 args.stream->size = resource_size;
592 args.stream->pos = 0;
593 args.stream->descriptor.value = resource_id;
595 args.stream->read = &__read_external_resource;
596 args.stream->close = &__close_external_resource;
598 error = FT_Open_Face(library, &args, 0, face);
600 error = FT_ERR(Out_Of_Memory);
604 error = FT_ERR(Cannot_Open_Resource);
610 static unsigned long __read_external_resource(FT_Stream stream,
unsigned long offset,
unsigned char *buffer,
611 unsigned long count) {
612 int32_t size = count;
613 RES_ID resource_id = (RES_ID)(stream->descriptor.value);
614 LLEXT_RES_seek(resource_id, offset);
615 LLEXT_RES_read(resource_id, buffer, &size);
619 static void __close_external_resource(FT_Stream stream) {
620 RES_ID resource_id = (RES_ID)(stream->descriptor.value);
621 LLEXT_RES_close(resource_id);
626 static void __register_font_description(
void *resource,
char *buffer, uint32_t bufferLength) {
635 jlong Java_com_microej_microvg_test_TestResource_getSNICloseFunctionForFont(
void) {
636 return (jlong) & __dispose_registered_font;
The box of the curve an outline draws, control points excluded.
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.
void VG_FREETYPE_initialize(void)
Initializes the lowlevel font library.
jfloat VG_FREETYPE_get_scale(jint face_handle, jfloat size)
Computes the scale that converts font units to pixels at the given size.
jfloat VG_FREETYPE_string_width(jchar *text, jint length, jint face_handle, jfloat size, jfloat letter_spacing)
Measures the width of a text for the specified font and size.
MicroEJ MicroVG library low level API: helper to implement library natives methods.
#define REGISTERDESC(desc, buf, buf_len)
Registers the description of a SNI close function.
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 LLUI_DISPLAY_waitAsynchronousDrawingEnd(void)
Waits until the end of current asynchronous drawing.
#define VG_LOG_INFO(fmt,...)
Logs an informative message. The format has no trailing line return.
void VG_HELPER_layout_stop(void)
Releases what the layouter still holds for the current iteration. Does nothing when there is nothing ...
#define FT_FACE_FLAG_COMPLEX_LAYOUT
Freetype supplementary flag for complex layout Uses a free bit in freetype face flags to convey the c...
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.
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: box of the curve an outline draws.
void VG_OUTLINE_BOX_compute(const FT_Outline *outline, VG_OUTLINE_BOX *box)
Computes the box of the curve the given outline draws, where the box a font declares also bounds the ...