1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Bitmap Cache V2
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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25
26 #include <winpr/crt.h>
27
28 #include <freerdp/freerdp.h>
29 #include <freerdp/constants.h>
30 #include <winpr/stream.h>
31
32 #include <freerdp/log.h>
33 #include <freerdp/cache/bitmap.h>
34 #include <freerdp/gdi/bitmap.h>
35
36 #include "../gdi/gdi.h"
37 #include "../core/graphics.h"
38
39 #include "bitmap.h"
40
41 #define TAG FREERDP_TAG("cache.bitmap")
42
43 static rdpBitmap* bitmap_cache_get(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index);
44 static BOOL bitmap_cache_put(rdpBitmapCache* bitmap_cache, UINT32 id, UINT32 index,
45 rdpBitmap* bitmap);
46
update_gdi_memblt(rdpContext * context,MEMBLT_ORDER * memblt)47 static BOOL update_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
48 {
49 rdpBitmap* bitmap;
50 rdpCache* cache = context->cache;
51
52 if (memblt->cacheId == 0xFF)
53 bitmap = offscreen_cache_get(cache->offscreen, memblt->cacheIndex);
54 else
55 bitmap = bitmap_cache_get(cache->bitmap, (BYTE)memblt->cacheId, memblt->cacheIndex);
56
57 /* XP-SP2 servers sometimes ask for cached bitmaps they've never defined. */
58 if (bitmap == NULL)
59 return TRUE;
60
61 memblt->bitmap = bitmap;
62 return IFCALLRESULT(TRUE, cache->bitmap->MemBlt, context, memblt);
63 }
64
update_gdi_mem3blt(rdpContext * context,MEM3BLT_ORDER * mem3blt)65 static BOOL update_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
66 {
67 BYTE style;
68 rdpBitmap* bitmap;
69 rdpCache* cache = context->cache;
70 rdpBrush* brush = &mem3blt->brush;
71 BOOL ret = TRUE;
72
73 if (mem3blt->cacheId == 0xFF)
74 bitmap = offscreen_cache_get(cache->offscreen, mem3blt->cacheIndex);
75 else
76 bitmap = bitmap_cache_get(cache->bitmap, (BYTE)mem3blt->cacheId, mem3blt->cacheIndex);
77
78 /* XP-SP2 servers sometimes ask for cached bitmaps they've never defined. */
79 if (!bitmap)
80 return TRUE;
81
82 style = brush->style;
83
84 if (brush->style & CACHED_BRUSH)
85 {
86 brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
87
88 if (!brush->data)
89 return FALSE;
90
91 brush->style = 0x03;
92 }
93
94 mem3blt->bitmap = bitmap;
95 IFCALLRET(cache->bitmap->Mem3Blt, ret, context, mem3blt);
96 brush->style = style;
97 return ret;
98 }
99
update_gdi_cache_bitmap(rdpContext * context,const CACHE_BITMAP_ORDER * cacheBitmap)100 static BOOL update_gdi_cache_bitmap(rdpContext* context, const CACHE_BITMAP_ORDER* cacheBitmap)
101 {
102 rdpBitmap* bitmap;
103 rdpBitmap* prevBitmap;
104 rdpCache* cache = context->cache;
105 bitmap = Bitmap_Alloc(context);
106
107 if (!bitmap)
108 return FALSE;
109
110 Bitmap_SetDimensions(bitmap, cacheBitmap->bitmapWidth, cacheBitmap->bitmapHeight);
111
112 if (!bitmap->Decompress(context, bitmap, cacheBitmap->bitmapDataStream,
113 cacheBitmap->bitmapWidth, cacheBitmap->bitmapHeight,
114 cacheBitmap->bitmapBpp, cacheBitmap->bitmapLength,
115 cacheBitmap->compressed, RDP_CODEC_ID_NONE))
116 {
117 Bitmap_Free(context, bitmap);
118 return FALSE;
119 }
120
121 if (!bitmap->New(context, bitmap))
122 {
123 Bitmap_Free(context, bitmap);
124 return FALSE;
125 }
126
127 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmap->cacheId, cacheBitmap->cacheIndex);
128 Bitmap_Free(context, prevBitmap);
129 return bitmap_cache_put(cache->bitmap, cacheBitmap->cacheId, cacheBitmap->cacheIndex, bitmap);
130 }
131
update_gdi_cache_bitmap_v2(rdpContext * context,CACHE_BITMAP_V2_ORDER * cacheBitmapV2)132 static BOOL update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cacheBitmapV2)
133
134 {
135 rdpBitmap* bitmap;
136 rdpBitmap* prevBitmap;
137 rdpCache* cache = context->cache;
138 rdpSettings* settings = context->settings;
139 bitmap = Bitmap_Alloc(context);
140
141 if (!bitmap)
142 return FALSE;
143
144 if (!cacheBitmapV2->bitmapBpp)
145 cacheBitmapV2->bitmapBpp = settings->ColorDepth;
146
147 if ((settings->ColorDepth == 15) && (cacheBitmapV2->bitmapBpp == 16))
148 cacheBitmapV2->bitmapBpp = settings->ColorDepth;
149
150 Bitmap_SetDimensions(bitmap, cacheBitmapV2->bitmapWidth, cacheBitmapV2->bitmapHeight);
151
152 if (!bitmap->Decompress(context, bitmap, cacheBitmapV2->bitmapDataStream,
153 cacheBitmapV2->bitmapWidth, cacheBitmapV2->bitmapHeight,
154 cacheBitmapV2->bitmapBpp, cacheBitmapV2->bitmapLength,
155 cacheBitmapV2->compressed, RDP_CODEC_ID_NONE))
156 {
157 Bitmap_Free(context, bitmap);
158 return FALSE;
159 }
160
161 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex);
162
163 if (!bitmap->New(context, bitmap))
164 {
165 Bitmap_Free(context, bitmap);
166 return FALSE;
167 }
168
169 Bitmap_Free(context, prevBitmap);
170 return bitmap_cache_put(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex,
171 bitmap);
172 }
173
update_gdi_cache_bitmap_v3(rdpContext * context,CACHE_BITMAP_V3_ORDER * cacheBitmapV3)174 static BOOL update_gdi_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cacheBitmapV3)
175 {
176 rdpBitmap* bitmap;
177 rdpBitmap* prevBitmap;
178 BOOL compressed = TRUE;
179 rdpCache* cache = context->cache;
180 rdpSettings* settings = context->settings;
181 BITMAP_DATA_EX* bitmapData = &cacheBitmapV3->bitmapData;
182 bitmap = Bitmap_Alloc(context);
183
184 if (!bitmap)
185 return FALSE;
186
187 if (!cacheBitmapV3->bpp)
188 cacheBitmapV3->bpp = settings->ColorDepth;
189
190 compressed = (bitmapData->codecID != RDP_CODEC_ID_NONE);
191 Bitmap_SetDimensions(bitmap, bitmapData->width, bitmapData->height);
192
193 if (!bitmap->Decompress(context, bitmap, bitmapData->data, bitmapData->width,
194 bitmapData->height, bitmapData->bpp, bitmapData->length, compressed,
195 bitmapData->codecID))
196 {
197 Bitmap_Free(context, bitmap);
198 return FALSE;
199 }
200
201 if (!bitmap->New(context, bitmap))
202 {
203 Bitmap_Free(context, bitmap);
204 return FALSE;
205 }
206
207 prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex);
208 Bitmap_Free(context, prevBitmap);
209 return bitmap_cache_put(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex,
210 bitmap);
211 }
212
bitmap_cache_get(rdpBitmapCache * bitmapCache,UINT32 id,UINT32 index)213 rdpBitmap* bitmap_cache_get(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index)
214 {
215 rdpBitmap* bitmap;
216
217 if (id >= bitmapCache->maxCells)
218 {
219 WLog_ERR(TAG, "get invalid bitmap cell id: %" PRIu32 "", id);
220 return NULL;
221 }
222
223 if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
224 {
225 index = bitmapCache->cells[id].number;
226 }
227 else if (index > bitmapCache->cells[id].number)
228 {
229 WLog_ERR(TAG, "get invalid bitmap index %" PRIu32 " in cell id: %" PRIu32 "", index, id);
230 return NULL;
231 }
232
233 bitmap = bitmapCache->cells[id].entries[index];
234 return bitmap;
235 }
236
bitmap_cache_put(rdpBitmapCache * bitmapCache,UINT32 id,UINT32 index,rdpBitmap * bitmap)237 BOOL bitmap_cache_put(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index, rdpBitmap* bitmap)
238 {
239 if (id > bitmapCache->maxCells)
240 {
241 WLog_ERR(TAG, "put invalid bitmap cell id: %" PRIu32 "", id);
242 return FALSE;
243 }
244
245 if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
246 {
247 index = bitmapCache->cells[id].number;
248 }
249 else if (index > bitmapCache->cells[id].number)
250 {
251 WLog_ERR(TAG, "put invalid bitmap index %" PRIu32 " in cell id: %" PRIu32 "", index, id);
252 return FALSE;
253 }
254
255 bitmapCache->cells[id].entries[index] = bitmap;
256 return TRUE;
257 }
258
bitmap_cache_register_callbacks(rdpUpdate * update)259 void bitmap_cache_register_callbacks(rdpUpdate* update)
260 {
261 rdpCache* cache = update->context->cache;
262 cache->bitmap->MemBlt = update->primary->MemBlt;
263 cache->bitmap->Mem3Blt = update->primary->Mem3Blt;
264 update->primary->MemBlt = update_gdi_memblt;
265 update->primary->Mem3Blt = update_gdi_mem3blt;
266 update->secondary->CacheBitmap = update_gdi_cache_bitmap;
267 update->secondary->CacheBitmapV2 = update_gdi_cache_bitmap_v2;
268 update->secondary->CacheBitmapV3 = update_gdi_cache_bitmap_v3;
269 update->BitmapUpdate = gdi_bitmap_update;
270 }
271
bitmap_cache_new(rdpSettings * settings)272 rdpBitmapCache* bitmap_cache_new(rdpSettings* settings)
273 {
274 UINT32 i;
275 rdpBitmapCache* bitmapCache;
276 bitmapCache = (rdpBitmapCache*)calloc(1, sizeof(rdpBitmapCache));
277
278 if (!bitmapCache)
279 return NULL;
280
281 bitmapCache->settings = settings;
282 bitmapCache->update = ((freerdp*)settings->instance)->update;
283 bitmapCache->context = bitmapCache->update->context;
284 bitmapCache->cells =
285 (BITMAP_V2_CELL*)calloc(settings->BitmapCacheV2NumCells, sizeof(BITMAP_V2_CELL));
286
287 if (!bitmapCache->cells)
288 goto fail;
289 bitmapCache->maxCells = settings->BitmapCacheV2NumCells;
290
291 for (i = 0; i < bitmapCache->maxCells; i++)
292 {
293 BITMAP_V2_CELL* cell = &bitmapCache->cells[i];
294 UINT32 nr = settings->BitmapCacheV2CellInfo[i].numEntries;
295 /* allocate an extra entry for BITMAP_CACHE_WAITING_LIST_INDEX */
296 cell->entries = (rdpBitmap**)calloc((nr + 1), sizeof(rdpBitmap*));
297
298 if (!cell->entries)
299 goto fail;
300 cell->number = nr;
301 }
302
303 return bitmapCache;
304 fail:
305
306 bitmap_cache_free(bitmapCache);
307 return NULL;
308 }
309
bitmap_cache_free(rdpBitmapCache * bitmapCache)310 void bitmap_cache_free(rdpBitmapCache* bitmapCache)
311 {
312 if (bitmapCache)
313 {
314 UINT32 i;
315 for (i = 0; i < bitmapCache->maxCells; i++)
316 {
317 UINT32 j;
318 BITMAP_V2_CELL* cell = &bitmapCache->cells[i];
319 if (!cell->entries)
320 continue;
321 for (j = 0; j < cell->number + 1; j++)
322 {
323 rdpBitmap* bitmap = cell->entries[j];
324 Bitmap_Free(bitmapCache->context, bitmap);
325 }
326
327 free(bitmapCache->cells[i].entries);
328 }
329
330 free(bitmapCache->cells);
331 free(bitmapCache);
332 }
333 }
334
free_bitmap_data(BITMAP_DATA * data,size_t count)335 static void free_bitmap_data(BITMAP_DATA* data, size_t count)
336 {
337 size_t x;
338
339 if (!data)
340 return;
341
342 for (x = 0; x < count; x++)
343 free(data[x].bitmapDataStream);
344
345 free(data);
346 }
347
copy_bitmap_data(const BITMAP_DATA * data,size_t count)348 static BITMAP_DATA* copy_bitmap_data(const BITMAP_DATA* data, size_t count)
349 {
350 size_t x;
351 BITMAP_DATA* dst = (BITMAP_DATA*)calloc(count, sizeof(BITMAP_DATA));
352
353 if (!dst)
354 goto fail;
355
356 for (x = 0; x < count; x++)
357 {
358 dst[x] = data[x];
359
360 if (data[x].bitmapLength > 0)
361 {
362 dst[x].bitmapDataStream = malloc(data[x].bitmapLength);
363
364 if (!dst[x].bitmapDataStream)
365 goto fail;
366
367 memcpy(dst[x].bitmapDataStream, data[x].bitmapDataStream, data[x].bitmapLength);
368 }
369 }
370
371 return dst;
372 fail:
373 free_bitmap_data(dst, count);
374 return NULL;
375 }
376
free_bitmap_update(rdpContext * context,BITMAP_UPDATE * pointer)377 void free_bitmap_update(rdpContext* context, BITMAP_UPDATE* pointer)
378 {
379 if (!pointer)
380 return;
381
382 free_bitmap_data(pointer->rectangles, pointer->number);
383 free(pointer);
384 }
385
copy_bitmap_update(rdpContext * context,const BITMAP_UPDATE * pointer)386 BITMAP_UPDATE* copy_bitmap_update(rdpContext* context, const BITMAP_UPDATE* pointer)
387 {
388 BITMAP_UPDATE* dst = calloc(1, sizeof(BITMAP_UPDATE));
389
390 if (!dst || !pointer)
391 goto fail;
392
393 *dst = *pointer;
394 dst->rectangles = copy_bitmap_data(pointer->rectangles, pointer->number);
395
396 if (!dst->rectangles)
397 goto fail;
398
399 return dst;
400 fail:
401 free_bitmap_update(context, dst);
402 return NULL;
403 }
404
copy_cache_bitmap_order(rdpContext * context,const CACHE_BITMAP_ORDER * order)405 CACHE_BITMAP_ORDER* copy_cache_bitmap_order(rdpContext* context, const CACHE_BITMAP_ORDER* order)
406 {
407 CACHE_BITMAP_ORDER* dst = calloc(1, sizeof(CACHE_BITMAP_ORDER));
408
409 if (!dst || !order)
410 goto fail;
411
412 *dst = *order;
413
414 if (order->bitmapLength > 0)
415 {
416 dst->bitmapDataStream = malloc(order->bitmapLength);
417
418 if (!dst->bitmapDataStream)
419 goto fail;
420
421 memcpy(dst->bitmapDataStream, order->bitmapDataStream, order->bitmapLength);
422 }
423
424 return dst;
425 fail:
426 free_cache_bitmap_order(context, dst);
427 return NULL;
428 }
429
free_cache_bitmap_order(rdpContext * context,CACHE_BITMAP_ORDER * order)430 void free_cache_bitmap_order(rdpContext* context, CACHE_BITMAP_ORDER* order)
431 {
432 if (order)
433 free(order->bitmapDataStream);
434
435 free(order);
436 }
437
copy_cache_bitmap_v2_order(rdpContext * context,const CACHE_BITMAP_V2_ORDER * order)438 CACHE_BITMAP_V2_ORDER* copy_cache_bitmap_v2_order(rdpContext* context,
439 const CACHE_BITMAP_V2_ORDER* order)
440 {
441 CACHE_BITMAP_V2_ORDER* dst = calloc(1, sizeof(CACHE_BITMAP_V2_ORDER));
442
443 if (!dst || !order)
444 goto fail;
445
446 *dst = *order;
447
448 if (order->bitmapLength > 0)
449 {
450 dst->bitmapDataStream = malloc(order->bitmapLength);
451
452 if (!dst->bitmapDataStream)
453 goto fail;
454
455 memcpy(dst->bitmapDataStream, order->bitmapDataStream, order->bitmapLength);
456 }
457
458 return dst;
459 fail:
460 free_cache_bitmap_v2_order(context, dst);
461 return NULL;
462 }
463
free_cache_bitmap_v2_order(rdpContext * context,CACHE_BITMAP_V2_ORDER * order)464 void free_cache_bitmap_v2_order(rdpContext* context, CACHE_BITMAP_V2_ORDER* order)
465 {
466 if (order)
467 free(order->bitmapDataStream);
468
469 free(order);
470 }
471
copy_cache_bitmap_v3_order(rdpContext * context,const CACHE_BITMAP_V3_ORDER * order)472 CACHE_BITMAP_V3_ORDER* copy_cache_bitmap_v3_order(rdpContext* context,
473 const CACHE_BITMAP_V3_ORDER* order)
474 {
475 CACHE_BITMAP_V3_ORDER* dst = calloc(1, sizeof(CACHE_BITMAP_V3_ORDER));
476
477 if (!dst || !order)
478 goto fail;
479
480 *dst = *order;
481
482 if (order->bitmapData.length > 0)
483 {
484 dst->bitmapData.data = malloc(order->bitmapData.length);
485
486 if (!dst->bitmapData.data)
487 goto fail;
488
489 memcpy(dst->bitmapData.data, order->bitmapData.data, order->bitmapData.length);
490 }
491
492 return dst;
493 fail:
494 free_cache_bitmap_v3_order(context, dst);
495 return NULL;
496 }
497
free_cache_bitmap_v3_order(rdpContext * context,CACHE_BITMAP_V3_ORDER * order)498 void free_cache_bitmap_v3_order(rdpContext* context, CACHE_BITMAP_V3_ORDER* order)
499 {
500 if (order)
501 free(order->bitmapData.data);
502
503 free(order);
504 }
505