From f5e1144cbe99aa7575543510855692d91ea7202e Mon Sep 17 00:00:00 2001 From: Vincent Wei Date: Tue, 26 Mar 2019 11:24:31 +0800 Subject: [PATCH] debug LayoutInfo implementaion --- include/gdi.h | 2 +- src/newgdi/layout-utils.c | 16 ++- src/newgdi/layoutinfo.c | 265 +++++++++++++++++++++++++++++--------- src/newgdi/textrunsinfo.c | 2 +- 4 files changed, 215 insertions(+), 70 deletions(-) diff --git a/include/gdi.h b/include/gdi.h index 1afd4733..dd81454f 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -12553,7 +12553,7 @@ typedef struct _TEXTRUNSINFO TEXTRUNSINFO; /** * Split a Uchar32 paragraph string in mixed scripts into text runs. */ -MG_EXPORT TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(Uchar32* ucs, int nr_ucs, +MG_EXPORT TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(const Uchar32* ucs, int nr_ucs, LanguageCode lang_code, ParagraphDir base_dir, GlyphRunDir run_dir, GlyphOrient glyph_orient, GlyphOrientPolicy orient_policy, const char* logfont_name, RGBCOLOR color); diff --git a/src/newgdi/layout-utils.c b/src/newgdi/layout-utils.c index f8bf0d1d..e9438d3a 100644 --- a/src/newgdi/layout-utils.c +++ b/src/newgdi/layout-utils.c @@ -42,6 +42,8 @@ #include #include +#define DEBUG + #include "common.h" #ifdef _MGCHARSET_UNICODE @@ -248,12 +250,18 @@ LayoutRun* __mg_layout_run_split(LayoutRun *orig, int split_index) if (split_index >= orig->len) return NULL; + _DBG_PRINTF("%s: orig: %d, %d\n", + __FUNCTION__, orig->si, orig->len); + new_run = __mg_layout_run_copy(orig); new_run->len = split_index; orig->si += split_index; orig->len -= split_index; + _DBG_PRINTF("%s: new layout run: %d, %d; orig: %d, %d\n", + __FUNCTION__, new_run->si, new_run->len, orig->si, orig->len); + return new_run; } @@ -358,12 +366,9 @@ void __mg_glyph_run_free(GlyphRun* run) * be at least one byte assigned to each item, you can't create a * zero-length item). * - * This function is similar in function to pango_item_split() (and uses - * it internally.) - * * Return value: the newly allocated item representing text before * @split_index, which should be freed - * with pango_glyph_run_free(). + * with __mg_glyph_run_free(). **/ GlyphRun *__mg_glyph_run_split (GlyphRun *orig, int split_index) { @@ -381,6 +386,9 @@ GlyphRun *__mg_glyph_run_split (GlyphRun *orig, int split_index) if (split_index >= orig->lrun->len) return NULL; + _DBG_PRINTF("%s: called, orig: %d, %d, split at: %d\n", + __FUNCTION__, orig->lrun->si, orig->lrun->len, split_index); + if (LTR (orig)) { for (i = 0; i < orig->gstr->nr_glyphs; i++) { if (orig->gstr->log_clusters[i] >= split_index) diff --git a/src/newgdi/layoutinfo.c b/src/newgdi/layoutinfo.c index 29e01b3c..783f20a6 100644 --- a/src/newgdi/layoutinfo.c +++ b/src/newgdi/layoutinfo.c @@ -42,6 +42,8 @@ #include #include +#define DEBUG + #include "common.h" #ifdef _MGCHARSET_UNICODE @@ -402,15 +404,81 @@ static void free_glyph_run (GlyphRun *grun) free(grun); } -static void uninsert_run (LAYOUTLINE *line) +#ifdef DEBUG +static inline void print_line_runs(const LAYOUTLINE* line, const char* func) +{ + int j = 0; + struct list_head* i; + + _DBG_PRINTF("Runs in line after calling %s (line length: %d):\n", + func, line->len); + + list_for_each(i, &line->gruns) { + GlyphRun* run = (GlyphRun*)i; + _DBG_PRINTF("RUN NO.: %d\n", j); + _DBG_PRINTF(" ADDRESS: %p\n", run); + _DBG_PRINTF(" INDEX: %d\n", run->lrun->si); + _DBG_PRINTF(" LENGHT: %d\n", run->lrun->len); + _DBG_PRINTF(" EMBEDDING LEVEL:%d\n", run->lrun->len); + _DBG_PRINTF(" NR GLYPHS: %d\n", run->gstr->nr_glyphs); + j++; + } +} + +static inline void print_run(const GlyphRun* run, const char* func) +{ + _DBG_PRINTF("Run in %s:\n", func); + _DBG_PRINTF(" ADDRESS: %p\n", run); + _DBG_PRINTF(" INDEX: %d\n", run->lrun->si); + _DBG_PRINTF(" LENGHT: %d\n", run->lrun->len); + _DBG_PRINTF(" EMBEDDING LEVEL:%d\n", run->lrun->len); + _DBG_PRINTF(" NR GLYPHS: %d\n", run->gstr->nr_glyphs); +} + +static inline void list_print(struct list_head* head, const char* desc) +{ + int i = 0; + struct list_head* e; + + printf ("entries in list (%p, next: %p, prev: %p) %s\n", + head, head->next, head->prev, desc); + list_for_each(e, head) { + printf ("%d: %p\n", i, e); + i++; + } +} + +#else + +static inline void print_line_runs(const LAYOUTLINE* line, const char* func) +{ + // do nothing. +} + +static inline void print_run(const GlyphRun* run, const char* func) +{ + // do nothing. +} + +static inline void list_print(struct list_head* head, const char* desc) +{ + // do nothing. +} + +#endif + +static void uninsert_run(LAYOUTLINE *line) { GlyphRun *grun; - grun = (GlyphRun*)&line->gruns.next; + grun = (GlyphRun*)line->gruns.next; + list_del(line->gruns.next); line->len -= grun->lrun->len; free_glyph_run(grun); + + print_line_runs(line, __FUNCTION__); } static GlyphRun* insert_run(LAYOUTLINE *line, LayoutState *state, @@ -436,6 +504,8 @@ static GlyphRun* insert_run(LAYOUTLINE *line, LayoutState *state, list_add_tail(&glyph_run->list, &line->gruns); line->len += layout_run->len; + print_line_runs(line, __FUNCTION__); + return glyph_run; } @@ -628,10 +698,13 @@ retry_break: new_lrun = __mg_layout_run_split(lrun, break_num_chars); + state->lrun = new_lrun; + __mg_layout_run_free(lrun); + /* Add the width back, to the line, reshape, subtract the new width */ state->remaining_width += break_width; - grun = insert_run (line, state, new_lrun, FALSE); + grun = insert_run(line, state, new_lrun, FALSE); break_width = __mg_glyph_string_get_width(grun->gstr); state->remaining_width -= break_width; @@ -714,106 +787,115 @@ static void line_set_resolved_dir(LAYOUTLINE *line, GlyphRunDir direction) } } -static struct list_head reorder_runs_recurse (struct list_head* entry, - int n_items) +static void reorder_runs_recurse(struct list_head* result, + GlyphRun** runs, int n_items) { - struct list_head *tmp, *level_start_node; + GlyphRun **tmp, **level_start_node; int i, level_start_i; int min_level = INT_MAX; - struct list_head result; - INIT_LIST_HEAD(&result); + INIT_LIST_HEAD(result); if (n_items == 0) - return result; + return; - tmp = entry; for (i = 0; i < n_items; i++) { - GlyphRun *run = (GlyphRun*)tmp; + GlyphRun *run = runs[i]; min_level = MIN (min_level, run->lrun->el); - tmp = tmp->next; } level_start_i = 0; - level_start_node = entry; - tmp = entry; + level_start_node = runs; + tmp = runs; for (i = 0; i < n_items; i++) { - GlyphRun *run = (GlyphRun*)tmp; + GlyphRun* run = runs[i]; if (run->lrun->el == min_level) { if (min_level % 2) { if (i > level_start_i) { struct list_head sub_result; - sub_result = reorder_runs_recurse (level_start_node, + reorder_runs_recurse (&sub_result, level_start_node, i - level_start_i); - - if (!list_empty(&result)) { - list_add_tail(result.next, &sub_result); - } - result = sub_result; + list_concat(&sub_result, result); + list_move(result, &sub_result); // result = sub_result; } - list_add(&run->list, &result); + list_add(&run->list, result); } else { if (i > level_start_i) { struct list_head sub_result; - sub_result = reorder_runs_recurse (level_start_node, + reorder_runs_recurse (&sub_result, level_start_node, i - level_start_i); - if (!list_empty(&sub_result)) { - list_add_tail(sub_result.next, &result); - } + list_concat(result, &sub_result); } - list_add(&run->list, &result); + list_add_tail(&run->list, result); } level_start_i = i + 1; - level_start_node = tmp->next; + level_start_node = tmp + 1; } - tmp = tmp->next; + tmp++; } if (min_level % 2) { if (i > level_start_i) { struct list_head sub_result; - sub_result = reorder_runs_recurse (level_start_node, + reorder_runs_recurse(&sub_result, level_start_node, i - level_start_i); - if (!list_empty(&result)) { - list_add_tail(result.next, &sub_result); - } - result = sub_result; + list_concat(&sub_result, result); + list_move(result, &sub_result); // result = sub_result; } } else { if (i > level_start_i) { struct list_head sub_result; - sub_result = reorder_runs_recurse (level_start_node, + reorder_runs_recurse(&sub_result, level_start_node, i - level_start_i); - if (!list_empty(&sub_result)) { - list_add_tail(sub_result.next, &result); - } + list_concat(result, &sub_result); } } - return result; + list_print(result, "returned from reorder_runs_recurse"); + return; } -static void reverse_runs(LAYOUTLINE *line) +static void reverse_runs(struct list_head* result, + GlyphRun** runs, int n_items) +{ + int i; + + INIT_LIST_HEAD(result); + + for (i = n_items - 1; i >= 0; i--) { + GlyphRun* run = runs[i]; + + list_add_tail(&run->list, result); + } +} + +static inline void list_reverse(struct list_head* head) { struct list_head tmp_head; INIT_LIST_HEAD(&tmp_head); - while (!list_empty(&line->gruns)) { - GlyphRun* run = (GlyphRun*)line->gruns.prev; - list_del(line->gruns.prev); - - list_add_tail(&run->list, &tmp_head); + while (!list_empty(head)) { + struct list_head* entry = head->prev; + list_del(head->prev); + list_add_tail(entry, &tmp_head); } - line->gruns = tmp_head; + list_move(head, &tmp_head); } +/* Local array size, used for stack-based local arrays */ +#if SIZEOF_PTR == 8 +# define LOCAL_ARRAY_SIZE 256 +#else +# define LOCAL_ARRAY_SIZE 128 +#endif + static void layout_line_reorder(LAYOUTLINE *line) { struct list_head *i; @@ -821,6 +903,16 @@ static void layout_line_reorder(LAYOUTLINE *line) Uint8 level_or = 0, level_and = 1; int length = 0; + GlyphRun** runs = NULL; + GlyphRun* local_runs[LOCAL_ARRAY_SIZE]; + + if (length > LOCAL_ARRAY_SIZE) { + runs = malloc(sizeof(GlyphRun*) * length); + } + else { + runs = local_runs; + } + /* Check if all gruns are in the same direction, in that case, the * line does not need modification and we can avoid the expensive * reorder runs recurse procedure. @@ -829,6 +921,8 @@ static void layout_line_reorder(LAYOUTLINE *line) list_for_each(i, &line->gruns) { GlyphRun *grun = (GlyphRun*)i; + runs[length] = grun; + level_or |= grun->lrun->el; level_and &= grun->lrun->el; length++; @@ -841,10 +935,31 @@ static void layout_line_reorder(LAYOUTLINE *line) all_odd = (level_and & 0x1) == 1; if (!all_even && !all_odd) { - line->gruns = reorder_runs_recurse(line->gruns.next, length); + reorder_runs_recurse(&line->gruns, runs, length); } - else if (all_odd) - reverse_runs(line); + else if (all_odd) { + reverse_runs(&line->gruns, runs, length); + } + + print_line_runs(line, __FUNCTION__); + +#if 0 /* test code for list_reverse and reverse_runs */ + list_reverse(&line->gruns); + print_line_runs(line, "list_reverse"); + + length = 0; + list_for_each(i, &line->gruns) { + GlyphRun *grun = (GlyphRun*)i; + runs[length] = grun; + length++; + } + + reverse_runs(&line->gruns, runs, length); + print_line_runs(line, "reverse_runs"); +#endif + + if (runs && runs != local_runs) + free(runs); } static void zero_line_final_space (LAYOUTLINE *line, @@ -940,7 +1055,7 @@ static void adjust_line_letter_spacing(LAYOUTLINE *line, LayoutState *state) if (line->resolved_dir == GLYPH_RUN_DIR_RTL) { list_for_each(l, &line->gruns) { if (is_tab_run (layout, (GlyphRun*)l)) { - reverse_runs(line); + list_reverse(&line->gruns); reversed = TRUE; break; } @@ -1007,7 +1122,7 @@ static void adjust_line_letter_spacing(LAYOUTLINE *line, LayoutState *state) } if (reversed) - reverse_runs (line); + list_reverse(&line->gruns); } static void justify_clusters (LAYOUTLINE *line, LayoutState *state) @@ -1265,15 +1380,7 @@ static void layout_line_postprocess (LAYOUTLINE *line, /* Truncate the logical-final whitespace in the line * if we broke the line at it */ if (wrapped) - /* The runs are in reverse order at this point, - * since we prepended them to the list. - * So, the first run is the last logical run. */ - zero_line_final_space (line, state, (GlyphRun*)&line->gruns.next); - - /* - * Reverse the runs - */ - //line->runs = g_slist_reverse (line->runs); + zero_line_final_space (line, state, (GlyphRun*)line->gruns.prev); /* Ellipsize the line if necessary */ @@ -1347,6 +1454,11 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) first_lrun_in_line = list_empty(&line->gruns); result = process_layout_run(layout, line, state, !have_break, FALSE); + lrun = state->lrun; + + _DBG_PRINTF("%s: result of process_layout_run: %d\n", + __FUNCTION__, result); + switch (result) { case BREAK_ALL_FIT: if (can_break_in (layout, state->start_offset, @@ -1368,11 +1480,15 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) goto done; case BREAK_SOME_FIT: + _DBG_PRINTF("%s: handle BREAK_SOME_FIT: %d\n", + __FUNCTION__, lrun->len); state->start_offset += old_num_chars - lrun->len; wrapped = TRUE; goto done; case BREAK_NONE_FIT: + _DBG_PRINTF("%s: handle BREAK_NONE_FIT: %d\n", + __FUNCTION__, lrun->len); /* Back up over unused runs to run where there is a break */ while (!list_empty(&line->gruns) && line->gruns.next != break_link) { @@ -1397,9 +1513,10 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) lrun = state->lrun; old_num_chars = lrun->len; result = process_layout_run(layout, line, state, TRUE, TRUE); + assert(result == BREAK_SOME_FIT || result == BREAK_EMPTY_FIT); - state->start_offset += old_num_chars - lrun->len; + state->start_offset += old_num_chars - state->lrun->len; wrapped = TRUE; goto done; @@ -1416,7 +1533,9 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) } done: - layout_line_postprocess (line, state, wrapped); + _DBG_PRINTF("%s: calling layout_line_postprocess: %d\n", + __FUNCTION__, line->len); + layout_line_postprocess(line, state, wrapped); state->line_of_par++; state->line_start_index += line->len; return line; @@ -1425,6 +1544,24 @@ done: static int traverse_line_glyphs(LAYOUTLINE* line, int x, int y, CB_GLYPH_LAID_OUT cb_laid_out, GHANDLE ctxt) { + int j = 0; + struct list_head* i; + int line_adv = 0; + + list_for_each(i, &line->gruns) { + GlyphRun* run = (GlyphRun*)i; + for (j = 0; j < run->gstr->nr_glyphs; j++) { + ShapedGlyph* sg = run->gstr->glyphs + j; + GLYPHPOS pos; + + pos.x = x + line_adv; + pos.y = y; + pos.x_off = sg->x_off; + pos.y_off = sg->y_off; + line_adv += sg->width; + cb_laid_out(ctxt, run->lrun->lf, 0, run->gstr->glyphs[j].gv, &pos); + } + } return 0; } @@ -1476,7 +1613,7 @@ LAYOUTLINE* GUIAPI LayoutNextLine( state.line_start_index = 0; state.start_index_in_trun = 0; - state.trun = (TextRun*)&layout->truninfo->truns.next; + state.trun = (TextRun*)layout->truninfo->truns.next; } else { state.line_start_index = layout->truninfo->nr_ucs - layout->nr_left_ucs; @@ -1497,7 +1634,7 @@ LAYOUTLINE* GUIAPI LayoutNextLine( if (layout->persist) { list_add_tail(&next_line->list, &layout->lines); } - else { + else if (prev_line) { release_line(prev_line); } diff --git a/src/newgdi/textrunsinfo.c b/src/newgdi/textrunsinfo.c index 15a42d8b..d0dd1737 100644 --- a/src/newgdi/textrunsinfo.c +++ b/src/newgdi/textrunsinfo.c @@ -438,7 +438,7 @@ out: return ok; } -TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(Uchar32* ucs, int nr_ucs, +TEXTRUNSINFO* GUIAPI CreateTextRunsInfo(const Uchar32* ucs, int nr_ucs, LanguageCode lang_code, ParagraphDir base_dir, GlyphRunDir run_dir, GlyphOrient glyph_orient, GlyphOrientPolicy orient_policy, const char* logfont_name, RGBCOLOR color)