Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-cache / glyph.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * Glyph Cache
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <freerdp/freerdp.h>
21 #include <freerdp/utils/stream.h>
22 #include <freerdp/utils/memory.h>
23
24 #include <freerdp/cache/glyph.h>
25
26 void update_process_glyph(rdpContext* context, uint8* data, int* index,
27                 int* x, int* y, uint32 cacheId, uint32 ulCharInc, uint32 flAccel)
28 {
29         int offset;
30         rdpGlyph* glyph;
31         uint32 cacheIndex;
32         rdpGraphics* graphics;
33         rdpGlyphCache* glyph_cache;
34
35         graphics = context->graphics;
36         glyph_cache = context->cache->glyph;
37
38         cacheIndex = data[*index];
39
40         glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
41
42         if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
43         {
44                 (*index)++;
45                 offset = data[*index];
46
47                 if (offset & 0x80)
48                 {
49                         offset = data[*index + 1] | (data[*index + 2] << 8);
50                         (*index)++;
51                         (*index)++;
52                 }
53
54                 if (flAccel & SO_VERTICAL)
55                         *y += offset;
56                 else
57                         *x += offset;
58         }
59
60         if (glyph != NULL)
61         {
62                 Glyph_Draw(context, glyph, glyph->x + *x, glyph->y + *y);
63
64                 if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
65                         *x += glyph->cx;
66         }
67 }
68
69 void update_process_glyph_fragments(rdpContext* context, uint8* data, uint32 length,
70                 uint32 cacheId, uint32 ulCharInc, uint32 flAccel, uint32 bgcolor, uint32 fgcolor, int x, int y,
71                 int bkX, int bkY, int bkWidth, int bkHeight, int opX, int opY, int opWidth, int opHeight)
72 {
73         int n;
74         uint32 id;
75         uint32 size;
76         int index = 0;
77         uint8* fragments;
78         rdpGraphics* graphics;
79         rdpGlyphCache* glyph_cache;
80
81         graphics = context->graphics;
82         glyph_cache = context->cache->glyph;
83
84         if (opWidth > 0 && opHeight > 0)
85                 Glyph_BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor);
86         else
87                 Glyph_BeginDraw(context, 0, 0, 0, 0, bgcolor, fgcolor);
88
89         while (index < (int) length)
90         {
91                 switch (data[index])
92                 {
93                         case GLYPH_FRAGMENT_USE:
94
95                                 if (index + 2 > (int) length)
96                                 {
97                                         /* at least one byte need to follow */
98                                         index = length = 0;
99                                         break;
100                                 }
101
102                                 id = data[index + 1];
103                                 fragments = (uint8*) glyph_cache_fragment_get(glyph_cache, id, &size);
104
105                                 if (fragments != NULL)
106                                 {
107                                         if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
108                                         {
109                                                 if (flAccel & SO_VERTICAL)
110                                                         y += data[index + 2];
111                                                 else
112                                                         x += data[index + 2];
113                                         }
114
115                                         for (n = 0; n < (int) size; n++)
116                                         {
117                                                 update_process_glyph(context, fragments, &n, &x, &y, cacheId, ulCharInc, flAccel);
118                                         }
119                                 }
120
121                                 index += (index + 2 < (int) length) ? 3 : 2;
122                                 length -= index;
123                                 data = &(data[index]);
124                                 index = 0;
125
126                                 break;
127
128                         case GLYPH_FRAGMENT_ADD:
129
130                                 if (index + 3 > (int) length)
131                                 {
132                                         /* at least two bytes need to follow */
133                                         index = length = 0;
134                                         break;
135                                 }
136
137                                 id = data[index + 1];
138                                 size = data[index + 2];
139
140                                 fragments = (uint8*) xmalloc(size);
141                                 memcpy(fragments, data, size);
142                                 glyph_cache_fragment_put(glyph_cache, id, size, fragments);
143
144                                 index += 3;
145                                 length -= index;
146                                 data = &(data[index]);
147                                 index = 0;
148
149                                 break;
150
151                         default:
152                                 update_process_glyph(context, data, &index, &x, &y, cacheId, ulCharInc, flAccel);
153                                 index++;
154                                 break;
155                 }
156         }
157
158         if (opWidth > 0 && opHeight > 0)
159                 Glyph_EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor);
160         else
161                 Glyph_EndDraw(context, bkX, bkY, bkWidth, bkHeight, bgcolor, fgcolor);
162 }
163
164 void update_gdi_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyph_index)
165 {
166         rdpGlyphCache* glyph_cache;
167
168         glyph_cache = context->cache->glyph;
169         update_process_glyph_fragments(context, glyph_index->data, glyph_index->cbData,
170                         glyph_index->cacheId, glyph_index->ulCharInc, glyph_index->flAccel,
171                         glyph_index->backColor, glyph_index->foreColor, glyph_index->x, glyph_index->y,
172                         glyph_index->bkLeft, glyph_index->bkTop,
173                         glyph_index->bkRight - glyph_index->bkLeft, glyph_index->bkBottom - glyph_index->bkTop,
174                         glyph_index->opLeft, glyph_index->opTop,
175                         glyph_index->opRight - glyph_index->opLeft, glyph_index->opBottom - glyph_index->opTop);
176 }
177
178 void update_gdi_fast_index(rdpContext* context, FAST_INDEX_ORDER* fast_index)
179 {
180         sint32 opLeft, opTop, opRight, opBottom;
181         sint32 x, y;
182         rdpGlyphCache* glyph_cache;
183
184         glyph_cache = context->cache->glyph;
185
186         opLeft = fast_index->opLeft;
187         opTop = fast_index->opTop;
188         opRight = fast_index->opRight;
189         opBottom = fast_index->opBottom;
190         x = fast_index->x;
191         y = fast_index->y;
192
193         if (opBottom == -32768)
194         {
195                 uint8 flags = (uint8) (opTop & 0x0F);
196
197                 if (flags & 0x01)
198                         opBottom = fast_index->bkBottom;
199                 if (flags & 0x02)
200                         opRight = fast_index->bkRight;
201                 if (flags & 0x04)
202                         opTop = fast_index->bkTop;
203                 if (flags & 0x08)
204                         opLeft = fast_index->bkLeft;
205         }
206
207         if (opLeft == 0)
208                 opLeft = fast_index->bkLeft;
209
210         if (opRight == 0)
211                 opRight = fast_index->bkRight;
212
213         if (x == -32768)
214                 x = fast_index->bkLeft;
215
216         if (y == -32768)
217                 y = fast_index->bkTop;
218
219         update_process_glyph_fragments(context, fast_index->data, fast_index->cbData,
220                         fast_index->cacheId, fast_index->ulCharInc, fast_index->flAccel,
221                         fast_index->backColor, fast_index->foreColor, x, y,
222                         fast_index->bkLeft, fast_index->bkTop,
223                         fast_index->bkRight - fast_index->bkLeft, fast_index->bkBottom - fast_index->bkTop,
224                         opLeft, opTop,
225                         opRight - opLeft, opBottom - opTop);
226 }
227
228 void update_gdi_fast_glyph(rdpContext* context, FAST_GLYPH_ORDER* fast_glyph)
229 {
230         sint32 opLeft, opTop, opRight, opBottom;
231         sint32 x, y;
232         GLYPH_DATA_V2* glyph_data;
233         rdpGlyph* glyph;
234         rdpCache* cache = context->cache;
235         uint8 text_data[2];
236
237         opLeft = fast_glyph->opLeft;
238         opTop = fast_glyph->opTop;
239         opRight = fast_glyph->opRight;
240         opBottom = fast_glyph->opBottom;
241         x = fast_glyph->x;
242         y = fast_glyph->y;
243
244         if (opBottom == -32768)
245         {
246                 uint8 flags = (uint8) (opTop & 0x0F);
247
248                 if (flags & 0x01)
249                         opBottom = fast_glyph->bkBottom;
250                 if (flags & 0x02)
251                         opRight = fast_glyph->bkRight;
252                 if (flags & 0x04)
253                         opTop = fast_glyph->bkTop;
254                 if (flags & 0x08)
255                         opLeft = fast_glyph->bkLeft;
256         }
257
258         if (opLeft == 0)
259                 opLeft = fast_glyph->bkLeft;
260
261         if (opRight == 0)
262                 opRight = fast_glyph->bkRight;
263
264         if (x == -32768)
265                 x = fast_glyph->bkLeft;
266
267         if (y == -32768)
268                 y = fast_glyph->bkTop;
269
270         if (fast_glyph->glyph_data != NULL)
271         {
272                 /* got option font that needs to go into cache */
273                 glyph_data = (GLYPH_DATA_V2*) (fast_glyph->glyph_data);
274                 glyph = Glyph_Alloc(context);
275                 glyph->x = glyph_data->x;
276                 glyph->y = glyph_data->y;
277                 glyph->cx = glyph_data->cx;
278                 glyph->cy = glyph_data->cy;
279                 glyph->aj = glyph_data->aj;
280                 glyph->cb = glyph_data->cb;
281                 Glyph_New(context, glyph);
282                 glyph_cache_put(cache->glyph, fast_glyph->cacheId, fast_glyph->data[0], glyph);
283                 xfree(fast_glyph->glyph_data);
284                 fast_glyph->glyph_data = NULL;
285         }
286
287         text_data[0] = fast_glyph->data[0];
288         text_data[1] = 0;
289
290         update_process_glyph_fragments(context, text_data, 1,
291                         fast_glyph->cacheId, fast_glyph->ulCharInc, fast_glyph->flAccel,
292                         fast_glyph->backColor, fast_glyph->foreColor, x, y,
293                         fast_glyph->bkLeft, fast_glyph->bkTop,
294                         fast_glyph->bkRight - fast_glyph->bkLeft, fast_glyph->bkBottom - fast_glyph->bkTop,
295                         opLeft, opTop,
296                         opRight - opLeft, opBottom - opTop);
297 }
298
299 void update_gdi_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cache_glyph)
300 {
301         int i;
302         rdpGlyph* glyph;
303         GLYPH_DATA* glyph_data;
304         rdpCache* cache = context->cache;
305
306         for (i = 0; i < (int) cache_glyph->cGlyphs; i++)
307         {
308                 glyph_data = cache_glyph->glyphData[i];
309
310                 glyph = Glyph_Alloc(context);
311
312                 glyph->x = glyph_data->x;
313                 glyph->y = glyph_data->y;
314                 glyph->cx = glyph_data->cx;
315                 glyph->cy = glyph_data->cy;
316                 glyph->aj = glyph_data->aj;
317                 glyph->cb = glyph_data->cb;
318                 Glyph_New(context, glyph);
319
320                 glyph_cache_put(cache->glyph, cache_glyph->cacheId, glyph_data->cacheIndex, glyph);
321
322                 cache_glyph->glyphData[i] = NULL;
323                 xfree(glyph_data);
324         }
325 }
326
327 void update_gdi_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER* cache_glyph_v2)
328 {
329         int i;
330         rdpGlyph* glyph;
331         GLYPH_DATA_V2* glyph_data;
332         rdpCache* cache = context->cache;
333
334         for (i = 0; i < (int) cache_glyph_v2->cGlyphs; i++)
335         {
336                 glyph_data = cache_glyph_v2->glyphData[i];
337
338                 glyph = Glyph_Alloc(context);
339
340                 glyph->x = glyph_data->x;
341                 glyph->y = glyph_data->y;
342                 glyph->cx = glyph_data->cx;
343                 glyph->cy = glyph_data->cy;
344                 glyph->aj = glyph_data->aj;
345                 glyph->cb = glyph_data->cb;
346                 Glyph_New(context, glyph);
347
348                 glyph_cache_put(cache->glyph, cache_glyph_v2->cacheId, glyph_data->cacheIndex, glyph);
349
350                 cache_glyph_v2->glyphData[i] = NULL;
351                 xfree(glyph_data);
352         }
353 }
354
355 rdpGlyph* glyph_cache_get(rdpGlyphCache* glyph_cache, uint32 id, uint32 index)
356 {
357         rdpGlyph* glyph;
358
359         if (id > 9)
360         {
361                 printf("invalid glyph cache id: %d\n", id);
362                 return NULL;
363         }
364
365         if (index > glyph_cache->glyphCache[id].number)
366         {
367                 printf("invalid glyph cache index: %d in cache id: %d\n", index, id);
368                 return NULL;
369         }
370
371         glyph = glyph_cache->glyphCache[id].entries[index];
372
373         if (glyph == NULL)
374         {
375                 printf("invalid glyph at cache index: %d in cache id: %d\n", index, id);
376         }
377
378         return glyph;
379 }
380
381 void glyph_cache_put(rdpGlyphCache* glyph_cache, uint32 id, uint32 index, rdpGlyph* glyph)
382 {
383         rdpGlyph* prevGlyph;
384
385         if (id > 9)
386         {
387                 printf("invalid glyph cache id: %d\n", id);
388                 return;
389         }
390
391         if (index > glyph_cache->glyphCache[id].number)
392         {
393                 printf("invalid glyph cache index: %d in cache id: %d\n", index, id);
394                 return;
395         }
396
397         prevGlyph = glyph_cache->glyphCache[id].entries[index];
398
399         if (prevGlyph != NULL)
400         {
401                 Glyph_Free(glyph_cache->context, prevGlyph);
402                 xfree(prevGlyph->aj);
403                 xfree(prevGlyph);
404         }
405
406         glyph_cache->glyphCache[id].entries[index] = glyph;
407 }
408
409 void* glyph_cache_fragment_get(rdpGlyphCache* glyph_cache, uint32 index, uint32* size)
410 {
411         void* fragment;
412
413         fragment = glyph_cache->fragCache.entries[index].fragment;
414         *size = (uint8) glyph_cache->fragCache.entries[index].size;
415
416         if (fragment == NULL)
417         {
418                 printf("invalid glyph fragment at index:%d\n", index);
419         }
420
421         return fragment;
422 }
423
424 void glyph_cache_fragment_put(rdpGlyphCache* glyph_cache, uint32 index, uint32 size, void* fragment)
425 {
426         void* prevFragment;
427
428         prevFragment = glyph_cache->fragCache.entries[index].fragment;
429
430         glyph_cache->fragCache.entries[index].fragment = fragment;
431         glyph_cache->fragCache.entries[index].size = size;
432
433         if (prevFragment != NULL)
434         {
435                 xfree(prevFragment);
436         }
437 }
438
439 void glyph_cache_register_callbacks(rdpUpdate* update)
440 {
441         update->primary->GlyphIndex = update_gdi_glyph_index;
442         update->primary->FastIndex = update_gdi_fast_index;
443         update->primary->FastGlyph = update_gdi_fast_glyph;
444         update->secondary->CacheGlyph = update_gdi_cache_glyph;
445         update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
446 }
447
448 rdpGlyphCache* glyph_cache_new(rdpSettings* settings)
449 {
450         rdpGlyphCache* glyph;
451
452         glyph = (rdpGlyphCache*) xzalloc(sizeof(rdpGlyphCache));
453
454         if (glyph != NULL)
455         {
456                 int i;
457
458                 glyph->settings = settings;
459                 glyph->context = ((freerdp*) settings->instance)->update->context;
460
461                 if (settings->glyph_cache)
462                         settings->glyphSupportLevel = GLYPH_SUPPORT_FULL;
463
464                 for (i = 0; i < 10; i++)
465                 {
466                         glyph->glyphCache[i].number = settings->glyphCache[i].cacheEntries;
467                         glyph->glyphCache[i].maxCellSize = settings->glyphCache[i].cacheMaximumCellSize;
468                         glyph->glyphCache[i].entries = (rdpGlyph**) xzalloc(sizeof(rdpGlyph*) * glyph->glyphCache[i].number);
469                 }
470
471                 glyph->fragCache.entries = xzalloc(sizeof(FRAGMENT_CACHE_ENTRY) * 256);
472         }
473
474         return glyph;
475 }
476
477 void glyph_cache_free(rdpGlyphCache* glyph_cache)
478 {
479         if (glyph_cache != NULL)
480         {
481                 int i;
482                 void* fragment;
483
484                 for (i = 0; i < 10; i++)
485                 {
486                         int j;
487
488                         for (j = 0; j < (int) glyph_cache->glyphCache[i].number; j++)
489                         {
490                                 rdpGlyph* glyph;
491
492                                 glyph = glyph_cache->glyphCache[i].entries[j];
493
494                                 if (glyph != NULL)
495                                 {
496                                         Glyph_Free(glyph_cache->context, glyph);
497                                         xfree(glyph->aj);
498                                         xfree(glyph);
499                                 }
500                         }
501                         xfree(glyph_cache->glyphCache[i].entries);
502                 }
503
504                 for (i = 0; i < 255; i++)
505                 {
506                         fragment = glyph_cache->fragCache.entries[i].fragment;
507                         xfree(fragment);
508                 }
509
510                 xfree(glyph_cache->fragCache.entries);
511                 xfree(glyph_cache);
512         }
513 }