shadow: initial font rendering
[platform/upstream/freerdp.git] / server / shadow / shadow_font.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  *
4  * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <winpr/crt.h>
24 #include <winpr/path.h>
25
26 #include "shadow.h"
27
28 #include "shadow_font.h"
29
30 int shadow_font_draw_glyph(rdpShadowSurface* surface, int nXDst, int nYDst, rdpShadowFont* font, rdpShadowGlyph* glyph)
31 {
32         int x, y;
33         int nXSrc;
34         int nYSrc;
35         int nWidth;
36         int nHeight;
37         int nSrcStep;
38         int nDstStep;
39         int nSrcPad;
40         int nDstPad;
41         BYTE* pSrcData;
42         BYTE* pSrcPixel;
43         BYTE* pDstData;
44         BYTE* pDstPixel;
45         BYTE A, R, G, B;
46
47         nXDst += glyph->offsetX;
48         nYDst += glyph->offsetY;
49
50         nXSrc = glyph->rectX;
51         nYSrc = glyph->rectY;
52
53         nWidth = glyph->rectWidth;
54         nHeight = glyph->rectHeight;
55
56         nSrcStep = font->image->scanline;
57         pSrcData = font->image->data;
58
59         pDstData = surface->data;
60         nDstStep = surface->scanline;
61
62         nSrcPad = (nSrcStep - (nWidth * 4));
63         nDstPad = (nDstStep - (nWidth * 4));
64
65         pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
66         pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)];
67
68         for (y = 0; y < nHeight; y++)
69         {
70                 pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)];
71                 pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)];
72
73                 for (x = 0; x < nWidth; x++)
74                 {
75                         B = pSrcPixel[0];
76                         G = pSrcPixel[1];
77                         R = pSrcPixel[2];
78                         A = pSrcPixel[3];
79                         pSrcPixel += 4;
80
81                         if (1)
82                         {
83                                 /* tint black */
84                                 R = 255 - R;
85                                 G = 255 - G;
86                                 B = 255 - B;
87                         }
88
89                         if (A == 255)
90                         {
91                                 pDstPixel[0] = B;
92                                 pDstPixel[1] = G;
93                                 pDstPixel[2] = R;
94                         }
95                         else
96                         {
97                                 R = (R * A) / 255;
98                                 G = (G * A) / 255;
99                                 B = (B * A) / 255;
100
101                                 pDstPixel[0] = B + (pDstPixel[0] * (255 - A) + (255 / 2)) / 255;
102                                 pDstPixel[1] = G + (pDstPixel[1] * (255 - A) + (255 / 2)) / 255;
103                                 pDstPixel[2] = R + (pDstPixel[2] * (255 - A) + (255 / 2)) / 255;
104                         }
105
106                         pDstPixel[3] = 0xFF;
107                         pDstPixel += 4;
108                 }
109
110                 pSrcPixel += nSrcPad;
111                 pDstPixel += nDstPad;
112         }
113
114         return 1;
115 }
116
117 int shadow_font_draw_text(rdpShadowSurface* surface, int nXDst, int nYDst, rdpShadowFont* font, const char* text)
118 {
119         int index;
120         int length;
121         rdpShadowGlyph* glyph;
122
123         length = strlen(text);
124
125         for (index = 0; index < length; index++)
126         {
127                 glyph = &font->glyphs[text[index] - 32];
128                 shadow_font_draw_glyph(surface, nXDst, nYDst, font, glyph);
129                 nXDst += (glyph->width + 1);
130         }
131
132         return 1;
133 }
134
135 char* shadow_font_load_descriptor_file(const char* filename, int* pSize)
136 {
137         BYTE* buffer;
138         FILE* fp = NULL;
139         size_t readSize;
140         size_t fileSize;
141
142         fp = fopen(filename, "r");
143
144         if (!fp)
145                 return NULL;
146
147         fseek(fp, 0, SEEK_END);
148         fileSize = ftell(fp);
149         fseek(fp, 0, SEEK_SET);
150
151         if (fileSize < 1)
152         {
153                 fclose(fp);
154                 return NULL;
155         }
156
157         buffer = (BYTE*) malloc(fileSize + 2);
158
159         if (!buffer)
160         {
161                 fclose(fp);
162                 return NULL;
163         }
164
165         readSize = fread(buffer, fileSize, 1, fp);
166
167         if (!readSize)
168         {
169                 if (!ferror(fp))
170                         readSize = fileSize;
171         }
172
173         fclose(fp);
174
175         if (readSize < 1)
176         {
177                 free(buffer);
178                 return NULL;
179         }
180
181         buffer[fileSize] = '\0';
182         buffer[fileSize + 1] = '\0';
183
184         *pSize = (int) fileSize;
185         return (char*) buffer;
186 }
187
188 int shadow_font_convert_descriptor_code_to_utf8(const char* str, BYTE* utf8)
189 {
190         int len = strlen(str);
191
192         *((UINT32*) utf8) = 0;
193
194         if (len < 1)
195                 return 1;
196
197         if (len == 1)
198         {
199                 if ((str[0] > 31) && (str[0] < 127))
200                 {
201                         utf8[0] = str[0];
202                 }
203         }
204         else
205         {
206                 if (str[0] == '&')
207                 {
208                         const char* acc = &str[1];
209
210                         if (strcmp(acc, "quot;") == 0)
211                                 utf8[0] = '"';
212                         else if (strcmp(acc, "amp;") == 0)
213                                 utf8[0] = '&';
214                         else if (strcmp(acc, "lt;") == 0)
215                                 utf8[0] = '<';
216                         else if (strcmp(acc, "gt;") == 0)
217                                 utf8[0] = '>';
218                 }
219         }
220
221         return 1;
222 }
223
224 int shadow_font_load_descriptor(rdpShadowFont* font, const char* filename)
225 {
226         char* p;
227         char* q;
228         char* r;
229         char* beg;
230         char* end;
231         char* tok[4];
232         int index;
233         int count;
234         int size;
235         char* buffer;
236         rdpShadowGlyph* glyph;
237
238         buffer = shadow_font_load_descriptor_file(filename, &size);
239
240         if (!buffer)
241                 return -1;
242
243         p = strstr(buffer, "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
244
245         if (!p)
246                 return -1;
247
248         p += sizeof("<?xml version=\"1.0\" encoding=\"utf-8\"?>") - 1;
249
250         p = strstr(p, "<Font ");
251
252         if (!p)
253                 return -1;
254
255         p += sizeof("<Font ") - 1;
256
257         /* find closing font tag */
258
259         end = strstr(p, "</Font>");
260
261         if (!end)
262                 return -1;
263
264         /* parse font size */
265
266         p = strstr(p, "size=\"");
267
268         if (!p)
269                 return -1;
270
271         p += sizeof("size=\"") - 1;
272         q = strchr(p, '"');
273
274         if (!q)
275                 return -1;
276
277         *q = '\0';
278         font->size = atoi(p);
279         *q = '"';
280
281         if (font->size <= 0)
282                 return -1;
283
284         p = q + 1;
285
286         /* parse font family */
287
288         p = strstr(p, "family=\"");
289
290         if (!p)
291                 return -1;
292
293         p += sizeof("family=\"") - 1;
294         q = strchr(p, '"');
295
296         if (!q)
297                 return -1;
298
299         *q = '\0';
300         font->family = _strdup(p);
301         *q = '"';
302
303         if (!font->family)
304                 return -1;
305
306         p = q + 1;
307
308         /* parse font height */
309
310         p = strstr(p, "height=\"");
311
312         if (!p)
313                 return -1;
314
315         p += sizeof("height=\"") - 1;
316         q = strchr(p, '"');
317
318         if (!q)
319                 return -1;
320
321         *q = '\0';
322         font->height = atoi(p);
323         *q = '"';
324
325         if (font->height <= 0)
326                 return -1;
327
328         p = q + 1;
329
330         /* parse font style */
331
332         p = strstr(p, "style=\"");
333
334         if (!p)
335                 return -1;
336
337         p += sizeof("style=\"") - 1;
338         q = strchr(p, '"');
339
340         if (!q)
341                 return -1;
342
343         *q = '\0';
344         font->style = _strdup(p);
345         *q = '"';
346
347         if (!font->style)
348                 return -1;
349
350         p = q + 1;
351
352         printf("size: %d family: %s height: %d style: %s\n",
353                         font->size, font->family, font->height, font->style);
354
355         beg = p;
356         count = 0;
357
358         while (p < end)
359         {
360                 p = strstr(p, "<Char ");
361
362                 if (!p)
363                         return -1;
364
365                 p += sizeof("<Char ") - 1;
366
367                 r = strstr(p, "/>");
368
369                 if (!r)
370                         return -1;
371
372                 *r = '\0';
373
374                 p = r + sizeof("/>");
375                 *r = '/';
376
377                 count++;
378         }
379
380         font->glyphCount = count;
381         font->glyphs = (rdpShadowGlyph*) calloc(font->glyphCount, sizeof(rdpShadowGlyph));
382
383         if (!font->glyphs)
384                 return -1;
385
386         p = beg;
387         index = 0;
388
389         while (p < end)
390         {
391                 p = strstr(p, "<Char ");
392
393                 if (!p)
394                         return -1;
395
396                 p += sizeof("<Char ") - 1;
397
398                 r = strstr(p, "/>");
399
400                 if (!r)
401                         return -1;
402
403                 *r = '\0';
404
405                 /* start parsing glyph */
406
407                 glyph = &font->glyphs[index];
408
409                 /* parse glyph width */
410
411                 p = strstr(p, "width=\"");
412
413                 if (!p)
414                         return -1;
415
416                 p += sizeof("width=\"") - 1;
417                 q = strchr(p, '"');
418
419                 if (!q)
420                         return -1;
421
422                 *q = '\0';
423                 glyph->width = atoi(p);
424                 *q = '"';
425
426                 if (glyph->width < 0)
427                         return -1;
428
429                 p = q + 1;
430
431                 /* parse glyph offset x,y */
432
433                 p = strstr(p, "offset=\"");
434
435                 if (!p)
436                         return -1;
437
438                 p += sizeof("offset=\"") - 1;
439                 q = strchr(p, '"');
440
441                 if (!q)
442                         return -1;
443
444                 *q = '\0';
445
446                 tok[0] = p;
447
448                 p = strchr(tok[0] + 1, ' ');
449
450                 if (!p)
451                         return -1;
452
453                 *p = 0;
454                 tok[1] = p + 1;
455
456                 glyph->offsetX = atoi(tok[0]);
457                 glyph->offsetY = atoi(tok[1]);
458
459                 *q = '"';
460
461                 p = q + 1;
462
463                 /* parse glyph rect x,y,w,h */
464
465                 p = strstr(p, "rect=\"");
466
467                 if (!p)
468                         return -1;
469
470                 p += sizeof("rect=\"") - 1;
471                 q = strchr(p, '"');
472
473                 if (!q)
474                         return -1;
475
476                 *q = '\0';
477
478                 tok[0] = p;
479
480                 p = strchr(tok[0] + 1, ' ');
481
482                 if (!p)
483                         return -1;
484
485                 *p = 0;
486                 tok[1] = p + 1;
487
488                 p = strchr(tok[1] + 1, ' ');
489
490                 if (!p)
491                         return -1;
492
493                 *p = 0;
494                 tok[2] = p + 1;
495
496                 p = strchr(tok[2] + 1, ' ');
497
498                 if (!p)
499                         return -1;
500
501                 *p = 0;
502                 tok[3] = p + 1;
503
504                 glyph->rectX = atoi(tok[0]);
505                 glyph->rectY = atoi(tok[1]);
506                 glyph->rectWidth = atoi(tok[2]);
507                 glyph->rectHeight = atoi(tok[3]);
508
509                 *q = '"';
510
511                 p = q + 1;
512
513                 /* parse code */
514
515                 p = strstr(p, "code=\"");
516
517                 if (!p)
518                         return -1;
519
520                 p += sizeof("code=\"") - 1;
521                 q = strchr(p, '"');
522
523                 if (!q)
524                         return -1;
525
526                 *q = '\0';
527                 shadow_font_convert_descriptor_code_to_utf8(p, glyph->code);
528                 *q = '"';
529
530                 p = q + 1;
531
532                 /* finish parsing glyph */
533
534                 p = r + sizeof("/>");
535                 *r = '/';
536
537                 index++;
538         }
539
540         return 1;
541 }
542
543 rdpShadowFont* shadow_font_new(const char* path, const char* file)
544 {
545         int status;
546         int length;
547         rdpShadowFont* font;
548         char* fontBaseFile;
549         char* fontImageFile;
550         char* fontDescriptorFile;
551
552         fontBaseFile = GetCombinedPath(path, file);
553
554         if (!fontBaseFile)
555                 return NULL;
556
557         length = strlen(fontBaseFile);
558
559         fontImageFile = (char*) malloc(length + 8);
560
561         if (!fontImageFile)
562                 return NULL;
563
564         strcpy(fontImageFile, fontBaseFile);
565         strcpy(&fontImageFile[length], ".png");
566
567         fontDescriptorFile = (char*) malloc(length + 8);
568
569         if (!fontImageFile)
570                 return NULL;
571
572         strcpy(fontDescriptorFile, fontBaseFile);
573         strcpy(&fontDescriptorFile[length], ".xml");
574
575         free(fontBaseFile);
576
577         if (!PathFileExistsA(fontImageFile))
578                 return NULL;
579
580         if (!PathFileExistsA(fontDescriptorFile))
581                 return NULL;
582
583         font = (rdpShadowFont*) calloc(1, sizeof(rdpShadowFont));
584
585         if (!font)
586                 return NULL;
587
588         font->image = winpr_image_new();
589
590         if (!font->image)
591                 return NULL;
592
593         status = winpr_image_read(font->image, fontImageFile);
594
595         if (status < 0)
596                 return NULL;
597
598         status = shadow_font_load_descriptor(font, fontDescriptorFile);
599
600         free(fontImageFile);
601         free(fontDescriptorFile);
602
603         return font;
604 }
605
606 void shadow_font_free(rdpShadowFont* font)
607 {
608         if (!font)
609                 return;
610
611         free(font);
612 }