1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** GUIX Component */
16 /** */
17 /** Rich Text View Management (Rich Text View) */
18 /** */
19 /**************************************************************************/
20
21 #define GX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_canvas.h"
29 #include "gx_rich_text_view.h"
30 #include "gx_utility.h"
31 #include "gx_widget.h"
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _gx_rich_text_view_line_info_get PORTABLE C */
38 /* 6.1.5 */
39 /* AUTHOR */
40 /* */
41 /* Kenneth Maxwell, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function prepares one line text for drawing. */
46 /* */
47 /* INPUT */
48 /* */
49 /* text_view Rich text view control block */
50 /* text String to process */
51 /* line_info Retrieved line information */
52 /* for drawing next line */
53 /* availlable_width Availlable width for drawing */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* None */
58 /* */
59 /* CALLS */
60 /* */
61 /* _gx_widget_font_get Retireve font by id */
62 /* _gx_rich_text_view_tag_enter Process rich text tag */
63 /* _gx_utility_utf8_string_character_get Retrieve glyph length */
64 /* _gx_system_string_width_get Retrieve string width */
65 /* _gx_system_rich_text_format_stack_clear */
66 /* Clear rich text format stack */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* GUIX Internal Code */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 09-30-2020 Kenneth Maxwell Initial Version 6.1 */
77 /* 03-02-2021 Ting Zhu Modified comment(s), */
78 /* removed unreachable code, */
79 /* resulting in version 6.1.5 */
80 /* */
81 /**************************************************************************/
_gx_rich_text_view_line_info_get(GX_RICH_TEXT_VIEW * text_view,GX_STRING text,GX_RICH_TEXT_LINE_INFO * line_info,GX_VALUE availlable_width)82 UINT _gx_rich_text_view_line_info_get(GX_RICH_TEXT_VIEW *text_view, GX_STRING text, GX_RICH_TEXT_LINE_INFO *line_info, GX_VALUE availlable_width)
83 {
84 GX_STRING string;
85 GX_FONT *font;
86 UINT glyph_len = 1;
87 GX_VALUE glyph_width;
88 GX_RICH_TEXT_LINE_INFO break_info;
89 GX_RICH_TEXT_FORMAT text_format;
90 GX_UBYTE processed_count;
91 GX_BOOL escape = GX_FALSE;
92 GX_RESOURCE_ID font_id;
93 INT tail_space_width = 0;
94
95 text_format = line_info -> gx_rich_text_line_info_start_format;
96 break_info = *line_info;
97 font_id = text_format.gx_rich_text_font_id;
98
99 /* Pickup draw font. */
100 _gx_widget_font_get((GX_WIDGET *)text_view, text_format.gx_rich_text_font_id, &font);
101
102 if (!font)
103 {
104 return GX_INVALID_FONT;
105 }
106
107 /* Calculate the total rows of text view string. */
108 while (text.gx_string_length > 0)
109 {
110 if ((!escape) && (text.gx_string_ptr[0] == '\\'))
111 {
112 escape = GX_TRUE;
113 text.gx_string_ptr++;
114 text.gx_string_length--;
115 line_info -> gx_rich_text_line_info_text.gx_string_length++;
116 continue;
117 }
118
119 /* Test rich text tags. */
120 if ((!escape) &&
121 (text.gx_string_ptr[0] == '<') &&
122 (_gx_rich_text_view_tag_enter(text_view, &text, &text_format, &processed_count) == GX_SUCCESS))
123 {
124 if (text_format.gx_rich_text_font_id != font_id)
125 {
126 /* Font changed. */
127 _gx_widget_font_get((GX_WIDGET *)text_view, text_format.gx_rich_text_font_id, &font);
128
129 if (!font)
130 {
131 return GX_INVALID_FONT;
132 }
133
134 /* Calculate maximum font height for one line text. */
135 if (line_info -> gx_rich_text_line_info_line_height < font -> gx_font_line_height)
136 {
137 line_info -> gx_rich_text_line_info_line_height = font -> gx_font_line_height;
138 line_info -> gx_rich_text_line_info_baseline = font -> gx_font_baseline;
139 }
140
141 font_id = text_format.gx_rich_text_font_id;
142 }
143
144 line_info -> gx_rich_text_line_info_text.gx_string_length += processed_count;
145 line_info -> gx_rich_text_line_info_end_format = text_format;
146
147 text.gx_string_ptr += processed_count;
148 text.gx_string_length -= processed_count;
149 continue;
150 }
151
152 #if defined GX_UTF8_SUPPORT
153 string = text;
154
155 /* Pick up glyph length. */
156 if (_gx_utility_utf8_string_character_get(&string, GX_NULL, &glyph_len) != GX_SUCCESS)
157 {
158 /* Invalid UTF8 string. */
159 return GX_INVALID_STRING;
160 }
161 #endif
162 string.gx_string_ptr = text.gx_string_ptr;
163 string.gx_string_length = glyph_len;
164
165 /* Calculate glyph width. */
166 _gx_system_string_width_get_ext(font, &string, &glyph_width);
167
168 /* Calculate the successive space width in the end of the line. */
169 if ((text.gx_string_ptr[0] == ' '))
170 {
171 tail_space_width += glyph_width;
172 }
173 else
174 {
175 tail_space_width = 0;
176 }
177
178 if (text.gx_string_ptr[0] == GX_KEY_CARRIAGE_RETURN)
179 {
180 /* Line break charater \r. */
181 glyph_len = 1;
182
183 if ((text.gx_string_length > 1) &&
184 (text.gx_string_ptr[1] == GX_KEY_LINE_FEED))
185 {
186 /* Line break character \r\n. */
187 glyph_len++;
188 }
189
190 line_info -> gx_rich_text_line_info_text.gx_string_length += glyph_len;
191 break;
192 }
193 else if (text.gx_string_ptr[0] == GX_KEY_LINE_FEED)
194 {
195 /* Line break character \n. */
196 line_info -> gx_rich_text_line_info_text.gx_string_length += glyph_len;
197 break;
198 }
199 else if (((UINT)(line_info -> gx_rich_text_line_info_text_width + (USHORT)glyph_width) > (UINT)availlable_width) &&
200 line_info -> gx_rich_text_line_info_text_width && (text.gx_string_ptr[0] != ' '))
201 {
202 if (break_info.gx_rich_text_line_info_text_width == 0)
203 {
204 break;
205 }
206
207 *line_info = break_info;
208 break;
209 }
210
211 /* Increase text width by glyph width. */
212 line_info -> gx_rich_text_line_info_text_width = (UINT)(line_info -> gx_rich_text_line_info_text_width + (USHORT)glyph_width);
213 line_info -> gx_rich_text_line_info_text.gx_string_length += glyph_len;
214
215 if ((text.gx_string_ptr[0] == ' ') || (text.gx_string_ptr[0] == ',') || (text.gx_string_ptr[0] == ';'))
216 {
217 /* Update line info when encounter word break character. */
218 break_info = *line_info;
219
220 if (tail_space_width)
221 {
222 break_info.gx_rich_text_line_info_text_width -= (UINT)tail_space_width;
223 }
224 }
225
226 /* Increaset next draw text length. */
227 text.gx_string_ptr += glyph_len;
228 text.gx_string_length -= glyph_len;
229
230 escape = GX_FALSE;
231 }
232
233 return GX_SUCCESS;
234 }
235
236