Fixing bugs exposed by scan-build
[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 #include <utf8.h>
12
13 // === TYPES ===
14 typedef struct sGlyph   tGlyph;
15
16 struct sGlyph
17 {
18         struct sGlyph   *Next;
19         struct sGlyph   *Prev;
20         
21         uint32_t        Codepoint;
22         
23         // Effective dimensions (distance to move 'cursor')
24         short   Width;
25         short   Height;
26         
27         // Distance from the current cursor position to render at
28         short   OffsetX;
29         short   OffsetY;
30         
31         // True dimensions (size of the bitmap
32         short   TrueWidth;
33         short   TrueHeight;
34         
35         // Bitmap Data
36         uint8_t Bitmap[];       // 8-bit alpha  
37 };
38
39 struct sFont
40 {
41         struct sFont    *Next;
42          int    ReferenceCount;
43         
44         tGlyph  *AsciiGlyphs[128];      // Glyphs 0-127
45         
46         tGlyph  *FirstGlyph;
47         tGlyph  *LastGlyph;
48         
49         tGlyph  *(*CacheGlyph)(struct sFont *this, uint32_t Codepoint);
50         
51 };
52
53
54 // === PROTOTYPES ===
55  int    WM_Render_DrawText(tWindow *Window, int X, int Y, int W, int H, tFont *Font, tColour Color, const char *Text, int MaxLen);
56 void    WM_Render_GetTextDims(tFont *Font, const char *Text, int MaxLen, int *W, int *H);
57 tGlyph  *_GetGlyph(tFont *Font, uint32_t Codepoint);
58 void    _RenderGlyph(tWindow *Window, short X, short Y, tGlyph *Glyph, uint32_t Color);
59 tGlyph  *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint);
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, int MaxLen)
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         if(MaxLen < 0)  MaxLen = INT_MAX;
82
83         X += Window->BorderL;
84         Y += Window->BorderT;
85
86         // Check the bounds
87         if(W < 0 || X < 0 || X >= Window->RealW)        return 0;
88         if(X + W > Window->RealW)       W = Window->RealW - X;
89         
90         if(H < 0 || Y < 0 || Y >= Window->RealH)        return 0;
91         if(Y + H > Window->RealH)       H = Window->RealH - Y;
92         
93         // TODO: Catch trampling of decorations
94
95         // Handle NULL font (system default monospace)
96         if( !Font )     Font = &gSystemFont;
97         
98         while( MaxLen > 0 && *Text )
99         {
100                  int    len;
101                 // Read character
102                 len = ReadUTF8(Text, &ch);
103                 Text += len;
104                 MaxLen -= len;
105                 
106                 // Find (or load) the glyph
107                 glyph = _GetGlyph(Font, ch);
108                 if( !glyph )    continue ;      // If not found, just don't render it
109                 
110                 // End render if it will overflow the provided range
111                 if( xOfs + glyph->TrueWidth > W )
112                         break;
113                 
114                 _RenderGlyph(Window, X + xOfs, Y, glyph, Colour);
115                 xOfs += glyph->Width;
116         }
117         
118         return xOfs;
119 }
120
121 void WM_Render_GetTextDims(tFont *Font, const char *Text, int MaxLen, int *W, int *H)
122 {
123          int    w=0, h=0;
124         uint32_t        ch;
125         tGlyph  *glyph;
126         if( !Font )     Font = &gSystemFont;
127         
128         if(MaxLen < 0)  MaxLen = INT_MAX;
129
130         while( MaxLen > 0 && *Text )
131         {
132                  int    len;
133                 len = ReadUTF8(Text, &ch);
134                 Text += len;
135                 MaxLen -= len;
136                 glyph = _GetGlyph(Font, ch);
137                 if( !glyph )    continue;
138                 
139                 w += glyph->Width;
140                 if( h < glyph->Height ) h = glyph->Height;
141         }
142         
143         if(W)   *W = w;
144         if(H)   *H = h;
145 }
146
147 tGlyph *_GetGlyph(tFont *Font, uint32_t Codepoint)
148 {
149         tGlyph  *next = NULL, *prev = NULL;
150         tGlyph  *new;
151         
152         // Check for ASCII
153         if( Codepoint < 128 )
154         {
155                 if( Font->AsciiGlyphs[Codepoint] == NULL ) {
156                         Font->AsciiGlyphs[Codepoint] = Font->CacheGlyph(Font, Codepoint);
157                 }
158                 
159                 return Font->AsciiGlyphs[Codepoint];
160         }
161         
162         // If within the range
163         if( Font->FirstGlyph && Font->FirstGlyph->Codepoint < Codepoint && Codepoint < Font->LastGlyph->Codepoint )
164         {
165                 // Find what end is "closest"
166                 if( Codepoint - Font->FirstGlyph->Codepoint < Font->LastGlyph->Codepoint - Codepoint )
167                 {
168                         // Start from the bottom
169                         for( next = Font->FirstGlyph;
170                                  next && next->Codepoint < Codepoint;
171                                  prev = next, next = next->Next
172                                  );
173                         
174                         if( next && next->Codepoint == Codepoint )
175                                 return next;
176                         
177                 }
178                 else
179                 {
180                         // Start at the top
181                         // NOTE: The roles of next and prev are reversed here to allow 
182                         //       the insert to be able to assume that `prev` is the
183                         //       previous entry, and `next` is the next.
184                         for( prev = Font->LastGlyph;
185                                  prev && prev->Codepoint > Codepoint;
186                                  next = prev, prev = prev->Prev
187                                  );
188                         if( prev && prev->Codepoint == Codepoint )
189                                 return prev;
190                 }
191         }
192         else
193         {
194                 // If below first
195                 if( !Font->FirstGlyph ||  Font->FirstGlyph->Codepoint > Codepoint ) {
196                         prev = NULL;
197                         next = Font->FirstGlyph;
198                 }
199                 // Above last
200                 else {
201                         prev = Font->LastGlyph;
202                         next = NULL;
203                 }
204         }
205         
206         // Load new
207         new = Font->CacheGlyph(Font, Codepoint);
208         if( !new )      return NULL;
209         
210         // Add to list
211         // - Forward link
212         if( prev ) {
213                 new->Next = prev->Next;
214                 prev->Next = new;
215         }
216         else {
217                 new->Next = Font->FirstGlyph;
218                 Font->FirstGlyph = new;
219         }
220         
221         // - Backlink
222         if( next ) {
223                 new->Prev = next->Prev;
224                 next->Prev = new;
225         }
226         else {
227                 new->Prev = Font->LastGlyph;
228                 Font->LastGlyph = new;
229         }
230         
231         // Return
232         return new;
233 }
234
235 /**
236  */
237 void _RenderGlyph(tWindow *Window, short X, short Y, tGlyph *Glyph, uint32_t Color)
238 {
239          int    xStart = 0, yStart = 0;
240          int    x, y, dst_x;
241         uint32_t        *outBuf;
242         uint8_t *inBuf;
243
244         X += Glyph->OffsetX;
245         if( X < 0 ) {   // If -ve, skip the first -X pixels
246                 xStart = -X;
247                 X = 0;
248         }
249
250         Y += Glyph->OffsetY;
251         if( Y < 0 ) {   // If -ve, skip the first -Y lines
252                 yStart = -Y;
253                 Y = 0;
254         }
255
256 //      _SysDebug("X = %i, Y = %i", X, Y);
257         outBuf = (uint32_t*)Window->RenderBuffer + Y*Window->RealW + X;
258         inBuf = Glyph->Bitmap + yStart*Glyph->TrueWidth;
259
260         for( y = yStart; y < Glyph->TrueHeight; y ++ )
261         {
262                 for( x = xStart, dst_x = 0; x < Glyph->TrueWidth; x ++, dst_x ++ )
263                 {
264                         outBuf[dst_x] = Video_AlphaBlend( outBuf[dst_x], Color, inBuf[x] );
265                 }
266                 outBuf += Window->RealW;
267                 inBuf += Glyph->TrueWidth;
268         }
269 }
270
271 // Load system font (8x16 monospace)
272 #include "font_8x16.h"
273
274 /*
275  */
276 tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint)
277 {
278          int    i;
279         uint8_t index = 0;
280         tGlyph  *ret;
281         uint8_t *data;
282
283 //      _SysDebug("_SystemFont_CacheGlyph: (Font=%p, Codepoint=0x%06x)", Font, Codepoint);
284         
285         if( Codepoint < 128 ) {
286                 index = Codepoint;
287         }
288         else {
289                 index = '?';    // Unknown glyphs come out as a question mark
290         }
291
292 //      _SysDebug(" index = %i", index);
293
294         ret = malloc( sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT );
295         if( !ret ) {
296                 _SysDebug("ERROR: malloc(%i) failed", sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT);
297                 return NULL;
298         }
299
300         ret->Codepoint = Codepoint;
301
302         ret->Width = FONT_WIDTH;
303         ret->Height = FONT_HEIGHT;
304         
305         ret->TrueWidth = FONT_WIDTH;
306         ret->TrueHeight = FONT_HEIGHT;
307
308         ret->OffsetX = 0;
309         ret->OffsetY = 0;
310         
311         data = &VTermFont[index * FONT_HEIGHT];
312
313         for( i = 0; i < FONT_HEIGHT; i ++ )
314         {
315                 ret->Bitmap[ i * 8 + 0 ] = data[i] & (1 << 7) ? 255 : 0;
316                 ret->Bitmap[ i * 8 + 1 ] = data[i] & (1 << 6) ? 255 : 0;
317                 ret->Bitmap[ i * 8 + 2 ] = data[i] & (1 << 5) ? 255 : 0;
318                 ret->Bitmap[ i * 8 + 3 ] = data[i] & (1 << 4) ? 255 : 0;
319                 ret->Bitmap[ i * 8 + 4 ] = data[i] & (1 << 3) ? 255 : 0;
320                 ret->Bitmap[ i * 8 + 5 ] = data[i] & (1 << 2) ? 255 : 0;
321                 ret->Bitmap[ i * 8 + 6 ] = data[i] & (1 << 1) ? 255 : 0;
322                 ret->Bitmap[ i * 8 + 7 ] = data[i] & (1 << 0) ? 255 : 0;
323         }
324
325         return ret;
326 }
327

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