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

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