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