diff --git a/include/gdi.h b/include/gdi.h index 6f348a35..974c057e 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -12934,13 +12934,32 @@ typedef BOOL (*CB_GLYPH_LAID_OUT) (GHANDLE ctxt, */ MG_EXPORT LAYOUTLINE* GUIAPI LayoutNextLine(LAYOUTINFO* layout_info, LAYOUTLINE* prev_line, - int max_extent, BOOL last_line, SIZE* line_size, + int max_extent, BOOL last_line, CB_GLYPH_LAID_OUT cb_laid_out, GHANDLE ctxt, int x, int y); +/** + * \fn BOOL GUIAPI GetLayoutLineSize(LAYOUTLINE* line, + SIZE* line_size) + * \brief Get the size of a layout line. + * + * This function gets the size of the specific layout line object \a line. + * + * \param line The layout line object. + * \param line_size The buffer to store the result. + * + * \return TRUE for success, FALSE otherwise. + * + * \sa CreateLayoutInfo, DestroyLayoutInfo, LayoutNextLine + * + * Since 3.4.0 + */ +MG_EXPORT BOOL GUIAPI GetLayoutLineSize(LAYOUTLINE* line, + SIZE* line_size); + /** * \fn int GUIAPI CalcLayoutBoundingRect(LAYOUTINFO* layout_info, * int max_line_extent, int max_height, int line_height, - * RECT* bounding) + * int x, int y, RECT* bounding) * \brief Calculate the bounding rectangle of a layout. * * This function calculates the bounding rectangle of the specific @@ -12948,22 +12967,32 @@ MG_EXPORT LAYOUTLINE* GUIAPI LayoutNextLine(LAYOUTINFO* layout_info, * * \param layout_info The LAYOUTINFO object. * \param max_line_extent The maximal line extent; only effective if - * the line extent mode of the layout object if variable. + * the line extent mode of the layout object is variable. * \param max_height The maximal height of the lines; no limit if * it is less than 0. * \param line_height The line height. If it is less than 0, this function * will try to determine the line height automatically. + * \param x The x-position of first line. + * \param y The y-position of first line. * \param bounding The buffer to receive the result. * * \return The number of lines laid out. * * \sa CreateLayoutInfo, DestroyLayoutInfo, LayoutNextLine * + * \note The position coordinates of the first line are + * with respect to the top-left corner of the output rectangle + * if the writing mode is GRF_WRITING_MODE_HORIZONTAL_TB or + * GRF_WRITING_MODE_VERTICAL_LR, the bottom-left corner if + * the writing mode is GRF_WRITING_MODE_HORIZONTAL_BT, + * the top-right corner if the writing mode is + * GRF_WRITING_MODE_VERTICAL_RL. + * * Since 3.4.0 */ MG_EXPORT int GUIAPI CalcLayoutBoundingRect(LAYOUTINFO* layout_info, int max_line_extent, int max_height, int line_height, - RECT* bounding); + int x, int y, RECT* bounding); /** * \fn BOOL DrawLayoutGlyph(HDC hdc, diff --git a/src/newgdi/layoutinfo.c b/src/newgdi/layoutinfo.c index 3ae42f6a..3d4330d7 100644 --- a/src/newgdi/layoutinfo.c +++ b/src/newgdi/layoutinfo.c @@ -106,6 +106,13 @@ LAYOUTINFO* GUIAPI CreateLayoutInfo( layout->tabs = tabs; layout->nr_tabs = nr_tabs; + layout->lf_upright = __mg_create_logfont_for_layout(layout, + NULL, GLYPH_ORIENT_UPRIGHT); + if (layout->lf_upright == NULL) { + free(layout); + return NULL; + } + INIT_LIST_HEAD(&layout->lines); layout->nr_left_ucs = truninfo->nr_ucs; @@ -174,6 +181,12 @@ static void release_line(LAYOUTLINE* line) BOOL GUIAPI DestroyLayoutInfo(LAYOUTINFO* layout) { + if (layout->lf_upright) { + FONT_RES* font_res = (FONT_RES*)layout->lf_upright; + if (font_res->key) + ReleaseRes(font_res->key); + } + while (!list_empty(&layout->lines)) { LAYOUTLINE* line = (LAYOUTLINE*)layout->lines.prev; list_del(layout->lines.prev); @@ -356,7 +369,7 @@ static int get_tab_pos(LAYOUTINFO *layout, int index, BOOL *is_default) } } -static int get_line_width(LAYOUTLINE *line) +static int get_line_width(const LAYOUTLINE *line) { struct list_head *l; int i; @@ -375,6 +388,23 @@ static int get_line_width(LAYOUTLINE *line) return width; } +static int get_line_height(const LAYOUTLINE *line) +{ + struct list_head *l; + int i; + int height = 0; + + list_for_each(l, &line->gruns) { + GlyphRun *run = (GlyphRun*)l; + + for (i = 0; i < run->gstr->nr_glyphs; i++) + if (run->gstr->glyphs[i].height > height) + height = run->gstr->glyphs[i].height; + } + + return height; +} + static void shape_tab(LAYOUTLINE *line, GlyphString *glyphs) { int i, space_width; @@ -1463,10 +1493,11 @@ static void justify_words (LAYOUTLINE *line, assert(run->lrun->si >= state->line_start_index); offset = state->line_start_index + run->lrun->si; - for (have_cluster = __mg_glyph_run_iter_init_start (&cluster_iter, + for (have_cluster = __mg_glyph_run_iter_init_start(&cluster_iter, run, text); have_cluster; - have_cluster = __mg_glyph_run_iter_next_cluster (&cluster_iter)) + have_cluster = __mg_glyph_run_iter_next_cluster( + &cluster_iter)) { int i; int dir; @@ -1475,8 +1506,10 @@ static void justify_words (LAYOUTLINE *line, BOV_EXPANDABLE_SPACE)) continue; - dir = (cluster_iter.start_glyph < cluster_iter.end_glyph) ? 1 : -1; - for (i = cluster_iter.start_glyph; i != cluster_iter.end_glyph; i += dir) + dir = (cluster_iter.start_glyph < cluster_iter.end_glyph) ? + 1 : -1; + for (i = cluster_iter.start_glyph; + i != cluster_iter.end_glyph; i += dir) { int glyph_width = glyphs->glyphs[i].width; @@ -1589,6 +1622,9 @@ static LAYOUTLINE* check_next_line(LAYOUTINFO* layout, LayoutState* state) line->is_paragraph_start = state->line_of_par == 1; line_set_resolved_dir(line, state->base_dir); + line->width = -1; + line->height = -1; + if (should_ellipsize_current_line (layout, state)) state->remaining_width = -1; else @@ -1753,7 +1789,7 @@ static int traverse_line_glyphs(const LAYOUTINFO* layout, LAYOUTLINE* GUIAPI LayoutNextLine( LAYOUTINFO* layout, LAYOUTLINE* prev_line, - int max_extent, BOOL last_line, SIZE* line_size, + int max_extent, BOOL last_line, CB_GLYPH_LAID_OUT cb_laid_out, GHANDLE ctxt, int x, int y) { LAYOUTLINE* next_line = NULL; @@ -1895,6 +1931,83 @@ out: return next_line; } +BOOL GUIAPI GetLayoutLineSize(LAYOUTLINE* line, + SIZE* line_size) +{ + if (line == NULL) + return FALSE; + + if (line->width >= 0 && line->height >= 0) { + line_size->cx = line->width; + line_size->cy = line->height; + } + else { + line->width = line_size->cx = get_line_width(line); + line->height = line_size->cy = get_line_height(line); + } + + return TRUE; +} + +int GUIAPI CalcLayoutBoundingRect(LAYOUTINFO* layout, + int max_line_extent, int max_height, int line_height, + int x, int y, RECT* bounding) +{ + int nr_lines = 0; + int remaining_height = max_height; + LAYOUTLINE* line = NULL; + BOOL last_line = FALSE; + SIZE line_size; + + if (line_height <= 0) { + // determine the default line height + Uint32 writing_mode = layout->rf & GRF_WRITING_MODE_MASK; + FONTMETRICS font_metrics; + + GetFontMetrics(layout->lf_upright, &font_metrics); + + if (writing_mode == GRF_WRITING_MODE_VERTICAL_LR || + writing_mode == GRF_WRITING_MODE_VERTICAL_RL) { + line_height = font_metrics.max_width; + } + else { + line_height = font_metrics.font_height; + } + } + + SetRect(bounding, 0, 0, 0, 0); + + do { + if (max_height > 0) { + remaining_height -= line_height; + if (remaining_height <= 0) + last_line = TRUE; + } + + line = LayoutNextLine(layout, line, max_line_extent, last_line, + NULL, NULL, 0, 0); + + if (line == NULL) { + break; + } + + GetLayoutLineSize(line, &line_size); + if (line_size.cy > line_height) + line_height = line_size.cy; + + bounding->bottom += line_height; + if (line_size.cx > bounding->right) + bounding->right = line_size.cx; + nr_lines++; + + } while (1); + + // TODO: transform the bouding rectangle according to the wrting mode + OffsetRect(bounding, x, y); + + return nr_lines; +} + #ifdef _MGDEVEL_MODE BOOL GUIAPI GetLayoutLineInfo(LAYOUTLINE* line, int* line_no, int* max_extent, int* nr_chars, int* nr_glyphs, diff --git a/src/newgdi/layoutinfo.h b/src/newgdi/layoutinfo.h index bd0b9286..36f49cde 100644 --- a/src/newgdi/layoutinfo.h +++ b/src/newgdi/layoutinfo.h @@ -52,7 +52,8 @@ struct _ShapedGlyph { int x_off; int y_off; - Uint32 width:24; + Uint32 width:14; + Uint32 height:14; Uint32 is_cluster_start:1; Uint32 hanged:2; }; @@ -127,6 +128,7 @@ struct _LAYOUTINFO { struct list_head lines; // the list head of lines + LOGFONT* lf_upright; // the default upright logfont int nr_left_ucs;// the number of chars not laied out int nr_lines; // the number of lines