mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-09-26 20:45:36 +08:00
some code for layout
This commit is contained in:
+1
-1
@@ -12743,7 +12743,7 @@ typedef BOOL (*CB_GLYPH_LAID_OUT) (GHANDLE ctxt,
|
||||
*/
|
||||
MG_EXPORT LAYOUTLINE* GUIAPI LayoutNextLine(LAYOUTINFO* layout_info,
|
||||
LAYOUTLINE* prev_Line,
|
||||
int x, int y, int max_extent, SIZE* line_size,
|
||||
int x, int y, int max_extent, BOOL last_line, SIZE* line_size,
|
||||
CB_GLYPH_LAID_OUT cb_laid_out, GHANDLE ctxt);
|
||||
|
||||
MG_EXPORT BOOL DrawShapedGlyph(HDC hdc, LOGFONT* lf, RGBCOLOR color,
|
||||
|
||||
@@ -19,7 +19,7 @@ SRC_FILES = gdi.c attr.c clip.c map.c coor.c rect.c \
|
||||
simple-glyph-renderer.c glyph-shaped.c \
|
||||
textrunsinfo.c \
|
||||
shape-glyphs-basic.c shape-glyphs-complex.c \
|
||||
layoutinfo.c
|
||||
layout-utils.c layoutinfo.c
|
||||
endif
|
||||
|
||||
HDR_FILES = glyph.h drawtext.h mi.h midc.h mistruct.h miwideline.h \
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* This file is part of MiniGUI, a mature cross-platform windowing
|
||||
* and Graphics User Interface (GUI) support system for embedded systems
|
||||
* and smart IoT devices.
|
||||
*
|
||||
* Copyright (C) 2002~2019, Beijing FMSoft Technologies Co., Ltd.
|
||||
* Copyright (C) 1998~2002, WEI Yongming
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Or,
|
||||
*
|
||||
* As this program is a library, any link to this program must follow
|
||||
* GNU General Public License version 3 (GPLv3). If you cannot accept
|
||||
* GPLv3, you need to be licensed from FMSoft.
|
||||
*
|
||||
* If you have got a commercial license of this program, please use it
|
||||
* under the terms and conditions of the commercial license.
|
||||
*
|
||||
* For more information about the commercial license, please refer to
|
||||
* <http://www.minigui.com/en/about/licensing-policy/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
** layout-utils.c: The implementation of utilities related LAYOUTINFO
|
||||
**
|
||||
** Create by WEI Yongming at 2019/03/21
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef _MGCHARSET_UNICODE
|
||||
|
||||
#include "minigui.h"
|
||||
#include "gdi.h"
|
||||
#include "window.h"
|
||||
#include "devfont.h"
|
||||
#include "unicode-ops.h"
|
||||
#include "layoutinfo.h"
|
||||
|
||||
GLYPHSTRING* __mg_glyph_string_new (void)
|
||||
{
|
||||
GLYPHSTRING *string = calloc(1, sizeof(GLYPHSTRING));
|
||||
return string;
|
||||
}
|
||||
|
||||
void __mg_glyph_string_free (GLYPHSTRING *string)
|
||||
{
|
||||
if (string == NULL)
|
||||
return;
|
||||
|
||||
free (string->glyphs);
|
||||
free (string->log_clusters);
|
||||
free (string);
|
||||
}
|
||||
|
||||
void __mg_glyph_string_set_size (GLYPHSTRING* string, int new_len)
|
||||
{
|
||||
if (new_len < 0)
|
||||
return;
|
||||
|
||||
while (new_len > string->space) {
|
||||
if (string->space == 0) {
|
||||
string->space = 4;
|
||||
}
|
||||
else {
|
||||
const unsigned int max_space =
|
||||
MIN (INT_MAX,
|
||||
UINT_MAX / MAX (sizeof(SHAPEDGLYPH), sizeof(int)));
|
||||
|
||||
unsigned int more_space = (unsigned int)string->space * 2;
|
||||
|
||||
if (more_space > max_space) {
|
||||
more_space = max_space;
|
||||
|
||||
if ((unsigned int)new_len > max_space) {
|
||||
_WRN_PRINTF("%s: Too large glyph string of length %d\n",
|
||||
__FUNCTION__, new_len);
|
||||
}
|
||||
}
|
||||
|
||||
string->space = more_space;
|
||||
}
|
||||
}
|
||||
|
||||
string->glyphs = realloc (string->glyphs,
|
||||
string->space * sizeof (SHAPEDGLYPH));
|
||||
string->log_clusters = realloc (string->log_clusters,
|
||||
string->space * sizeof (int));
|
||||
string->nr_glyphs = new_len;
|
||||
}
|
||||
|
||||
int __mg_glyph_string_get_width(const GLYPHSTRING *glyphs)
|
||||
{
|
||||
int i;
|
||||
int width = 0;
|
||||
|
||||
for (i = 0; i < glyphs->nr_glyphs; i++)
|
||||
width += glyphs->glyphs[i].width;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
#define LTR(glyph_item) (((glyph_item)->item->el & 1) == 0)
|
||||
|
||||
BOOL __mg_glyph_item_iter_next_cluster (GlyphItemIter *iter)
|
||||
{
|
||||
int glyph_index = iter->end_glyph;
|
||||
GLYPHSTRING *glyphs = iter->glyph_item->glyphs;
|
||||
int cluster;
|
||||
TEXTRUN *item = iter->glyph_item->item;
|
||||
|
||||
if (LTR (iter->glyph_item)) {
|
||||
if (glyph_index == glyphs->nr_glyphs)
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
if (glyph_index < 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
iter->start_glyph = iter->end_glyph;
|
||||
iter->start_index = iter->end_index;
|
||||
iter->start_char = iter->end_char;
|
||||
|
||||
if (LTR (iter->glyph_item)) {
|
||||
cluster = glyphs->log_clusters[glyph_index];
|
||||
while (TRUE) {
|
||||
glyph_index++;
|
||||
|
||||
if (glyph_index == glyphs->nr_glyphs) {
|
||||
iter->end_index = item->idx + item->len;
|
||||
iter->end_char = item->len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (glyphs->log_clusters[glyph_index] > cluster) {
|
||||
iter->end_index = item->idx + glyphs->log_clusters[glyph_index];
|
||||
iter->end_char += iter->end_index - iter->start_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* RTL */
|
||||
cluster = glyphs->log_clusters[glyph_index];
|
||||
while (TRUE) {
|
||||
glyph_index--;
|
||||
|
||||
if (glyph_index < 0) {
|
||||
iter->end_index = item->idx + item->len;
|
||||
iter->end_char = item->len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (glyphs->log_clusters[glyph_index] > cluster) {
|
||||
iter->end_index = item->idx + glyphs->log_clusters[glyph_index];
|
||||
iter->end_char += iter->end_index - iter->start_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iter->end_glyph = glyph_index;
|
||||
|
||||
assert (iter->start_char < iter->end_char);
|
||||
assert (iter->end_char <= item->len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL __mg_glyph_item_iter_prev_cluster (GlyphItemIter *iter)
|
||||
{
|
||||
int glyph_index = iter->start_glyph;
|
||||
GLYPHSTRING *glyphs = iter->glyph_item->glyphs;
|
||||
int cluster;
|
||||
TEXTRUN *item = iter->glyph_item->item;
|
||||
|
||||
if (LTR (iter->glyph_item)) {
|
||||
if (glyph_index == 0)
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
if (glyph_index == glyphs->nr_glyphs - 1)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
iter->end_glyph = iter->start_glyph;
|
||||
iter->end_index = iter->start_index;
|
||||
iter->end_char = iter->start_char;
|
||||
|
||||
if (LTR (iter->glyph_item)) {
|
||||
|
||||
cluster = glyphs->log_clusters[glyph_index - 1];
|
||||
while (TRUE) {
|
||||
if (glyph_index == 0) {
|
||||
iter->start_index = item->idx;
|
||||
iter->start_char = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
glyph_index--;
|
||||
|
||||
if (glyphs->log_clusters[glyph_index] < cluster) {
|
||||
glyph_index++;
|
||||
iter->start_index = item->idx + glyphs->log_clusters[glyph_index];
|
||||
iter->start_char -= iter->end_index - iter->start_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* RTL */
|
||||
|
||||
cluster = glyphs->log_clusters[glyph_index + 1];
|
||||
while (TRUE) {
|
||||
if (glyph_index == glyphs->nr_glyphs - 1) {
|
||||
iter->start_index = item->idx;
|
||||
iter->start_char = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
glyph_index++;
|
||||
|
||||
if (glyphs->log_clusters[glyph_index] < cluster) {
|
||||
glyph_index--;
|
||||
iter->start_index = item->idx + glyphs->log_clusters[glyph_index];
|
||||
iter->start_char -= iter->end_index - iter->start_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iter->start_glyph = glyph_index;
|
||||
|
||||
assert (iter->start_char < iter->end_char);
|
||||
assert (0 <= iter->start_char);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL __mg_glyph_item_iter_init_start (GlyphItemIter *iter,
|
||||
const GlyphItem *glyph_item, const Uchar32 *text)
|
||||
{
|
||||
iter->glyph_item = glyph_item;
|
||||
iter->text = text;
|
||||
|
||||
if (LTR (glyph_item))
|
||||
iter->end_glyph = 0;
|
||||
else
|
||||
iter->end_glyph = glyph_item->glyphs->nr_glyphs - 1;
|
||||
|
||||
iter->end_index = glyph_item->item->idx;
|
||||
iter->end_char = 0;
|
||||
|
||||
iter->start_glyph = iter->end_glyph;
|
||||
iter->start_index = iter->end_index;
|
||||
iter->start_char = iter->end_char;
|
||||
|
||||
/* Advance onto the first cluster of the glyph item */
|
||||
return __mg_glyph_item_iter_next_cluster (iter);
|
||||
}
|
||||
|
||||
BOOL __mg_glyph_item_iter_init_end (GlyphItemIter *iter,
|
||||
const GlyphItem *glyph_item, const Uchar32 *text)
|
||||
{
|
||||
iter->glyph_item = glyph_item;
|
||||
iter->text = text;
|
||||
|
||||
if (LTR (glyph_item))
|
||||
iter->start_glyph = glyph_item->glyphs->nr_glyphs;
|
||||
else
|
||||
iter->start_glyph = -1;
|
||||
|
||||
iter->start_index = glyph_item->item->idx + glyph_item->item->len;
|
||||
iter->start_char = glyph_item->item->len;
|
||||
|
||||
iter->end_glyph = iter->start_glyph;
|
||||
iter->end_index = iter->start_index;
|
||||
iter->end_char = iter->start_char;
|
||||
|
||||
/* Advance onto the first cluster of the glyph item */
|
||||
return __mg_glyph_item_iter_prev_cluster (iter);
|
||||
}
|
||||
|
||||
void __mg_glyph_item_get_logical_widths (const GlyphItem *glyph_item,
|
||||
const Uchar32 *text, int *logical_widths)
|
||||
{
|
||||
GlyphItemIter iter;
|
||||
BOOL has_cluster;
|
||||
int dir;
|
||||
|
||||
dir = glyph_item->item->el % 2 == 0 ? +1 : -1;
|
||||
for (has_cluster = __mg_glyph_item_iter_init_start (&iter, glyph_item, text);
|
||||
has_cluster;
|
||||
has_cluster = __mg_glyph_item_iter_next_cluster (&iter))
|
||||
{
|
||||
int glyph_index, char_index, num_chars, cluster_width = 0, char_width;
|
||||
|
||||
for (glyph_index = iter.start_glyph;
|
||||
glyph_index != iter.end_glyph;
|
||||
glyph_index += dir) {
|
||||
cluster_width += glyph_item->glyphs->glyphs[glyph_index].width;
|
||||
}
|
||||
|
||||
num_chars = iter.end_char - iter.start_char;
|
||||
if (num_chars) /* pedantic */
|
||||
{
|
||||
char_width = cluster_width / num_chars;
|
||||
|
||||
for (char_index = iter.start_char;
|
||||
char_index < iter.end_char;
|
||||
char_index++)
|
||||
{
|
||||
logical_widths[char_index] = char_width;
|
||||
}
|
||||
|
||||
/* add any residues to the first char */
|
||||
logical_widths[iter.start_char] += cluster_width - (char_width * num_chars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _MGCHARSET_UNICODE */
|
||||
|
||||
+334
-3
@@ -130,9 +130,340 @@ BOOL GUIAPI DestroyLayoutInfo(LAYOUTINFO* info)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LAYOUTLINE* GUIAPI LayoutNextLine(LAYOUTINFO* info,
|
||||
LAYOUTLINE* prev_Line,
|
||||
int x, int y, int max_extent, SIZE* line_size,
|
||||
typedef struct _LayoutState LayoutState;
|
||||
|
||||
typedef enum {
|
||||
BREAK_NONE_FIT,
|
||||
BREAK_SOME_FIT,
|
||||
BREAK_ALL_FIT,
|
||||
BREAK_EMPTY_FIT,
|
||||
BREAK_LINE_SEPARATOR
|
||||
} BreakResult;
|
||||
|
||||
struct _LayoutState {
|
||||
/* maintained per layout */
|
||||
/* is last line */
|
||||
Uint32 last_line:1;
|
||||
Uint32 shape_set:1;
|
||||
|
||||
RECT shape_ink_rect, shape_logical_rect;
|
||||
|
||||
/* maintained per paragraph */
|
||||
|
||||
/* Current text run */
|
||||
TEXTRUN* item;
|
||||
|
||||
/* Current resolved base direction */
|
||||
GlyphRunDir base_dir;
|
||||
|
||||
/* Line of the paragraph, starting at 1 for first line */
|
||||
int line_of_par;
|
||||
|
||||
/* Glyphs for the current text run */
|
||||
GLYPHSTRING* glyphs;
|
||||
|
||||
/* Character offset of first item in state->item in layout->runinfo->ucs */
|
||||
int start_offset;
|
||||
|
||||
/* Logical widths for the current text run */
|
||||
int *log_widths;
|
||||
|
||||
/* Offset into log_widths to the point corresponding
|
||||
* to the remaining portion of the first item */
|
||||
int log_widths_offset;
|
||||
|
||||
/* Start index of line in layout->runinfo->ucs */
|
||||
int line_start_index;
|
||||
|
||||
/* maintained per line */
|
||||
/* Goal width of line currently processing; < 0 is infinite */
|
||||
int line_width;
|
||||
|
||||
/* Amount of space remaining on line; < 0 is infinite */
|
||||
int remaining_width;
|
||||
};
|
||||
|
||||
static BOOL should_ellipsize_current_line(LAYOUTINFO *layout,
|
||||
LayoutState *state)
|
||||
{
|
||||
if (((layout->rf & GRF_OVERFLOW_ELLIPSIZE_MASK) ==
|
||||
GRF_OVERFLOW_ELLIPSIZE_NONE) || state->line_width < 0)
|
||||
return FALSE;
|
||||
|
||||
if (!state->last_line) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void shape_tab(LAYOUTLINE *line, GLYPHSTRING *glyphs)
|
||||
{
|
||||
}
|
||||
|
||||
static void shape_shape(const Uchar32* ucs, int nr_ucs,
|
||||
RECT* ink_rc, RECT* log_rc, GLYPHSTRING *glyphs)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
__mg_glyph_string_set_size (glyphs, nr_ucs);
|
||||
|
||||
for (i = 0; i < nr_ucs; i++) {
|
||||
glyphs->glyphs[i].gv = INV_GLYPH_VALUE;
|
||||
glyphs->glyphs[i].x_off = 0;
|
||||
glyphs->glyphs[i].y_off = 0;
|
||||
glyphs->glyphs[i].width = RECTWP(log_rc);
|
||||
glyphs->glyphs[i].is_cluster_start = 1;
|
||||
|
||||
glyphs->log_clusters[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
static void shape_full(const Uchar32* item_ucs, int nr_item_ucs,
|
||||
const Uchar32* para_ucs, int nr_para_ucs,
|
||||
const TEXTRUNSINFO* runinfo, const TEXTRUN* textrun,
|
||||
GLYPHSTRING* glyphs)
|
||||
{
|
||||
}
|
||||
|
||||
static void distribute_letter_spacing (int letter_spacing,
|
||||
int *space_left, int *space_right)
|
||||
{
|
||||
*space_left = letter_spacing / 2;
|
||||
/* hinting */
|
||||
if (letter_spacing & 1) {
|
||||
*space_left += 1;
|
||||
}
|
||||
|
||||
*space_right = letter_spacing - *space_left;
|
||||
}
|
||||
|
||||
static GLYPHSTRING* shape_run(LAYOUTLINE *line, LayoutState *state,
|
||||
TEXTRUN *item)
|
||||
{
|
||||
LAYOUTINFO *layout = line->layout;
|
||||
GLYPHSTRING *glyphs = __mg_glyph_string_new ();
|
||||
|
||||
if (layout->runinfo->ucs[item->idx] == '\t')
|
||||
shape_tab(line, glyphs);
|
||||
else {
|
||||
if (state->shape_set)
|
||||
shape_shape(layout->runinfo->ucs + item->idx, item->len,
|
||||
&state->shape_ink_rect,
|
||||
&state->shape_logical_rect, glyphs);
|
||||
else
|
||||
shape_full(layout->runinfo->ucs + item->idx, item->len,
|
||||
layout->runinfo->ucs, layout->runinfo->nr_ucs,
|
||||
layout->runinfo, item, glyphs);
|
||||
|
||||
if (layout->ls) {
|
||||
GlyphItem glyph_item;
|
||||
int space_left, space_right;
|
||||
|
||||
glyph_item.item = item;
|
||||
glyph_item.glyphs = glyphs;
|
||||
|
||||
__mg_glyph_item_letter_space (&glyph_item,
|
||||
layout->runinfo->ucs,
|
||||
layout->bos + state->start_offset,
|
||||
layout->ls);
|
||||
|
||||
distribute_letter_spacing (layout->ls, &space_left, &space_right);
|
||||
|
||||
glyphs->glyphs[0].width += space_left;
|
||||
glyphs->glyphs[0].x_off += space_left;
|
||||
glyphs->glyphs[glyphs->nr_glyphs - 1].width += space_right;
|
||||
}
|
||||
}
|
||||
|
||||
return glyphs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to insert as much as possible of the text runs at the head of
|
||||
* state->items onto @line. Five results are possible:
|
||||
*
|
||||
* %BREAK_NONE_FIT: Couldn't fit anything.
|
||||
* %BREAK_SOME_FIT: The item was broken in the middle.
|
||||
* %BREAK_ALL_FIT: Everything fit.
|
||||
* %BREAK_EMPTY_FIT: Nothing fit, but that was ok, as we can break at the first char.
|
||||
* %BREAK_LINE_SEPARATOR: The text runs begins with a line separator.
|
||||
*
|
||||
* If @force_fit is %TRUE, then %BREAK_NONE_FIT will never
|
||||
* be returned, a run will be added even if inserting the minimum amount
|
||||
* will cause the line to overflow. This is used at the start of a line
|
||||
* and until we've found at least some place to break.
|
||||
*
|
||||
* If @no_break_at_end is %TRUE, then %BREAK_ALL_FIT will never be
|
||||
* returned even everything fits; the run will be broken earlier,
|
||||
* or %BREAK_NONE_FIT returned. This is used when the end of the
|
||||
* run is not a break position.
|
||||
*/
|
||||
static BreakResult process_one_text_run(LAYOUTINFO *layout,
|
||||
LAYOUTLINE *line, LayoutState *state,
|
||||
BOOL force_fit, BOOL no_break_at_end)
|
||||
{
|
||||
TEXTRUN *item = state->item;
|
||||
BOOL shape_set = FALSE;
|
||||
int width;
|
||||
int length;
|
||||
int i;
|
||||
BOOL processing_new_item = FALSE;
|
||||
|
||||
/* Only one character has type UCHAR_CATEGORY_LINE_SEPARATOR in
|
||||
* Unicode 12.0; update this if that changes. */
|
||||
#define LINE_SEPARATOR 0x2028
|
||||
|
||||
if (!state->glyphs) {
|
||||
pango_layout_get_item_properties (item, &state->properties);
|
||||
state->glyphs = shape_run (line, state, item);
|
||||
|
||||
state->log_widths = NULL;
|
||||
state->log_widths_offset = 0;
|
||||
|
||||
processing_new_item = TRUE;
|
||||
}
|
||||
|
||||
if (!layout->single_paragraph &&
|
||||
layout->runinfo->text[item->idx] == LINE_SEPARATOR &&
|
||||
!should_ellipsize_current_line (layout, state)) {
|
||||
insert_run (line, state, item, TRUE);
|
||||
state->log_widths_offset += item->len;
|
||||
return BREAK_LINE_SEPARATOR;
|
||||
}
|
||||
|
||||
if (state->remaining_width < 0 && !no_break_at_end) /* Wrapping off */
|
||||
{
|
||||
insert_run (line, state, item, TRUE);
|
||||
|
||||
return BREAK_ALL_FIT;
|
||||
}
|
||||
|
||||
width = 0;
|
||||
if (processing_new_item) {
|
||||
width = __mg_glyph_string_get_width (state->glyphs);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < item->len; i++)
|
||||
width += state->log_widths[state->log_widths_offset + i];
|
||||
}
|
||||
|
||||
if ((width <= state->remaining_width ||
|
||||
(item->len == 1 && !line->runs)) &&
|
||||
!no_break_at_end) {
|
||||
state->remaining_width -= width;
|
||||
state->remaining_width = MAX (state->remaining_width, 0);
|
||||
insert_run (line, state, item, TRUE);
|
||||
|
||||
return BREAK_ALL_FIT;
|
||||
}
|
||||
else {
|
||||
int num_chars = item->len;
|
||||
int break_num_chars = num_chars;
|
||||
int break_width = width;
|
||||
int orig_width = width;
|
||||
BOOL retrying_with_char_breaks = FALSE;
|
||||
|
||||
if (processing_new_item) {
|
||||
GlyphItem glyph_item = {item, state->glyphs};
|
||||
state->log_widths = malloc (sizeof (int) * item->len);
|
||||
__mg_glyph_item_get_logical_widths(&glyph_item, layout->runinfo->ucs,
|
||||
state->log_widths);
|
||||
}
|
||||
|
||||
retry_break:
|
||||
|
||||
/* See how much of the item we can stuff in the line. */
|
||||
width = 0;
|
||||
for (num_chars = 0; num_chars < item->len; num_chars++) {
|
||||
if (width > state->remaining_width && break_num_chars < item->len)
|
||||
break;
|
||||
|
||||
/* If there are no previous runs we have to take care to grab at least one char. */
|
||||
if (can_break_at (layout, state->start_offset + num_chars, retrying_with_char_breaks) &&
|
||||
(num_chars > 0 || line->runs))
|
||||
{
|
||||
break_num_chars = num_chars;
|
||||
break_width = width;
|
||||
}
|
||||
|
||||
width += state->log_widths[state->log_widths_offset + num_chars];
|
||||
}
|
||||
|
||||
/* If there's a space at the end of the line, include that also.
|
||||
* The logic here should match zero_line_final_space().
|
||||
* XXX Currently it doesn't quite match the logic there. We don't check
|
||||
* the cluster here. But should be fine in practice. */
|
||||
if (break_num_chars > 0 && break_num_chars < item->len &&
|
||||
layout->log_attrs[state->start_offset + break_num_chars - 1].is_white)
|
||||
{
|
||||
break_width -= state->log_widths[state->log_widths_offset + break_num_chars - 1];
|
||||
}
|
||||
|
||||
if (layout->wrap == PANGO_WRAP_WORD_CHAR && force_fit && break_width > state->remaining_width && !retrying_with_char_breaks)
|
||||
{
|
||||
retrying_with_char_breaks = TRUE;
|
||||
num_chars = item->len;
|
||||
width = orig_width;
|
||||
break_num_chars = num_chars;
|
||||
break_width = width;
|
||||
goto retry_break;
|
||||
}
|
||||
|
||||
if (force_fit || break_width <= state->remaining_width) /* Successfully broke the item */
|
||||
{
|
||||
if (state->remaining_width >= 0)
|
||||
{
|
||||
state->remaining_width -= break_width;
|
||||
state->remaining_width = MAX (state->remaining_width, 0);
|
||||
}
|
||||
|
||||
if (break_num_chars == item->len)
|
||||
{
|
||||
insert_run (line, state, item, TRUE);
|
||||
|
||||
return BREAK_ALL_FIT;
|
||||
}
|
||||
else if (break_num_chars == 0)
|
||||
{
|
||||
return BREAK_EMPTY_FIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
TEXTRUN *new_item;
|
||||
|
||||
length = g_utf8_offset_to_pointer (layout->runinfo->ucs + item->idx, break_num_chars) - (layout->runinfo->ucs + item->idx);
|
||||
|
||||
new_item = pango_item_split (item, length, break_num_chars);
|
||||
|
||||
/* Add the width back, to the line, reshape, subtract the new width */
|
||||
state->remaining_width += break_width;
|
||||
insert_run (line, state, new_item, FALSE);
|
||||
break_width = __mg_glyph_string_get_width (NULL /*((GlyphItem *)(line->runs->data))->glyphs*/);
|
||||
state->remaining_width -= break_width;
|
||||
|
||||
state->log_widths_offset += break_num_chars;
|
||||
|
||||
/* Shaped items should never be broken */
|
||||
assert (!shape_set);
|
||||
|
||||
return BREAK_SOME_FIT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
__mg_glyph_string_free (state->glyphs);
|
||||
state->glyphs = NULL;
|
||||
free (state->log_widths);
|
||||
state->log_widths = NULL;
|
||||
|
||||
return BREAK_NONE_FIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LAYOUTLINE* GUIAPI LayoutNextLine(
|
||||
LAYOUTINFO* info, LAYOUTLINE* prev_Line,
|
||||
int x, int y, int max_extent, BOOL last_line, SIZE* line_size,
|
||||
CB_GLYPH_LAID_OUT cb_laid_out, GHANDLE ctxt)
|
||||
{
|
||||
return NULL;
|
||||
|
||||
+48
-4
@@ -61,24 +61,26 @@ struct _GLYPHSTRING {
|
||||
int* log_clusters;
|
||||
|
||||
int nr_glyphs;
|
||||
int reserved;
|
||||
unsigned int space;
|
||||
};
|
||||
|
||||
struct _GLYPHRUN {
|
||||
struct list_head list;
|
||||
TEXTRUN* text; // the text run to which this glyph run belongs
|
||||
GLYPHSTRING* gs; // the glyph string
|
||||
int offset; // the offset of the first uchar in the text run
|
||||
int nr_ucs; // the number of the uchars
|
||||
};
|
||||
|
||||
struct _LAYOUTLINE {
|
||||
struct list_head list;
|
||||
LAYOUTINFO* layout_info;
|
||||
LAYOUTINFO* layout;
|
||||
int* log_widths; // the widths of the logical chars
|
||||
|
||||
struct list_head run_head; // the list head for glyph runs
|
||||
|
||||
int idx; // the index in uchar string
|
||||
int len; // the length in uchar string
|
||||
int idx; // the index in the uchar string
|
||||
int nr_ucs; // the number of the uchars
|
||||
|
||||
Uint8 first_line:1; // is first line of the paragraph?
|
||||
Uint8 resolved_dir:3; // resolved direction of the line
|
||||
@@ -101,12 +103,54 @@ struct _LAYOUTINFO {
|
||||
|
||||
int left_ucs; // the number of chars not laied out.
|
||||
Uint32 persist:1; // persist lines?
|
||||
Uint32 single_paragraph:1;
|
||||
};
|
||||
|
||||
typedef struct _GlyphItem GlyphItem;
|
||||
typedef struct _GlyphItemIter GlyphItemIter;
|
||||
|
||||
struct _GlyphItem {
|
||||
TEXTRUN *item;
|
||||
GLYPHSTRING *glyphs;
|
||||
};
|
||||
|
||||
struct _GlyphItemIter {
|
||||
const GlyphItem *glyph_item;
|
||||
const Uchar32 *text;
|
||||
|
||||
int start_glyph;
|
||||
int start_index;
|
||||
int start_char;
|
||||
|
||||
int end_glyph;
|
||||
int end_index;
|
||||
int end_char;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
GLYPHSTRING* __mg_glyph_string_new(void);
|
||||
void __mg_glyph_string_free(GLYPHSTRING* string);
|
||||
void __mg_glyph_string_set_size(GLYPHSTRING* string, int new_len);
|
||||
int __mg_glyph_string_get_width(const GLYPHSTRING* string);
|
||||
|
||||
BOOL __mg_glyph_item_iter_init_start (GlyphItemIter *iter,
|
||||
const GlyphItem *glyph_item, const Uchar32 *text);
|
||||
|
||||
BOOL __mg_glyph_item_iter_init_end (GlyphItemIter *iter,
|
||||
const GlyphItem *glyph_item, const Uchar32 *text);
|
||||
|
||||
BOOL __mg_glyph_item_iter_prev_cluster (GlyphItemIter *iter);
|
||||
BOOL __mg_glyph_item_iter_next_cluster (GlyphItemIter *iter);
|
||||
|
||||
void __mg_glyph_item_get_logical_widths(const GlyphItem* glyph_item,
|
||||
const Uchar32* ucs, int* log_widths);
|
||||
|
||||
void __mg_glyph_item_letter_space (const GlyphItem* glyph_item,
|
||||
const Uchar32* ucs, const BreakOppo* bos, int letter_spacing);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
Reference in New Issue
Block a user