From a95ee5b18190d315af61f909e4b3ac6e8b7613f2 Mon Sep 17 00:00:00 2001 From: Vincent Wei Date: Tue, 26 Mar 2019 18:09:49 +0800 Subject: [PATCH] debug --- src/font/logfont.c | 2 - src/newgdi/layout-ellipsize.c | 2 - src/newgdi/layout-utils.c | 69 +++++++++--- src/newgdi/layoutinfo.c | 171 ++++++++++++++++++++++------- src/newgdi/layoutinfo.h | 3 +- src/newgdi/simple-glyph-renderer.c | 6 +- src/newgdi/textrunsinfo.c | 8 +- src/newgdi/textrunsinfo.h | 2 +- 8 files changed, 196 insertions(+), 67 deletions(-) diff --git a/src/font/logfont.c b/src/font/logfont.c index a9a23c4e..b22e697f 100644 --- a/src/font/logfont.c +++ b/src/font/logfont.c @@ -41,8 +41,6 @@ #include #include -#define DEBUG - #include "common.h" #include "minigui.h" #include "gdi.h" diff --git a/src/newgdi/layout-ellipsize.c b/src/newgdi/layout-ellipsize.c index 2abe20ba..03dcb26e 100644 --- a/src/newgdi/layout-ellipsize.c +++ b/src/newgdi/layout-ellipsize.c @@ -568,8 +568,6 @@ static void fixup_ellipsis_grun (EllipsizeState *state) level = MIN (level, state->run_info[i].run->lrun->el); layout_run->el = level; - - layout_run->flags |= LAYOUTRUN_FLAG_ORPHAN; } /* Computes the new list of runs for the line diff --git a/src/newgdi/layout-utils.c b/src/newgdi/layout-utils.c index 3f073d92..ea277304 100644 --- a/src/newgdi/layout-utils.c +++ b/src/newgdi/layout-utils.c @@ -101,9 +101,6 @@ LOGFONT* __mg_create_logfont_for_layout(const LAYOUTINFO* layout, return NULL; } - _DBG_PRINTF("%s: calling LoadResource for LOGFONT: %s\n", - __FUNCTION__, my_fontname); - lf = (LOGFONT*)LoadResource(my_fontname, RES_TYPE_FONT, 0); if (lf == NULL) { _ERR_PRINTF("%s: failed to create LOGFONT for layout: %p\n", @@ -160,7 +157,7 @@ LayoutRun* __mg_layout_run_new_orphan(const LAYOUTINFO* layout, lrun->el = trun->el; lrun->dir = trun->dir; lrun->ort = trun->ort; - lrun->flags |= LAYOUTRUN_FLAG_ORPHAN; + lrun->flags = trun->flags; return lrun; } @@ -196,8 +193,11 @@ LayoutRun* __mg_layout_run_new_from_offset(const LAYOUTINFO* layout, LOGFONT* lf; LayoutRun* lrun; - if (offset >= trun->len) + if (offset >= trun->len) { + _DBG_PRINTF("%s: offset(%d) >= trun->len(%p, %d)\n", + __FUNCTION__, offset, trun, trun->len); return NULL; + } lf = __mg_create_logfont_for_layout(layout, trun->fontname, trun->ort); if (lf == NULL) @@ -221,12 +221,8 @@ LayoutRun* __mg_layout_run_new_from_offset(const LAYOUTINFO* layout, void __mg_layout_run_free(LayoutRun* lrun) { - _DBG_PRINTF("%s: called for %p\n", - __FUNCTION__, lrun); - if (lrun->lf) { FONT_RES* font_res = (FONT_RES*)lrun->lf; - // FIXME if (font_res->key) ReleaseRes(font_res->key); } @@ -263,18 +259,12 @@ 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; } @@ -686,11 +676,56 @@ void __mg_glyph_run_get_logical_widths (const GlyphRun *glyph_run, } } -void __mg_glyph_run_letter_space (const GlyphRun* glyph_run, +void __mg_glyph_run_letter_space(const GlyphRun* glyph_run, const Uchar32* ucs, const BreakOppo* bos, int letter_spacing) { -} + GlyphRunIter iter; + ShapedGlyph *glyphs = glyph_run->gstr->glyphs; + BOOL have_cluster; + int space_left, space_right; + space_left = letter_spacing / 2; + + /* hinting */ + if ((letter_spacing & 1) == 0) { + space_left += 1; + } + + space_right = letter_spacing - space_left; + + for (have_cluster = __mg_glyph_run_iter_init_start(&iter, glyph_run, ucs); + have_cluster; + have_cluster = __mg_glyph_run_iter_next_cluster(&iter)) { + + if (!(bos[iter.start_char] & BOV_GB_CURSOR_POS)) + continue; + + if (iter.start_glyph < iter.end_glyph) { + /* LTR */ + + if (iter.start_char > 0) { + glyphs[iter.start_glyph].width += space_left ; + glyphs[iter.start_glyph].x_off += space_left ; + } + + if (iter.end_char < glyph_run->lrun->len) { + glyphs[iter.end_glyph-1].width += space_right; + } + } + else { + /* RTL */ + + if (iter.start_char > 0) { + glyphs[iter.start_glyph].width += space_right; + } + + if (iter.end_char < glyph_run->lrun->len) { + glyphs[iter.end_glyph+1].x_off += space_left ; + glyphs[iter.end_glyph+1].width += space_left ; + } + } + } +} #endif /* _MGCHARSET_UNICODE */ diff --git a/src/newgdi/layoutinfo.c b/src/newgdi/layoutinfo.c index 60bf2a91..5db40354 100644 --- a/src/newgdi/layoutinfo.c +++ b/src/newgdi/layoutinfo.c @@ -36,6 +36,29 @@ ** layoutlayout.c: The implementation of APIs related LAYOUTINFO ** ** Create by WEI Yongming at 2019/03/20 +** +** This implementation is derived from LGPL'd Pango. However, we optimize +** and simplify the original implementation in the following respects: +** +** - We split the layout process into two stages. We get the text runs +** (Pango items) in the first stage, and the text runs will keep as +** constants for subsequent different layouts. In the seconde stage, +** we create a layout context for a set of specific layout parameters, +** and generates the lines one by one for the caller. This is useful +** for an app like browser, it can reuse the text runs if the output +** width or height changed, and it is no need to re-generate the text +** runs because of the size change of the output rectangle. +** +** - We use MiniGUI's fontname for the font attributes of text, and leave +** the font selection and the glyph generating to MiniGUI's LOGFONT. +** In this way, we simplify the layout process greatly. +** +** - We always use Uchar32 string for the whole layout process. So the +** code and the structures are clearer than original implementation. +** +** - We provide two shaping engines for rendering the text. One is a +** basic shaping engine and other is the complex shaping engine based +** on HarzBuff. The former can be used for standard scripts. */ #include @@ -54,6 +77,7 @@ #include "devfont.h" #include "unicode-ops.h" #include "layoutinfo.h" +#include "glyph.h" LAYOUTINFO* GUIAPI CreateLayoutInfo( const TEXTRUNSINFO* truninfo, Uint32 render_flags, @@ -313,6 +337,39 @@ static void shape_tab(LAYOUTLINE *line, GlyphString *glyphs) } } +static void shape_space(const LAYOUTINFO* layout, const LayoutRun* lrun, + GlyphString* glyphs) +{ + unsigned int i; + + __mg_glyph_string_set_size (glyphs, lrun->len); + + for (i = 0; i < lrun->len; i++) { + UCharGeneralCategory gc; + + gc = UCharGetCategory(lrun->ucs[i]); + + glyphs->glyphs[i].gv = INV_GLYPH_VALUE; + glyphs->glyphs[i].x_off = 0; + glyphs->glyphs[i].y_off = 0; + + if (gc == UCHAR_CATEGORY_SPACE_SEPARATOR) { + Glyph32 space_gv = GetGlyphValue(lrun->lf, UCHAR_SPACE); + glyphs->glyphs[i].width + = _font_get_glyph_log_width(lrun->lf, space_gv); + if (IsUCharWide(lrun->ucs[i])) { + glyphs->glyphs[i].width *= 2; + } + } + else { + glyphs->glyphs[i].width = 0; + } + + glyphs->glyphs[i].is_cluster_start = 1; + glyphs->log_clusters[i] = i; + } +} + static void shape_shape(const Uchar32* ucs, int nr_ucs, RECT* ink_rc, RECT* log_rc, GlyphString *glyphs) { @@ -333,7 +390,7 @@ static void shape_shape(const Uchar32* ucs, int nr_ucs, static void shape_full(const Uchar32* lrun_ucs, int nr_lrun_ucs, const Uchar32* para_ucs, int nr_para_ucs, - const TEXTRUNSINFO* info, LayoutRun* lrun, + const TEXTRUNSINFO* info, const LayoutRun* lrun, GlyphString* glyphs) { // TODO @@ -358,8 +415,13 @@ static GlyphString* shape_run(LAYOUTLINE *line, LayoutState *state, LAYOUTINFO *layout = line->layout; GlyphString *glyphs = __mg_glyph_string_new (); - if (layout->truninfo->ucs[lrun->si] == UCHAR_TAB) + if (layout->truninfo->ucs[lrun->si] == UCHAR_TAB) { shape_tab(line, glyphs); + } + else if (lrun->lf == NULL) { + // no need shaping + shape_space(layout, lrun, glyphs); + } else { if (state->shape_set) shape_shape(layout->truninfo->ucs + lrun->si, lrun->len, @@ -405,12 +467,31 @@ static void free_glyph_run (GlyphRun *grun) } #ifdef DEBUG +static inline void print_text_runs(const TEXTRUNSINFO* info, const char* func) +{ + int j = 0; + struct list_head* i; + + _DBG_PRINTF("Text runs in content when calling %s (nr_runs: %d):\n", + func, info->nr_runs); + + list_for_each(i, &info->truns) { + TextRun* run = (TextRun*)i; + _DBG_PRINTF("RUN NO.: %d\n", j); + _DBG_PRINTF(" ADDRESS: %p\n", run); + _DBG_PRINTF(" INDEX: %d\n", run->si); + _DBG_PRINTF(" LENGHT: %d\n", run->len); + _DBG_PRINTF(" EMBEDDING LEVEL:%d\n", run->el); + j++; + } +} + 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", + _DBG_PRINTF("Runs in line when calling %s (line length: %d):\n", func, line->len); list_for_each(i, &line->gruns) { @@ -419,7 +500,7 @@ static inline void print_line_runs(const LAYOUTLINE* line, const char* 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(" EMBEDDING LEVEL:%d\n", run->lrun->el); _DBG_PRINTF(" NR GLYPHS: %d\n", run->gstr->nr_glyphs); j++; } @@ -431,7 +512,7 @@ static inline void print_run(const GlyphRun* run, const char* 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(" EMBEDDING LEVEL:%d\n", run->lrun->el); _DBG_PRINTF(" NR GLYPHS: %d\n", run->gstr->nr_glyphs); } @@ -450,6 +531,11 @@ static inline void list_print(struct list_head* head, const char* desc) #else +static inline void print_text_runs(const TEXTRUNSINFO* info, const char* func) +{ + // do nothing. +} + static inline void print_line_runs(const LAYOUTLINE* line, const char* func) { // do nothing. @@ -471,11 +557,10 @@ static void uninsert_run(LAYOUTLINE *line) { GlyphRun *grun; - grun = (GlyphRun*)line->gruns.next; + grun = (GlyphRun*)line->gruns.prev; - list_del(line->gruns.next); + list_del(line->gruns.prev); line->len -= grun->lrun->len; - free_glyph_run(grun); print_line_runs(line, __FUNCTION__); @@ -628,6 +713,7 @@ BreakResult process_layout_run(LAYOUTINFO *layout, glyph_run.lrun = lrun; glyph_run.gstr = state->glyphs; + assert(state->log_widths == NULL); state->log_widths = malloc (sizeof (int) * lrun->len); __mg_glyph_run_get_logical_widths(&glyph_run, layout->truninfo->ucs, state->log_widths); @@ -660,8 +746,7 @@ retry_break: * the cluster here. But should be fine in practice. */ if (break_num_chars > 0 && break_num_chars < lrun->len && layout->bos[state->start_offset + break_num_chars - 1] & - BOV_WHITESPACE) - { + BOV_WHITESPACE) { break_width -= state->log_widths[state->log_widths_offset + break_num_chars - 1]; } @@ -697,8 +782,8 @@ retry_break: GlyphRun *grun; new_lrun = __mg_layout_run_split(lrun, break_num_chars); - state->lrun = new_lrun; + /* we must free the original layout run */ __mg_layout_run_free(lrun); /* Add the width back, to the line, reshape, @@ -1343,12 +1428,10 @@ static void justify_words (LAYOUTLINE *line, } } - if (mode == MEASURE) - { + if (mode == MEASURE) { total_space_width = spaces_so_far; - if (total_space_width == 0) - { + if (total_space_width == 0) { justify_clusters (line, state); return; } @@ -1433,7 +1516,6 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) state->remaining_width = state->line_width; while (state->trun) { - LayoutRun *lrun; BreakResult result; int old_num_chars; int old_remaining_width; @@ -1446,17 +1528,12 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) else { state->lrun = __mg_layout_run_new_from(layout, state->trun); } - lrun = state->lrun; - old_num_chars = lrun->len; + old_num_chars = state->lrun->len; old_remaining_width = state->remaining_width; 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: @@ -1469,25 +1546,26 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) } state->trun = (const TextRun*)state->trun->list.next; + state->start_index_in_trun = 0; + state->start_offset += old_num_chars; if (&state->trun->list == &layout->truninfo->truns) state->trun = NULL; - state->start_offset += old_num_chars; break; case BREAK_EMPTY_FIT: + __mg_layout_run_free(state->lrun); + state->lrun = NULL; wrapped = TRUE; 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; + state->start_offset += old_num_chars - state->lrun->len; wrapped = TRUE; goto done; case BREAK_NONE_FIT: - _DBG_PRINTF("%s: handle BREAK_NONE_FIT: %d\n", - __FUNCTION__, lrun->len); + __mg_layout_run_free(state->lrun); + /* Back up over unused runs to run where there is a break */ while (!list_empty(&line->gruns) && line->gruns.next != break_link) { @@ -1509,8 +1587,7 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) } /* Reshape run to break */ - lrun = state->lrun; - old_num_chars = lrun->len; + old_num_chars = state->lrun->len; result = process_layout_run(layout, line, state, TRUE, TRUE); assert(result == BREAK_SOME_FIT || result == BREAK_EMPTY_FIT); @@ -1521,9 +1598,10 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) case BREAK_LINE_SEPARATOR: state->trun = (const TextRun*)state->trun->list.next; + state->start_index_in_trun = 0; + state->start_offset += old_num_chars; if (&state->trun->list == &layout->truninfo->truns) state->trun = NULL; - state->start_offset += old_num_chars; /* A line-separate is just a forced break. Set wrapped, so we do * justification */ wrapped = TRUE; @@ -1532,8 +1610,6 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) } done: - _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; @@ -1611,29 +1687,39 @@ LAYOUTLINE* GUIAPI LayoutNextLine( } state.line_start_index = 0; + state.start_offset = 0; state.start_index_in_trun = 0; state.trun = (TextRun*)layout->truninfo->truns.next; } else { state.line_start_index = layout->truninfo->nr_ucs - layout->nr_left_ucs; + state.start_offset = state.line_start_index; + state.start_index_in_trun = 0; state.trun = __mg_text_run_get_by_offset(layout->truninfo, - state.start_offset, &state.start_index_in_trun); + state.line_start_index, &state.start_index_in_trun); + + _DBG_PRINTF("%s: line_start_index: %d, start_index_in_trun: %d(%p)\n", + __FUNCTION__, state.line_start_index, state.start_index_in_trun, + state.trun); + if (state.trun == NULL) { next_line = NULL; goto out; } } - if (prev_line) { - release_line(prev_line); - prev_line = NULL; - } - state.line_width = max_extent; state.remaining_width = max_extent; next_line = check_next_line(layout, &state); + if (state.glyphs) { + __mg_glyph_string_free(state.glyphs); + } + if (state.log_widths) { + free(state.log_widths); + } + if (next_line) { if (layout->persist) { list_add_tail(&next_line->list, &layout->lines); @@ -1643,6 +1729,13 @@ LAYOUTLINE* GUIAPI LayoutNextLine( layout->nr_left_ucs -= next_line->len; } + // Release previous line after got next line. + // This will avoid releasing the LOGFONT objects earlier. + if (prev_line) { + release_line(prev_line); + prev_line = NULL; + } + out: if (prev_line) { release_line(prev_line); diff --git a/src/newgdi/layoutinfo.h b/src/newgdi/layoutinfo.h index 51fcea4d..447bf0bb 100644 --- a/src/newgdi/layoutinfo.h +++ b/src/newgdi/layoutinfo.h @@ -64,7 +64,8 @@ struct _GlyphString { unsigned int space; }; -#define LAYOUTRUN_FLAG_ORPHAN 0x01 +#define LAYOUTRUN_FLAG_CENTERED_BASELINE TEXTRUN_FLAG_CENTERED_BASELINE +#define LAYOUTRUN_FLAG_NO_SHAPING TEXTRUN_FLAG_NO_SHAPING struct _LayoutRun { LOGFONT* lf; // the logfont for this run diff --git a/src/newgdi/simple-glyph-renderer.c b/src/newgdi/simple-glyph-renderer.c index a13316d7..304e93c4 100644 --- a/src/newgdi/simple-glyph-renderer.c +++ b/src/newgdi/simple-glyph-renderer.c @@ -1079,8 +1079,12 @@ int GUIAPI GetGlyphsExtentFromUChars(LOGFONT* logfont_upright, } } else if (is_whitespace_glyph(&args, gis, n)) { + Glyph32 space_gv = GetGlyphValue(logfont_upright, UCHAR_SPACE); + gis[n].whitespace = 1; - ges[n].line_adv = logfont_upright->size / 6; + ges[n].line_adv = _font_get_glyph_log_width(logfont_upright, + space_gv); + switch (render_flags & GRF_WRITING_MODE_MASK) { case GRF_WRITING_MODE_VERTICAL_RL: case GRF_WRITING_MODE_VERTICAL_LR: diff --git a/src/newgdi/textrunsinfo.c b/src/newgdi/textrunsinfo.c index d0dd1737..0f4d9a26 100644 --- a/src/newgdi/textrunsinfo.c +++ b/src/newgdi/textrunsinfo.c @@ -168,7 +168,7 @@ static void state_add_character(TextRunState *state, BOOL no_shaping, BOOL force_break, const Uchar32* pos) { if (state->run) { - BOOL without_shaping = (state->run->flags & TEXTRUN_FLAG_NOT_SHAPING); + BOOL without_shaping = (state->run->flags & TEXTRUN_FLAG_NO_SHAPING); if (!force_break && state->run->lc == state->derived_lang && without_shaping == no_shaping) { @@ -189,7 +189,7 @@ static void state_add_character(TextRunState *state, state->run->flags = 0; if (no_shaping) { - state->run->flags |= TEXTRUN_FLAG_NOT_SHAPING; + state->run->flags |= TEXTRUN_FLAG_NO_SHAPING; } /* The level vs. gravity dance: @@ -567,10 +567,10 @@ const TextRun* __mg_text_run_get_by_offset(const TEXTRUNSINFO* runinfo, int index, int *start_offset) { struct list_head *i; - TextRun* found = NULL; + const TextRun* found = NULL; list_for_each(i, &runinfo->truns) { - TextRun* trun = (TextRun*)i; + const TextRun* trun = (const TextRun*)i; if (index >= trun->si && (index < trun->si + trun->len)) { found = trun; diff --git a/src/newgdi/textrunsinfo.h b/src/newgdi/textrunsinfo.h index 034ff98b..a829c3e1 100644 --- a/src/newgdi/textrunsinfo.h +++ b/src/newgdi/textrunsinfo.h @@ -69,7 +69,7 @@ struct _ShapingEngineInfo { }; #define TEXTRUN_FLAG_CENTERED_BASELINE 0x01 -#define TEXTRUN_FLAG_NOT_SHAPING 0x02 +#define TEXTRUN_FLAG_NO_SHAPING 0x02 struct _TextRun { struct list_head list;