From 9dab380f3e8d134c96457f10bf58c38cb14d8220 Mon Sep 17 00:00:00 2001 From: Vincent Wei Date: Wed, 3 Apr 2019 19:01:19 +0800 Subject: [PATCH] GetLayoutLineRect --- include/gdi.h | 41 +++++++++++++- src/newgdi/layoutinfo.c | 120 +++++++++++++++++++++++++++++----------- 2 files changed, 125 insertions(+), 36 deletions(-) diff --git a/include/gdi.h b/include/gdi.h index 64c9f3bf..105efb30 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -12997,8 +12997,8 @@ MG_EXPORT LAYOUTLINE* GUIAPI LayoutNextLine(LAYOUTINFO* layout_info, CB_GLYPH_LAID_OUT cb_laid_out, GHANDLE ctxt); /** - * \fn BOOL GUIAPI GetLayoutLineSize(LAYOUTLINE* line, - SIZE* line_size) + * \fn BOOL GUIAPI GetLayoutLineSize(const 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. @@ -13012,9 +13012,43 @@ MG_EXPORT LAYOUTLINE* GUIAPI LayoutNextLine(LAYOUTINFO* layout_info, * * Since 3.4.0 */ -MG_EXPORT BOOL GUIAPI GetLayoutLineSize(LAYOUTLINE* line, +MG_EXPORT BOOL GUIAPI GetLayoutLineSize(const LAYOUTLINE* line, SIZE* line_size); +/** + * \fn BOOL GUIAPI GetLayoutLineRect(LAYOUTLINE* line, + * int* x, int* y, int line_height, RECT* line_rc) + * \brief Get the bouding rectangle of a layout line. + * + * This function gets the bouding rectangle of the specific + * layout line object \a line. + * + * \param line The layout line object. + * \param x The buffer contained the initial x-position of the line, + * and returns the x-position of the next line. + * \param x The buffer contained the initial y-position of the line, + * and returns the y-position of the next line. + * \param line_height The line height. + * \param line_rc The buffer to store the result. + * + * \return TRUE for success, FALSE otherwise. + * + * \note The position coordinates of the 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. + * + * \sa CreateLayoutInfo, DestroyLayoutInfo, LayoutNextLine, + * GetLayoutLineSize + * + * Since 3.4.0 + */ +MG_EXPORT BOOL GUIAPI GetLayoutLineRect(const LAYOUTLINE* line, + int* x, int* y, int line_height, RECT* line_rc); + /** * \fn int GUIAPI CalcLayoutBoundingRect(LAYOUTINFO* layout_info, * int max_line_extent, int max_height, int line_height, @@ -13046,6 +13080,7 @@ MG_EXPORT BOOL GUIAPI GetLayoutLineSize(LAYOUTLINE* line, * GRF_WRITING_MODE_VERTICAL_RL. * * \sa CreateLayoutInfo, DestroyLayoutInfo, LayoutNextLine + * GetLayoutLineRect * * Since 3.4.0 */ diff --git a/src/newgdi/layoutinfo.c b/src/newgdi/layoutinfo.c index 879abb3f..3afd43cc 100644 --- a/src/newgdi/layoutinfo.c +++ b/src/newgdi/layoutinfo.c @@ -1836,6 +1836,23 @@ static Uint32 get_line_alignment(const LAYOUTINFO *layout, } #endif +static inline int line_dir_to_factor(LineDirection d) +{ + switch (d) { + case LINE_DIRECTION_LTR: + case LINE_DIRECTION_WEAK_LTR: + return 1; + case LINE_DIRECTION_RTL: + case LINE_DIRECTION_WEAK_RTL: + return -1; + case LINE_DIRECTION_NEUTRAL: + default: + return 1; + } + + return 1; +} + int __mg_layout_get_line_offset(const LAYOUTINFO *layout, const LAYOUTLINE *line) { @@ -1864,23 +1881,14 @@ int __mg_layout_get_line_offset(const LAYOUTINFO *layout, } /* Indentation */ + if ((layout->rf & GRF_INDENT_MASK) == GRF_INDENT_FIRST_LINE && line->is_paragraph_start) { - if (alignment == GRF_ALIGN_LEFT) - x_offset += layout->indent; - else if (alignment == GRF_ALIGN_RIGHT) - x_offset -= layout->indent; - else - x_offset -= layout->indent / 2; + x_offset += layout->indent; } else if ((layout->rf & GRF_INDENT_MASK) == GRF_INDENT_HANGING && !line->is_paragraph_start) { - if (alignment == GRF_ALIGN_LEFT) - x_offset += layout->indent; - else if (alignment == GRF_ALIGN_RIGHT) - x_offset -= layout->indent; - else - x_offset -= layout->indent / 2; + x_offset += layout->indent; } done: @@ -1925,6 +1933,9 @@ static int traverse_line_glyphs(const LAYOUTINFO* layout, break; } + /* FIXME: for upside down and sideways left, the indentation + * should apply to the opposite edge + */ line_offset = __mg_layout_get_line_offset(layout, line); list_for_each(i, &line->gruns) { @@ -2189,19 +2200,70 @@ out: return next_line; } -BOOL GUIAPI GetLayoutLineSize(LAYOUTLINE* line, +BOOL GUIAPI GetLayoutLineSize(const LAYOUTLINE* line, SIZE* line_size) { - if (line == NULL) + if (line == NULL || line->width < 0 || line->height < 0) 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 = calc_line_width(line); - line->height = line_size->cy = calc_line_height(line); + line_size->cx = line->width; + line_size->cy = line->height; + + return TRUE; +} + +BOOL GUIAPI GetLayoutLineRect(const LAYOUTLINE* line, + int* x, int* y, int line_height, RECT* line_rc) +{ + const LAYOUTINFO* layout; + int line_offset; + + if (line == NULL || line->width < 0 || line->height < 0) + return FALSE; + + layout = line->layout; + line_offset = __mg_layout_get_line_offset(layout, line); + + if (line_height < line->height) + line_height = line->height; + + switch (layout->rf & GRF_WRITING_MODE_MASK) { + case GRF_WRITING_MODE_HORIZONTAL_BT: + line_rc->left = *x + line_offset; + line_rc->bottom = *y; + line_rc->right = line_rc->left + line->width; + line_rc->top = line_rc->bottom - line->height; + + *y -= line_height; + break; + + case GRF_WRITING_MODE_VERTICAL_LR: + line_rc->left = *x; + line_rc->top = *y + line_offset; + line_rc->right = line_rc->left + line->height; + line_rc->bottom = line_rc->top + line->width; + + *x += line_height; + break; + + case GRF_WRITING_MODE_VERTICAL_RL: + line_rc->right = *x; + line_rc->top = *y + line_offset; + line_rc->left = line_rc->right - line->height; + line_rc->bottom = line_rc->top + line->width; + + *x -= line_height; + break; + + case GRF_WRITING_MODE_HORIZONTAL_TB: + default: + line_rc->left = *x + line_offset; + line_rc->top = *y; + line_rc->right = line_rc->left + line->width; + line_rc->bottom = line_rc->top + line->height; + + *y += line_height; + break; } return TRUE; @@ -2215,7 +2277,7 @@ int GUIAPI CalcLayoutBoundingRect(LAYOUTINFO* layout, int remaining_height = max_height; LAYOUTLINE* line = NULL; BOOL last_line = FALSE; - SIZE line_size; + RECT line_rc; if (line_height <= 0) { // determine the default line height @@ -2238,7 +2300,7 @@ int GUIAPI CalcLayoutBoundingRect(LAYOUTINFO* layout, do { if (max_height > 0) { remaining_height -= line_height; - if (remaining_height <= 0) + if ((remaining_height - line_height) < 0) last_line = TRUE; } @@ -2249,20 +2311,12 @@ int GUIAPI CalcLayoutBoundingRect(LAYOUTINFO* layout, break; } - GetLayoutLineSize(line, &line_size); - if (line_size.cy > line_height) - line_height = line_size.cy; + GetLayoutLineRect(line, &x, &y, line_height, &line_rc); + GetBoundRect(bounding, bounding, &line_rc); - 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 writing mode - OffsetRect(bounding, x, y); - return nr_lines; }