Added sanity checking to kernel vnsprintf
[tpg/acess2.git] / Usermode / Applications / axwin2_src / WM / video_text.c
1 /*
2  * Acess GUI (AxWin) Version 2
3  * By John Hodge (thePowersGang)
4  */
5 #include "common.h"
6
7 typedef struct sGlyph {
8         struct sGlyph   *Next;
9         struct sGlyph   *Prev;
10         
11         uint32_t        Codepoint;
12         
13         // Effective dimensions (distance to move 'cursor')
14         short   Width;
15         short   Height;
16         
17         // Distance from the current cursor position to render at
18         short   OffsetX;
19         short   OffsetY;
20         
21         // True dimensions (size of the bitmap
22         short   TrueWidth;
23         short   TrueHeight;
24         
25         // Bitmap Data
26         uint8_t Bitmap[];
27         
28 }       tGlyph;
29
30 struct sFont {
31         struct sFont    *Next;
32          int    ReferenceCount;
33         
34         tGlyph  *AsciiGlyphs[128];      // Glyphs 0-127
35         
36         tGlyph  *FirstGlyph;
37         tGlyph  *LastGlyph;
38         
39         tGlyph  *(*CacheGlyph)(struct sFont *this, uint32_t Codepoint);
40         
41 };
42
43
44 // === PROTOTYPES ===
45  int    Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text);
46 tGlyph  *_GetGlyph(tFont *Font, uint32_t Codepoint);
47 void    _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color);
48 tGlyph  *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint);
49  int    ReadUTF8(char *Input, uint32_t *Output);
50
51 // === GLOBALS ===
52 tFont   gSystemFont = {
53         CacheGlyph: _SystemFont_CacheGlyph
54 };
55
56 // === CODE ===
57 /**
58  * \brief Draw text to the screen
59  */
60 int Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text)
61 {
62          int    xOfs = 0;
63         tGlyph  *glyph;
64         uint32_t        ch = 0;
65
66         _SysDebug("Video_DrawText: (X=%i,Y=%i,W=%i,H=%i,Font=%p,Color=%08x,Text='%s')",
67                 X, Y, W, H, Font, Color, Text);
68         
69         // Check the bounds
70         if(W < 0 || X < 0 || X >= giScreenWidth)        return 0;
71         if(X + W > giScreenWidth)       W = giScreenWidth - X;
72         
73         if(H < 0 || Y < 0 || Y >= giScreenHeight)       return 0;
74         if(Y + H > giScreenHeight)      H = giScreenHeight - Y;
75         
76         // Handle NULL font (system default monospace)
77         if( !Font )     Font = &gSystemFont;
78         
79         while( *Text )
80         {
81                 // Read character
82                 Text += ReadUTF8(Text, &ch);
83                 
84                 // Find (or load) the glyph
85                 glyph = _GetGlyph(Font, ch);
86                 if( !glyph )    continue ;      // If not found, just don't render it
87                 
88                 // End render if it will overflow the perscribed range
89                 if( xOfs + glyph->TrueWidth > W )
90                         break;
91                 
92                 xOfs += glyph->Width;
93                 _RenderGlyph(X + xOfs, Y, glyph, Color);
94         }
95         
96         return xOfs;
97 }
98
99 tGlyph  *_GetGlyph(tFont *Font, uint32_t Codepoint)
100 {
101         tGlyph  *next = NULL, *prev = NULL;
102         tGlyph  *new;
103         
104         // Check for ASCII
105         if( Codepoint < 128 )
106         {
107                 if( Font->AsciiGlyphs[Codepoint] == NULL ) {
108                         Font->CacheGlyph(Font, Codepoint);
109                 }
110                 
111                 return Font->AsciiGlyphs[Codepoint];
112         }
113         
114         // If within the range
115         if( Font->FirstGlyph && Font->FirstGlyph->Codepoint < Codepoint && Codepoint < Font->LastGlyph->Codepoint )
116         {
117                 // Find what end is "closest"
118                 if( Codepoint - Font->FirstGlyph->Codepoint < Font->LastGlyph->Codepoint - Codepoint )
119                 {
120                         // Start from the bottom
121                         for( next = Font->FirstGlyph;
122                                  next && next->Codepoint < Codepoint;
123                                  prev = next, next = next->Next
124                                  );
125                         
126                         if( next->Codepoint == Codepoint )
127                                 return next;
128                         
129                 }
130                 else
131                 {
132                         // Start at the top
133                         // NOTE: The roles of next and prev are reversed here to allow 
134                         //       the insert to be able to assume that `prev` is the
135                         //       previous entry, and `next` is the next.
136                         for( prev = Font->LastGlyph;
137                                  prev && prev->Codepoint > Codepoint;
138                                  next = prev, prev = prev->Prev
139                                  );
140                         if( prev->Codepoint == Codepoint )
141                                 return prev;
142                 }
143         }
144         else
145         {
146                 // If below first
147                 if( !Font->FirstGlyph ||  Font->FirstGlyph->Codepoint > Codepoint ) {
148                         prev = NULL;
149                         next = Font->FirstGlyph;
150                 }
151                 // Above last
152                 else {
153                         prev = Font->LastGlyph;
154                         next = NULL;
155                 }
156         }
157         
158         // Load new
159         new = Font->CacheGlyph(Font, Codepoint);
160         if( !new )      return NULL;
161         
162         // Add to list
163         // - Forward link
164         if( prev ) {
165                 new->Next = prev->Next;
166                 prev->Next = new;
167         }
168         else {
169                 new->Next = Font->FirstGlyph;
170                 Font->FirstGlyph = new;
171         }
172         
173         // - Backlink
174         if( next ) {
175                 new->Prev = next->Prev;
176                 next->Prev = new;
177         }
178         else {
179                 new->Prev = Font->LastGlyph;
180                 Font->LastGlyph = new;
181         }
182         
183         // Return
184         return new;
185 }
186
187 /**
188  */
189 void _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color)
190 {
191         
192 }
193
194 // Load system font (8x16 monospace)
195 #include "font_8x16.h"
196
197 /*
198  */
199 tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint)
200 {
201          int    i;
202         uint8_t index = 0;
203         tGlyph  *ret;
204         
205         if( Codepoint < 128 ) {
206                 index = Codepoint;
207         }
208         else {
209                 index = '?';    // Unknowns come out as a question mark
210         }
211
212         ret = malloc( sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT );
213
214         ret->Width = FONT_WIDTH;
215         ret->Height = FONT_HEIGHT;
216         
217         ret->TrueWidth = FONT_WIDTH;
218         ret->TrueHeight = FONT_HEIGHT;
219
220         ret->OffsetX = 0;
221         ret->OffsetY = 0;
222         
223         for( i = 0; i < FONT_HEIGHT; i ++ )
224         {
225                 ret->Bitmap[ i * 8 + 0 ] = VTermFont[index] & (1 << 0) ? 255 : 0;
226                 ret->Bitmap[ i * 8 + 1 ] = VTermFont[index] & (1 << 1) ? 255 : 0;
227                 ret->Bitmap[ i * 8 + 2 ] = VTermFont[index] & (1 << 2) ? 255 : 0;
228                 ret->Bitmap[ i * 8 + 3 ] = VTermFont[index] & (1 << 3) ? 255 : 0;
229                 ret->Bitmap[ i * 8 + 4 ] = VTermFont[index] & (1 << 4) ? 255 : 0;
230                 ret->Bitmap[ i * 8 + 5 ] = VTermFont[index] & (1 << 5) ? 255 : 0;
231                 ret->Bitmap[ i * 8 + 6 ] = VTermFont[index] & (1 << 6) ? 255 : 0;
232                 ret->Bitmap[ i * 8 + 7 ] = VTermFont[index] & (1 << 7) ? 255 : 0;
233         }
234
235         return ret;
236 }
237
238
239 /**
240  * \fn int ReadUTF8(char *Input, uint32_t *Val)
241  * \brief Read a UTF-8 character from a string
242  */
243 int ReadUTF8(char *Input, uint32_t *Val)
244 {
245         uint8_t *str = (uint8_t *)Input;
246         *Val = 0xFFFD;  // Assume invalid character
247         
248         // ASCII
249         if( !(*str & 0x80) ) {
250                 *Val = *str;
251                 return 1;
252         }
253         
254         // Middle of a sequence
255         if( (*str & 0xC0) == 0x80 ) {
256                 return 1;
257         }
258         
259         // Two Byte
260         if( (*str & 0xE0) == 0xC0 ) {
261                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
262                 str ++;
263                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
264                 *Val |= (*str & 0x3F);  // Lower 6 Bits
265                 return 2;
266         }
267         
268         // Three Byte
269         if( (*str & 0xF0) == 0xE0 ) {
270                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
271                 str ++;
272                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
273                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
274                 str ++;
275                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
276                 *Val |= (*str & 0x3F);  // Lower 6 Bits
277                 return 3;
278         }
279         
280         // Four Byte
281         if( (*str & 0xF1) == 0xF0 ) {
282                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
283                 str ++;
284                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
285                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
286                 str ++;
287                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
288                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
289                 str ++;
290                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
291                 *Val |= (*str & 0x3F);  // Lower 6 Bits
292                 return 4;
293         }
294         
295         // UTF-8 Doesn't support more than four bytes
296         return 4;
297 }
298
299
300
301

UCC git Repository :: git.ucc.asn.au