EAPI Eina_Bool evas_common_text_props_content_create(void *_fi, const Eina_Unicode *text, Evas_Text_Props *text_props, const Evas_BiDi_Paragraph_Props *par_props, size_t par_pos, int len) { RGBA_Font_Int *fi = (RGBA_Font_Int *) _fi; if (text_props->info) { evas_common_text_props_content_unref(text_props); } if (len == 0) { text_props->info = NULL; text_props->start = text_props->len = text_props->text_offset = 0; } text_props->info = calloc(1, sizeof(Evas_Text_Props_Info)); text_props->font_instance = fi; evas_common_font_int_reload(fi); if (fi->src->current_size != fi->size) { FTLOCK(); FT_Activate_Size(fi->ft.size); FTUNLOCK(); fi->src->current_size = fi->size; } #ifdef OT_SUPPORT size_t char_index; Evas_Font_Glyph_Info *gl_itr; Evas_Coord pen_x = 0, adjust_x = 0; (void) par_props; (void) par_pos; evas_common_font_ot_populate_text_props(text, text_props, len); gl_itr = text_props->info->glyph; for (char_index = 0 ; char_index < text_props->len ; char_index++) { FT_UInt idx; RGBA_Font_Glyph *fg; Eina_Bool is_replacement = EINA_FALSE; /* If we got a malformed index, show the replacement char instead */ if (gl_itr->index == 0) { gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR); is_replacement = EINA_TRUE; } idx = gl_itr->index; LKL(fi->ft_mutex); fg = evas_common_font_int_cache_glyph_get(fi, idx); if (!fg) { LKU(fi->ft_mutex); continue; } LKU(fi->ft_mutex); gl_itr->x_bear = fg->glyph_out->left; gl_itr->width = fg->glyph_out->bitmap.width; /* text_props->info->glyph[char_index].advance = * text_props->info->glyph[char_index].index = * already done by the ot function */ if (EVAS_FONT_CHARACTER_IS_INVISIBLE( text[text_props->info->ot[char_index].source_cluster])) { gl_itr->index = 0; /* Reduce the current advance */ if (gl_itr > text_props->info->glyph) { adjust_x -= gl_itr->pen_after - (gl_itr - 1)->pen_after; } else { adjust_x -= gl_itr->pen_after; } } else { if (is_replacement) { /* Update the advance accordingly */ adjust_x += (pen_x + (fg->glyph->advance.x >> 16)) - gl_itr->pen_after; } pen_x = gl_itr->pen_after; } gl_itr->pen_after += adjust_x; fi = text_props->font_instance; gl_itr++; } #else /* We are walking the string in visual ordering */ Evas_Font_Glyph_Info *gl_itr; Eina_Bool use_kerning; FT_UInt prev_index; FT_Face pface = NULL; Evas_Coord pen_x = 0; int adv_d, i; #if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT) Eina_Unicode *base_str = NULL; if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) { text = base_str = eina_unicode_strndup(text, len); evas_bidi_shape_string(base_str, par_props, par_pos, len); } #else (void) par_props; (void) par_pos; #endif FTLOCK(); use_kerning = FT_HAS_KERNING(fi->src->ft.face); FTUNLOCK(); prev_index = 0; i = len; text_props->info->glyph = calloc(len, sizeof(Evas_Font_Glyph_Info)); if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) { text += len - 1; adv_d = -1; } else { adv_d = 1; } gl_itr = text_props->info->glyph; for ( ; i > 0 ; gl_itr++, text += adv_d, i--) { FT_UInt idx; RGBA_Font_Glyph *fg; int _gl, kern; Evas_Coord adv; _gl = *text; if (_gl == 0) break; idx = evas_common_get_char_index(fi, _gl); if (idx == 0) { idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR); } LKL(fi->ft_mutex); fg = evas_common_font_int_cache_glyph_get(fi, idx); if (!fg) { LKU(fi->ft_mutex); continue; } kern = 0; if ((use_kerning) && (prev_index) && (idx) && (pface == fi->src->ft.face)) { if (evas_common_font_query_kerning(fi, prev_index, idx, &kern)) { pen_x += kern; (gl_itr - 1)->pen_after += EVAS_FONT_ROUND_26_6_TO_INT(kern); } } pface = fi->src->ft.face; LKU(fi->ft_mutex); gl_itr->index = idx; gl_itr->x_bear = fg->glyph_out->left; adv = fg->glyph->advance.x >> 10; gl_itr->width = fg->glyph_out->bitmap.width; if (EVAS_FONT_CHARACTER_IS_INVISIBLE(_gl)) { gl_itr->index = 0; } else { pen_x += adv; } gl_itr->pen_after = EVAS_FONT_ROUND_26_6_TO_INT(pen_x); prev_index = idx; } text_props->len = len; # if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT) if (base_str) free(base_str); # endif #endif text_props->text_len = len; text_props->info->refcount = 1; return EINA_TRUE; }
static inline void _content_create_regular(RGBA_Font_Int *fi, const Eina_Unicode *text, Evas_Text_Props *text_props, const Evas_BiDi_Paragraph_Props *par_props, size_t par_pos, int len, Evas_Text_Props_Mode mode) { /* We are walking the string in visual ordering */ Evas_Font_Glyph_Info *gl_itr; Eina_Bool use_kerning; FT_UInt prev_index; FT_Face pface = NULL; Evas_Coord pen_x = 0; int adv_d, i; #if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT) Eina_Unicode *base_str = NULL; if (mode == EVAS_TEXT_PROPS_MODE_SHAPE) { if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) { text = base_str = eina_unicode_strndup(text, len); evas_bidi_shape_string(base_str, par_props, par_pos, len); } } #else (void) mode; (void) par_props; (void) par_pos; #endif FTLOCK(); use_kerning = FT_HAS_KERNING(fi->src->ft.face); FTUNLOCK(); prev_index = 0; i = len; text_props->info->glyph = calloc(len, sizeof(Evas_Font_Glyph_Info)); if (text_props->bidi.dir == EVAS_BIDI_DIRECTION_RTL) { text += len - 1; adv_d = -1; } else { adv_d = 1; } gl_itr = text_props->info->glyph; for ( ; i > 0 ; gl_itr++, text += adv_d, i--) { FT_UInt idx; RGBA_Font_Glyph *fg; int _gl, kern; Evas_Coord adv; _gl = *text; if (_gl == 0) break; idx = evas_common_get_char_index(fi, _gl); if (idx == 0) { idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR); } fg = evas_common_font_int_cache_glyph_get(fi, idx); if (!fg) continue; kern = 0; if ((use_kerning) && (prev_index) && (idx) && (pface == fi->src->ft.face)) { if (evas_common_font_query_kerning(fi, prev_index, idx, &kern)) { pen_x += kern; (gl_itr - 1)->pen_after += EVAS_FONT_ROUND_26_6_TO_INT(kern); } } pface = fi->src->ft.face; gl_itr->index = idx; gl_itr->x_bear = fg->x_bear; gl_itr->y_bear = fg->y_bear; adv = fg->glyph->advance.x >> 10; gl_itr->width = fg->width; if (EVAS_FONT_CHARACTER_IS_INVISIBLE(_gl)) { gl_itr->index = 0; } else { pen_x += adv; } gl_itr->pen_after = EVAS_FONT_ROUND_26_6_TO_INT(pen_x); prev_index = idx; } text_props->len = len; # if !defined(OT_SUPPORT) && defined(BIDI_SUPPORT) if (base_str) free(base_str); # endif }
/** * @internal * Find the end of a run according to font coverage, and return the base script * font and the current wanted font. * * @param[in] fn the font to use. * @param script_fi The base font instance to be used with the script. If NULL, then it's calculated and returned in this variable, if not NULL, it's used and not modified. * @param[out] cur_fi The font instance found for the current run. * @param[in] script the base script * @param[in] text the text to work on. * @param[in] run_let the current run len, i.e "search limit". * @return length of the run found. */ EAPI int evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi, RGBA_Font_Int **cur_fi, Evas_Script_Type script, const Eina_Unicode *text, int run_len) { RGBA_Font_Int *fi = NULL; const Eina_Unicode *run_end = text + run_len; const Eina_Unicode *itr; /* If there's no current script_fi, find it first */ if (!*script_fi) { const Eina_Unicode *base_char = NULL; /* Skip common chars */ for (base_char = text ; (base_char < run_end) && (evas_common_language_char_script_get(*base_char) != script) ; base_char++) ; if (base_char == run_end) base_char = text; /* Find the first renderable char */ while (base_char < run_end) { /* 0x1F is the last ASCII contral char, just a hack in * the meanwhile. */ if ((*base_char > 0x1F) && evas_common_font_glyph_search(fn, &fi, *base_char)) break; base_char++; } /* If everything else fails, at least try to find a font for the * replacement char */ if (base_char == run_end) evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR); if (!fi) fi = fn->fonts->data; *script_fi = fi; } else { fi = *script_fi; } /* Find the longest run of the same font starting from the start position * and update cur_fi accordingly. */ itr = text; while (itr < run_end) { RGBA_Font_Int *tmp_fi; /* Itr will end up being the first of the next run */ for ( ; itr < run_end ; itr++) { /* 0x1F is the last ASCII contral char, just a hack in * the meanwhile. */ if (*itr <= 0x1F) continue; /* Break if either it's not in the font, or if it is in the * script's font. */ if (!evas_common_get_char_index(fi, *itr)) break; if (fi != *script_fi) { if (evas_common_get_char_index(*script_fi, *itr)) break; } } /* Abort if we reached the end */ if (itr == run_end) break; /* If the script font doesn't fit even one char, find a new font. */ if (itr == text) { /* If we can find a font, use it. Otherwise, find the first * char the run of chars that can't be rendered until the first * one that can. */ if (evas_common_font_glyph_search(fn, &tmp_fi, *itr)) { fi = tmp_fi; } else { itr++; /* Go through all the chars that can't be rendered with any * font */ for ( ; itr < run_end ; itr++) { tmp_fi = fi; if (evas_common_get_char_index(fi, *itr) || evas_common_font_glyph_search(fn, &tmp_fi, *itr)) { fi = tmp_fi; break; } } /* If we found a renderable character and the found font * can render the replacement char, continue, otherwise * find a font most suitable for the replacement char and * break */ if ((itr == run_end) || !evas_common_get_char_index(fi, REPLACEMENT_CHAR)) { evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR); break; } } itr++; } else { /* If this char is not renderable by any font, but the replacement * char can be rendered using the currentfont, continue this * run. */ if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr) && evas_common_get_char_index(fi, REPLACEMENT_CHAR)) { itr++; } else { /* Done, we did as much as possible */ break; } } } if (fi) *cur_fi = fi; else *cur_fi = *script_fi; return itr - text; }
static inline void _content_create_ot(RGBA_Font_Int *fi, const Eina_Unicode *text, Evas_Text_Props *text_props, int len, Evas_Text_Props_Mode mode) { size_t char_index; Evas_Font_Glyph_Info *gl_itr; Evas_Coord pen_x = 0, adjust_x = 0; evas_common_font_ot_populate_text_props(text, text_props, len, mode); gl_itr = text_props->info->glyph; for (char_index = 0 ; char_index < text_props->len ; char_index++) { FT_UInt idx; RGBA_Font_Glyph *fg; Eina_Bool is_replacement = EINA_FALSE; /* If we got a malformed index, show the replacement char instead */ if (gl_itr->index == 0) { gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR); is_replacement = EINA_TRUE; } idx = gl_itr->index; LKL(fi->ft_mutex); fg = evas_common_font_int_cache_glyph_get(fi, idx); if (!fg) { LKU(fi->ft_mutex); continue; } LKU(fi->ft_mutex); gl_itr->x_bear = fg->x_bear; gl_itr->y_bear = fg->y_bear; gl_itr->width = fg->width; /* text_props->info->glyph[char_index].advance = * text_props->info->glyph[char_index].index = * already done by the ot function */ if (EVAS_FONT_CHARACTER_IS_INVISIBLE( text[text_props->info->ot[char_index].source_cluster])) { gl_itr->index = 0; /* Reduce the current advance */ if (gl_itr > text_props->info->glyph) { adjust_x -= gl_itr->pen_after - (gl_itr - 1)->pen_after; } else { adjust_x -= gl_itr->pen_after; } } else { if (is_replacement) { /* Update the advance accordingly */ adjust_x += (pen_x + (fg->glyph->advance.x >> 16)) - gl_itr->pen_after; } pen_x = gl_itr->pen_after; } gl_itr->pen_after += adjust_x; fi = text_props->font_instance; gl_itr++; } }