From 3e5ff0af91602e547a5f1de09235b433c5e9c201 Mon Sep 17 00:00:00 2001 From: Vincent Wei Date: Sun, 24 Mar 2019 12:35:31 +0800 Subject: [PATCH] tune implementation --- include/gdi.h | 2 +- src/newgdi/layout-ellipsize.c | 145 ++++++++++++++-------------------- src/newgdi/layout-utils.c | 19 ++--- src/newgdi/layoutinfo.c | 49 ++++++------ src/newgdi/layoutinfo.h | 7 +- src/newgdi/textrunsinfo.c | 41 +++++++--- src/newgdi/textrunsinfo.h | 9 +++ 7 files changed, 135 insertions(+), 137 deletions(-) diff --git a/include/gdi.h b/include/gdi.h index dd6a0a65..5de4e63d 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -11408,7 +11408,7 @@ MG_EXPORT int GUIAPI GetACharsExtentPoint (HDC hdc, Achar32* achars, int nr_achars, int max_extent, SIZE* size); /** - * \fn void GUIAPI GetGlyphValue (LOGFONT* logfont, Achar32 chv) + * \fn Glyph32 GUIAPI GetGlyphValue (LOGFONT* logfont, Achar32 chv) * \brief Get the LOGFONT glyph value of an abstract character. * * \param logfont The logical font. diff --git a/src/newgdi/layout-ellipsize.c b/src/newgdi/layout-ellipsize.c index 0c465bc9..59728f29 100644 --- a/src/newgdi/layout-ellipsize.c +++ b/src/newgdi/layout-ellipsize.c @@ -133,7 +133,8 @@ struct _EllipsizeState int total_width; /* Original width of line in Pango units */ int gap_center; /* Goal for center of gap */ - GlyphItem *ellipsis_run;/* Run created to hold ellipsis */ + TEXTRUN *ellipsis_trun; /* Text run created to hold ellipsis */ + GLYPHRUN *ellipsis_grun; /* Glyph run created to hold ellipsis */ int ellipsis_width; /* Width of ellipsis, in Pango units */ int ellipsis_is_cjk; /* Whether the first character in the ellipsized * is wide; this triggers us to try to use a @@ -159,7 +160,6 @@ static void init_state (EllipsizeState *state, LAYOUTLINE *line) int start_offset; state->layout = line->layout; - //state->attrs = attrs; state->n_runs = line->nr_runs; state->run_info = malloc(sizeof(RunInfo) * state->n_runs); @@ -180,10 +180,9 @@ static void init_state (EllipsizeState *state, LAYOUTLINE *line) i++; } - state->ellipsis_run = NULL; + state->ellipsis_trun = NULL; + state->ellipsis_grun = NULL; state->ellipsis_is_cjk = FALSE; - //state->line_start_attr = NULL; - //state->gap_start_attr = NULL; } /* Cleanup memory allocation @@ -294,96 +293,72 @@ static BOOL ends_at_ellipsization_boundary (EllipsizeState *state, LineIter *ite return state->layout->bos[run_info->start_offset + iter->run_iter.end_char + 1] & BOV_GB_CURSOR_POS; } -/* Helper function to re-itemize a string of text - */ -static TEXTRUN * itemize_text (EllipsizeState *state, const char *text) -{ -#if 0 - TEXTRUN *item; - GList *items; - items = pango_itemize (state->layout->context, text, 0, strlen (text), attrs, NULL); - g_assert (g_list_length (items) == 1); - - item = items->data; - g_list_free (items); - return item; -#endif - - return NULL; -} - /* Shapes the ellipsis using the font and is_cjk information computed by * update_ellipsis_shape() from the first character in the gap. */ static void shape_ellipsis (EllipsizeState *state) { - //PangoAttrList *attrs = pango_attr_list_new (); - //GSList *run_attrs; - TEXTRUN *item; + Glyph32 ellipsis_gv; + TEXTRUN *text_run; GLYPHSTRING *glyphs; - //GSList *l; - //PangoAttribute *fallback; - const char *ellipsis_text; + Uchar32 ellipsis_ucs[3]; + int nr_ucs = 0; int i; - /* Create/reset state->ellipsis_run + /* Create/reset state->ellipsis_grun */ - if (!state->ellipsis_run) { - state->ellipsis_run = malloc (sizeof(GlyphItem)); - state->ellipsis_run->gs = __mg_glyph_string_new (); - state->ellipsis_run->trun = NULL; + if (!state->ellipsis_grun) { + state->ellipsis_grun = malloc (sizeof(GlyphItem)); + state->ellipsis_grun->gs = __mg_glyph_string_new (); + state->ellipsis_grun->trun = NULL; } - if (state->ellipsis_run->trun) { - __mg_text_run_free (state->ellipsis_run->trun); - state->ellipsis_run->trun = NULL; + if (state->ellipsis_trun) { + __mg_text_run_free (state->ellipsis_trun); + state->ellipsis_trun = NULL; } -#if 0 - /* Create an attribute list - */ - run_attrs = pango_attr_iterator_get_attrs (state->gap_start_attr); - for (l = run_attrs; l; l = l->next) - { - PangoAttribute *attr = l->data; - attr->start_index = 0; - attr->end_index = G_MAXINT; - - pango_attr_list_insert (attrs, attr); - } - - g_slist_free (run_attrs); - - fallback = pango_attr_fallback_new (FALSE); - fallback->start_index = 0; - fallback->end_index = G_MAXINT; - pango_attr_list_insert (attrs, fallback); -#endif - /* First try using a specific ellipsis character in the best matching font */ - if (state->ellipsis_is_cjk) - ellipsis_text = "\342\213\257"; /* U+22EF: MIDLINE HORIZONTAL ELLIPSIS, used for CJK */ - else - ellipsis_text = "\342\200\246"; /* U+2026: HORIZONTAL ELLIPSIS */ - - item = itemize_text (state, ellipsis_text); - - /* If that fails we use "..." in the first matching font - */ - if (0) { - __mg_text_run_free (item); - ellipsis_text = "..."; - item = itemize_text (state, ellipsis_text); + if (state->ellipsis_is_cjk) { + /* U+22EF: MIDLINE HORIZONTAL ELLIPSIS, used for CJK */ + ellipsis_ucs[0] = 0x22EF; // "\342\213\257"; + nr_ucs = 1; + } + else { + /* U+2026: HORIZONTAL ELLIPSIS */ + ellipsis_ucs[0] = 0x2026; // "\342\200\246"; + nr_ucs = 1; } - state->ellipsis_run->trun = item; + + text_run = __mg_text_run_new_orphan (state->layout->truninfo, + ellipsis_ucs, nr_ucs); + // TODO: other attributes of the text run. + + text_run->lf = __mg_create_logfont_for_run(state->layout->truninfo, text_run); + ellipsis_gv = GetGlyphValue(text_run->lf, ellipsis_ucs[0]); + + /* If the devfont of the glyph value of the specific ellipsis character + * is SBC devfont, we use "...". + */ + if (DFI_IN_GLYPH(ellipsis_gv) == 0) { + __mg_text_run_free (text_run); + ellipsis_ucs[0] = '.'; + ellipsis_ucs[1] = '.'; + ellipsis_ucs[2] = '.'; + nr_ucs = 3; + text_run = __mg_text_run_new_orphan (state->layout->truninfo, + ellipsis_ucs, nr_ucs); + } + + state->ellipsis_trun = text_run; /* Now shape */ - glyphs = state->ellipsis_run->gs; + glyphs = state->ellipsis_grun->gs; - __mg_shape_utf8 (ellipsis_text, strlen(ellipsis_text), item, glyphs); + __mg_shape_text_run(state->layout->truninfo, text_run, 0, nr_ucs, glyphs); state->ellipsis_width = 0; for (i = 0; i < glyphs->nr_glyphs; i++) @@ -626,10 +601,10 @@ static BOOL remove_one_span (EllipsizeState *state) /* Fixes up the properties of the ellipsis run once we've determined the final extents * of the gap */ -static void fixup_ellipsis_run (EllipsizeState *state) +static void fixup_ellipsis_grun (EllipsizeState *state) { - GLYPHSTRING *glyphs = state->ellipsis_run->gs; - TEXTRUN *item = state->ellipsis_run->trun; + GLYPHSTRING *glyphs = state->ellipsis_grun->gs; + TEXTRUN *text_run = state->ellipsis_trun; int level; int i; @@ -641,18 +616,18 @@ static void fixup_ellipsis_run (EllipsizeState *state) glyphs->glyphs[0].is_cluster_start = TRUE; - /* Fix up the item to point to the entire elided text */ - item->si = state->gap_start_iter.run_iter.start_index; - item->len = state->gap_end_iter.run_iter.end_index - item->si; + /* Fix up the text_run to point to the entire elided text */ + text_run->si = state->gap_start_iter.run_iter.start_index; + text_run->len = state->gap_end_iter.run_iter.end_index - text_run->si; - /* The level for the item is the minimum level of the elided text */ + /* The level for the text_run is the minimum level of the elided text */ level = INT_MAX; for (i = state->gap_start_iter.run_index; i <= state->gap_end_iter.run_index; i++) level = MIN (level, state->run_info[i].run->trun->el); - item->el = level; + text_run->el = level; - item->flags |= TEXTRUN_FLAG_IS_ELLIPSIS; + text_run->flags |= TEXTRUN_FLAG_IS_ELLIPSIS; } #if 0 @@ -696,7 +671,7 @@ static GSList * get_run_list (EllipsizeState *state) if (partial_start_run) result = g_slist_prepend (result, partial_start_run); - result = g_slist_prepend (result, state->ellipsis_run); + result = g_slist_prepend (result, state->ellipsis_grun); if (partial_end_run) result = g_slist_prepend (result, partial_end_run); @@ -751,7 +726,7 @@ BOOL __mg_layout_line_ellipsize (LAYOUTLINE *line, int goal_width) break; } - fixup_ellipsis_run (&state); + fixup_ellipsis_grun (&state); //g_slist_free (line->runs); //line->runs = get_run_list (&state); diff --git a/src/newgdi/layout-utils.c b/src/newgdi/layout-utils.c index c9185026..b0fc99b9 100644 --- a/src/newgdi/layout-utils.c +++ b/src/newgdi/layout-utils.c @@ -64,8 +64,10 @@ void __mg_glyph_string_free (GLYPHSTRING *string) if (string == NULL) return; - free (string->glyphs); - free (string->log_clusters); + if (string->glyphs) + free (string->glyphs); + if (string->log_clusters) + free (string->log_clusters); free (string); } @@ -122,7 +124,7 @@ BOOL __mg_glyph_item_iter_next_cluster (GlyphItemIter *iter) int glyph_index = iter->end_glyph; GLYPHSTRING *glyphs = iter->glyph_item->gs; int cluster; - TEXTRUN *item = iter->glyph_item->trun; + const TEXTRUN *item = iter->glyph_item->trun; if (LTR (iter->glyph_item)) { if (glyph_index == glyphs->nr_glyphs) @@ -186,7 +188,7 @@ BOOL __mg_glyph_item_iter_prev_cluster (GlyphItemIter *iter) int glyph_index = iter->start_glyph; GLYPHSTRING *glyphs = iter->glyph_item->gs; int cluster; - TEXTRUN *item = iter->glyph_item->trun; + const TEXTRUN *item = iter->glyph_item->trun; if (LTR (iter->glyph_item)) { if (glyph_index == 0) @@ -332,15 +334,6 @@ void __mg_glyph_item_get_logical_widths (const GlyphItem *glyph_item, } } -void __mg_shape_utf8 (const char* text, int len, - const TEXTRUN* trun, GLYPHSTRING* gs) -{ -} - -void __mg_text_run_free(TEXTRUN* trun) -{ -} - void __mg_glyph_item_letter_space (const GlyphItem* glyph_item, const Uchar32* ucs, const BreakOppo* bos, int letter_spacing) { diff --git a/src/newgdi/layoutinfo.c b/src/newgdi/layoutinfo.c index b128cb83..ea08b10e 100644 --- a/src/newgdi/layoutinfo.c +++ b/src/newgdi/layoutinfo.c @@ -168,7 +168,7 @@ struct _LayoutState { // Start index of line in layout->text int line_start_index; // Current text run - TEXTRUN* item; + const TEXTRUN* item; // Start index of line in current item */ int start_index_in_item; // the number of not fit uchars in current text run @@ -236,20 +236,20 @@ static void distribute_letter_spacing (int letter_spacing, } static GLYPHSTRING* shape_run(LAYOUTLINE *line, LayoutState *state, - TEXTRUN *item) + const TEXTRUN *item, int offset, int len) { LAYOUTINFO *layout = line->layout; GLYPHSTRING *glyphs = __mg_glyph_string_new (); - if (layout->truninfo->ucs[item->si] == '\t') + if (layout->truninfo->ucs[item->si + offset] == '\t') shape_tab(line, glyphs); else { if (state->shape_set) - shape_shape(layout->truninfo->ucs + item->si, item->len, + shape_shape(layout->truninfo->ucs + item->si + offset, len, &state->shape_ink_rect, &state->shape_logical_rect, glyphs); else - shape_full(layout->truninfo->ucs + item->si, item->len, + shape_full(layout->truninfo->ucs + item->si + offset, len, layout->truninfo->ucs, layout->truninfo->nr_ucs, layout->truninfo, item, glyphs); @@ -259,6 +259,8 @@ static GLYPHSTRING* shape_run(LAYOUTLINE *line, LayoutState *state, glyph_item.trun = item; glyph_item.gs = glyphs; + glyph_item.so = offset; + glyph_item.len = len; __mg_glyph_item_letter_space (&glyph_item, layout->truninfo->ucs, @@ -282,44 +284,43 @@ static void free_run (GLYPHRUN *run) free(run); } -static TEXTRUN *uninsert_run (LAYOUTLINE *line) +static const TEXTRUN *uninsert_run (LAYOUTLINE *line) { GLYPHRUN *run; - TEXTRUN *item; + const TEXTRUN *item; run = (GLYPHRUN*)&line->gruns.next; item = run->trun; list_del(line->gruns.next); - line->len -= item->len; + line->len -= run->len; free_run(run); return item; } static GLYPHRUN* insert_run(LAYOUTLINE *line, LayoutState *state, - TEXTRUN *text_run, int si, int len, BOOL last_run) + const TEXTRUN *text_run, int so, int len, BOOL last_run) { - GLYPHRUN *glyph_run = malloc (sizeof(GLYPHRUN)); + GLYPHRUN *glyph_run = malloc(sizeof(GLYPHRUN)); glyph_run->trun = text_run; + glyph_run->so = so; + glyph_run->len = len; if (last_run && state->log_widths_offset == 0) glyph_run->gs = state->glyphs; else - glyph_run->gs = shape_run (line, state, text_run); + glyph_run->gs = shape_run(line, state, text_run, so, len); if (last_run) { if (state->log_widths_offset > 0) - __mg_glyph_string_free (state->glyphs); + __mg_glyph_string_free(state->glyphs); state->glyphs = NULL; - free (state->log_widths); + free(state->log_widths); state->log_widths = NULL; } - glyph_run->si = si; - glyph_run->len = len; - list_add_tail(&glyph_run->list, &line->gruns); line->len += text_run->len; @@ -385,7 +386,7 @@ BreakResult process_text_run(LAYOUTINFO *layout, LAYOUTLINE *line, LayoutState *state, BOOL force_fit, BOOL no_break_at_end) { - TEXTRUN *item = state->item; + const TEXTRUN *item = state->item; BOOL shape_set = FALSE; int width; int i; @@ -396,7 +397,7 @@ BreakResult process_text_run(LAYOUTINFO *layout, #define LINE_SEPARATOR 0x2028 if (!state->glyphs) { - state->glyphs = shape_run (line, state, item); + state->glyphs = shape_run (line, state, item, 0, item->len); state->log_widths = NULL; state->log_widths_offset = 0; @@ -645,7 +646,7 @@ static void zero_line_final_space (LAYOUTLINE *line, LayoutState *state, GLYPHRUN *run) { LAYOUTINFO *layout = line->layout; - TEXTRUN *item = run->trun; + const TEXTRUN *item = run->trun; GLYPHSTRING *glyphs = run->gs; int glyph = item->el % 2 ? 0 : glyphs->nr_glyphs - 1; @@ -1101,13 +1102,12 @@ static void layout_line_postprocess (LAYOUTLINE *line, static void add_line (LAYOUTLINE *line, LayoutState *state) { +#if 0 LAYOUTINFO *layout = line->layout; - /* we prepend, then reverse the list later */ list_add_tail(&line->list, &layout->lines); layout->nr_lines++; -#if 0 if (layout->height >= 0) { PangoRectangle logical_rect; pango_layout_line_get_extents (line, NULL, &logical_rect); @@ -1115,6 +1115,8 @@ static void add_line (LAYOUTLINE *line, LayoutState *state) state->remaining_height -= layout->spacing; state->line_height = logical_rect.height; } +#else + // do nothing #endif } @@ -1139,7 +1141,7 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) state->remaining_width = state->line_width; while (state->item) { - TEXTRUN *item = state->item; + const TEXTRUN *item = state->item; BreakResult result; int old_num_chars; int old_remaining_width; @@ -1214,7 +1216,7 @@ done: add_line (line, state); state->line_of_par++; state->line_start_index += line->len; - return NULL; + return line; } static int traverse_line_glyphs(LAYOUTLINE* line, int x, int y, @@ -1293,6 +1295,7 @@ next_line: release_line(prev_line); } + layout->nr_lines ++; layout->nr_left_ucs -= next_line->len; } diff --git a/src/newgdi/layoutinfo.h b/src/newgdi/layoutinfo.h index 356341f0..b695ade5 100644 --- a/src/newgdi/layoutinfo.h +++ b/src/newgdi/layoutinfo.h @@ -66,9 +66,9 @@ struct _GLYPHSTRING { struct _GLYPHRUN { struct list_head list; - TEXTRUN* trun; // the text run to which this glyph run belongs + const TEXTRUN* trun; // the text run to which this glyph run belongs GLYPHSTRING* gs; // the glyph string - int si; // the start index in the text run + int so; // the start offset in the text run int len; // the number of the uchars }; @@ -151,6 +151,9 @@ void __mg_glyph_item_letter_space (const GlyphItem* glyph_item, BOOL __mg_layout_line_ellipsize(LAYOUTLINE *line, int goal_width); +int __mg_shape_text_run(const TEXTRUNSINFO* info, const TEXTRUN* run, + int so, int len, GLYPHSTRING* glyphs); + void __mg_shape_utf8 (const char* text, int len, const TEXTRUN* trun, GLYPHSTRING* gs); diff --git a/src/newgdi/textrunsinfo.c b/src/newgdi/textrunsinfo.c index 1c514385..549b4879 100644 --- a/src/newgdi/textrunsinfo.c +++ b/src/newgdi/textrunsinfo.c @@ -165,8 +165,8 @@ static void state_update_for_new_run (TEXTRUNSTATE *state) } /* Use MiniGUI resource manager to avoid duplicated logfonts */ -static LOGFONT* create_logfont_for_ort(const TEXTRUNSINFO* runinfo, - GlyphOrient ort) +LOGFONT* __mg_create_logfont_for_run(const TEXTRUNSINFO* runinfo, + const TEXTRUN* run) { char fontname[LEN_LOGFONT_NAME_FULL + 1]; int orient_pos = fontGetOrientPosFromName(runinfo->fontname); @@ -178,7 +178,7 @@ static LOGFONT* create_logfont_for_ort(const TEXTRUNSINFO* runinfo, memset (fontname, 0, LEN_LOGFONT_NAME_FULL + 1); strncpy (fontname, runinfo->fontname, LEN_LOGFONT_NAME_FULL); - switch (ort) { + switch (run->ort) { case GLYPH_ORIENT_UPRIGHT: fontname[orient_pos] = FONT_ORIENT_UPRIGHT; break; @@ -192,7 +192,7 @@ static LOGFONT* create_logfont_for_ort(const TEXTRUNSINFO* runinfo, fontname[orient_pos] = FONT_ORIENT_SIDEWAYS_LEFT; break; default: - _WRN_PRINTF("bad orientation param: %d", ort); + _WRN_PRINTF("bad orientation param: %d", run->ort); return NULL; } @@ -206,7 +206,7 @@ static LOGFONT* create_logfont_for_ort(const TEXTRUNSINFO* runinfo, return lf; } -static void release_logfont_for_run(const TEXTRUNSINFO* runinfo, +void __mg_release_logfont_for_run(const TEXTRUNSINFO* runinfo, const TEXTRUN* run) { char fontname[LEN_LOGFONT_NAME_FULL + 1]; @@ -253,10 +253,6 @@ static void state_add_character(TEXTRUNSTATE *state, } state->run = malloc(sizeof(TEXTRUN)); - if (no_shaping) - state->run->lf = NULL; - else - state->run->lf = create_logfont_for_ort(state->runinfo, state->ort_rsv); state->run->si = pos - state->text; state->run->len = 1; state->run->lc = state->derived_lang; @@ -265,6 +261,12 @@ static void state_add_character(TEXTRUNSTATE *state, state->run->dir = state->runinfo->run_dir; state->run->ort = state->ort_rsv; + if (no_shaping) + state->run->lf = NULL; + else + state->run->lf = __mg_create_logfont_for_run(state->runinfo, + state->run); + /* The level vs. gravity dance: * If gravity is SOUTH, leave level untouched. * If gravity is NORTH, step level one up, to @@ -362,7 +364,7 @@ static BOOL state_next (TEXTRUNSTATE *state) return TRUE; } -static BOOL create_glyph_runs(TEXTRUNSINFO* runinfo, BidiLevel* els) +static BOOL create_text_runs(TEXTRUNSINFO* runinfo, BidiLevel* els) { BOOL ok = FALSE; TEXTRUNSTATE state; @@ -614,8 +616,8 @@ TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(Uchar32* ucs, int nr_ucs, runinfo->all_odd = (level_and & 0x1) == 1; #endif - if (!create_glyph_runs(runinfo, els)) { - _ERR_PRINTF("%s: failed to call create_glyph_runs.\n", + if (!create_text_runs(runinfo, els)) { + _ERR_PRINTF("%s: failed to call create_text_runs.\n", __FUNCTION__); goto out; } @@ -670,6 +672,19 @@ TEXTRUN* __mg_textruns_get_by_offset(const TEXTRUNSINFO* runinfo, return NULL; } +TEXTRUN* __mg_text_run_new_orphan(const TEXTRUNSINFO* info, + const Uchar32* ucs, int nr_ucs) +{ + TEXTRUN* trun = malloc(sizeof(TEXTRUN)); + + return trun; +} + +void __mg_text_run_free_orphan(TEXTRUN* trun) +{ + free(trun); +} + BOOL GUIAPI SetTextColorInTextRuns(TEXTRUNSINFO* runinfo, int start_index, int length, RGBCOLOR color) { @@ -714,7 +729,7 @@ BOOL GUIAPI DestroyTextRunsInfo(TEXTRUNSINFO* runinfo) TEXTRUN* run = (TEXTRUN*)runinfo->truns.prev; list_del(runinfo->truns.prev); if (run->lf) - release_logfont_for_run(runinfo, run); + __mg_release_logfont_for_run(runinfo, run); free(run); } diff --git a/src/newgdi/textrunsinfo.h b/src/newgdi/textrunsinfo.h index b3650354..427bb3b1 100644 --- a/src/newgdi/textrunsinfo.h +++ b/src/newgdi/textrunsinfo.h @@ -125,6 +125,15 @@ struct _TEXTRUNSINFO { extern "C" { #endif /* __cplusplus */ +LOGFONT* __mg_create_logfont_for_run(const TEXTRUNSINFO* runinfo, + const TEXTRUN* run); +void __mg_release_logfont_for_run(const TEXTRUNSINFO* runinfo, + const TEXTRUN* run); + +TEXTRUN* __mg_text_run_new_orphan(const TEXTRUNSINFO* info, + const Uchar32* ucs, int nr_ucs); +void __mg_text_run_free_orphan(TEXTRUN* trun); + RGBCOLOR __mg_textruns_get_color(const TEXTRUNSINFO* runinfo, int index); TEXTRUN* __mg_textruns_get_by_offset(const TEXTRUNSINFO* runinfo, int offset, int *start_index);