1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25
26 #include <winpr/crt.h>
27
28 #include <winpr/stream.h>
29
30 #include <freerdp/log.h>
31 #include <freerdp/cache/pointer.h>
32
33 #include "pointer.h"
34
35 #define TAG FREERDP_TAG("cache.pointer")
36
37 static BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer);
38 static const rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index);
39
pointer_free(rdpContext * context,rdpPointer * pointer)40 static void pointer_free(rdpContext* context, rdpPointer* pointer)
41 {
42 if (pointer)
43 {
44 IFCALL(pointer->Free, context, pointer);
45
46 if (pointer->xorMaskData)
47 {
48 free(pointer->xorMaskData);
49 pointer->xorMaskData = NULL;
50 }
51
52 if (pointer->andMaskData)
53 {
54 free(pointer->andMaskData);
55 pointer->andMaskData = NULL;
56 }
57
58 free(pointer);
59 }
60 }
61
update_pointer_position(rdpContext * context,const POINTER_POSITION_UPDATE * pointer_position)62 static BOOL update_pointer_position(rdpContext* context,
63 const POINTER_POSITION_UPDATE* pointer_position)
64 {
65 rdpPointer* pointer;
66
67 if (!context || !context->graphics || !context->graphics->Pointer_Prototype ||
68 !pointer_position)
69 return FALSE;
70
71 pointer = context->graphics->Pointer_Prototype;
72 return IFCALLRESULT(TRUE, pointer->SetPosition, context, pointer_position->xPos,
73 pointer_position->yPos);
74 }
75
update_pointer_system(rdpContext * context,const POINTER_SYSTEM_UPDATE * pointer_system)76 static BOOL update_pointer_system(rdpContext* context, const POINTER_SYSTEM_UPDATE* pointer_system)
77 {
78 rdpPointer* pointer;
79
80 if (!context || !context->graphics || !context->graphics->Pointer_Prototype || !pointer_system)
81 return FALSE;
82
83 pointer = context->graphics->Pointer_Prototype;
84
85 switch (pointer_system->type)
86 {
87 case SYSPTR_NULL:
88 return IFCALLRESULT(TRUE, pointer->SetNull, context);
89
90 case SYSPTR_DEFAULT:
91 return IFCALLRESULT(TRUE, pointer->SetDefault, context);
92
93 default:
94 WLog_ERR(TAG, "Unknown system pointer type (0x%08" PRIX32 ")", pointer_system->type);
95 }
96 return TRUE;
97 }
98
upate_pointer_copy_andxor(rdpPointer * pointer,const BYTE * andMaskData,size_t lengthAndMask,const BYTE * xorMaskData,size_t lengthXorMask)99 static BOOL upate_pointer_copy_andxor(rdpPointer* pointer, const BYTE* andMaskData,
100 size_t lengthAndMask, const BYTE* xorMaskData,
101 size_t lengthXorMask)
102 {
103 pointer->lengthAndMask = 0;
104 pointer->lengthXorMask = 0;
105
106 if (lengthAndMask && andMaskData)
107 {
108 pointer->lengthAndMask = lengthAndMask;
109 pointer->andMaskData = (BYTE*)malloc(lengthAndMask);
110
111 if (!pointer->andMaskData)
112 return FALSE;
113
114 CopyMemory(pointer->andMaskData, andMaskData, lengthAndMask);
115 }
116
117 if (lengthXorMask && xorMaskData)
118 {
119 pointer->lengthXorMask = lengthXorMask;
120 pointer->xorMaskData = (BYTE*)malloc(lengthXorMask);
121
122 if (!pointer->xorMaskData)
123 return FALSE;
124
125 CopyMemory(pointer->xorMaskData, xorMaskData, lengthXorMask);
126 }
127
128 return TRUE;
129 }
130
update_pointer_color(rdpContext * context,const POINTER_COLOR_UPDATE * pointer_color)131 static BOOL update_pointer_color(rdpContext* context, const POINTER_COLOR_UPDATE* pointer_color)
132 {
133 rdpPointer* pointer;
134 rdpCache* cache = context->cache;
135 pointer = Pointer_Alloc(context);
136
137 if (pointer != NULL)
138 {
139 pointer->xorBpp = 24;
140 pointer->xPos = pointer_color->xPos;
141 pointer->yPos = pointer_color->yPos;
142 pointer->width = pointer_color->width;
143 pointer->height = pointer_color->height;
144
145 if (!upate_pointer_copy_andxor(pointer, pointer_color->andMaskData,
146 pointer_color->lengthAndMask, pointer_color->xorMaskData,
147 pointer_color->lengthXorMask))
148 goto out_fail;
149
150 if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
151 goto out_fail;
152
153 if (!pointer_cache_put(cache->pointer, pointer_color->cacheIndex, pointer))
154 goto out_fail;
155
156 return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
157 }
158
159 return FALSE;
160 out_fail:
161 pointer_free(context, pointer);
162 return FALSE;
163 }
164
update_pointer_large(rdpContext * context,const POINTER_LARGE_UPDATE * pointer_large)165 static BOOL update_pointer_large(rdpContext* context, const POINTER_LARGE_UPDATE* pointer_large)
166 {
167 rdpPointer* pointer = Pointer_Alloc(context);
168 rdpCache* cache = context->cache;
169
170 if (pointer != NULL)
171 {
172 pointer->xorBpp = pointer_large->xorBpp;
173 pointer->xPos = pointer_large->hotSpotX;
174 pointer->yPos = pointer_large->hotSpotY;
175 pointer->width = pointer_large->width;
176 pointer->height = pointer_large->height;
177
178 if (!upate_pointer_copy_andxor(pointer, pointer_large->andMaskData,
179 pointer_large->lengthAndMask, pointer_large->xorMaskData,
180 pointer_large->lengthXorMask))
181 goto out_fail;
182
183 if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
184 goto out_fail;
185
186 if (!pointer_cache_put(cache->pointer, pointer_large->cacheIndex, pointer))
187 goto out_fail;
188
189 return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
190 }
191
192 return FALSE;
193 out_fail:
194 pointer_free(context, pointer);
195 return FALSE;
196 }
197
update_pointer_new(rdpContext * context,const POINTER_NEW_UPDATE * pointer_new)198 static BOOL update_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
199 {
200 rdpPointer* pointer;
201 rdpCache* cache;
202
203 if (!context || !pointer_new)
204 return FALSE;
205
206 cache = context->cache;
207 pointer = Pointer_Alloc(context);
208
209 if (!pointer)
210 return FALSE;
211
212 pointer->xorBpp = pointer_new->xorBpp;
213 pointer->xPos = pointer_new->colorPtrAttr.xPos;
214 pointer->yPos = pointer_new->colorPtrAttr.yPos;
215 pointer->width = pointer_new->colorPtrAttr.width;
216 pointer->height = pointer_new->colorPtrAttr.height;
217 if (!upate_pointer_copy_andxor(
218 pointer, pointer_new->colorPtrAttr.andMaskData, pointer_new->colorPtrAttr.lengthAndMask,
219 pointer_new->colorPtrAttr.xorMaskData, pointer_new->colorPtrAttr.lengthXorMask))
220 goto out_fail;
221
222 if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
223 goto out_fail;
224
225 if (!pointer_cache_put(cache->pointer, pointer_new->colorPtrAttr.cacheIndex, pointer))
226 goto out_fail;
227
228 return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
229 out_fail:
230 pointer_free(context, pointer);
231 return FALSE;
232 }
233
update_pointer_cached(rdpContext * context,const POINTER_CACHED_UPDATE * pointer_cached)234 static BOOL update_pointer_cached(rdpContext* context, const POINTER_CACHED_UPDATE* pointer_cached)
235 {
236 const rdpPointer* pointer;
237 rdpCache* cache = context->cache;
238 pointer = pointer_cache_get(cache->pointer, pointer_cached->cacheIndex);
239
240 if (pointer != NULL)
241 return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
242
243 return FALSE;
244 }
245
pointer_cache_get(rdpPointerCache * pointer_cache,UINT32 index)246 const rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index)
247 {
248 const rdpPointer* pointer;
249
250 if (index >= pointer_cache->cacheSize)
251 {
252 WLog_ERR(TAG, "invalid pointer index:%" PRIu32 "", index);
253 return NULL;
254 }
255
256 pointer = pointer_cache->entries[index];
257 return pointer;
258 }
259
pointer_cache_put(rdpPointerCache * pointer_cache,UINT32 index,rdpPointer * pointer)260 BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer)
261 {
262 rdpPointer* prevPointer;
263
264 if (index >= pointer_cache->cacheSize)
265 {
266 WLog_ERR(TAG, "invalid pointer index:%" PRIu32 "", index);
267 return FALSE;
268 }
269
270 prevPointer = pointer_cache->entries[index];
271 pointer_free(pointer_cache->update->context, prevPointer);
272 pointer_cache->entries[index] = pointer;
273 return TRUE;
274 }
275
pointer_cache_register_callbacks(rdpUpdate * update)276 void pointer_cache_register_callbacks(rdpUpdate* update)
277 {
278 rdpPointerUpdate* pointer = update->pointer;
279 pointer->PointerPosition = update_pointer_position;
280 pointer->PointerSystem = update_pointer_system;
281 pointer->PointerColor = update_pointer_color;
282 pointer->PointerLarge = update_pointer_large;
283 pointer->PointerNew = update_pointer_new;
284 pointer->PointerCached = update_pointer_cached;
285 }
286
pointer_cache_new(rdpSettings * settings)287 rdpPointerCache* pointer_cache_new(rdpSettings* settings)
288 {
289 rdpPointerCache* pointer_cache;
290 pointer_cache = (rdpPointerCache*)calloc(1, sizeof(rdpPointerCache));
291
292 if (!pointer_cache)
293 return NULL;
294
295 pointer_cache->settings = settings;
296 pointer_cache->cacheSize = settings->PointerCacheSize;
297 pointer_cache->update = ((freerdp*)settings->instance)->update;
298 pointer_cache->entries = (rdpPointer**)calloc(pointer_cache->cacheSize, sizeof(rdpPointer*));
299
300 if (!pointer_cache->entries)
301 {
302 free(pointer_cache);
303 return NULL;
304 }
305
306 return pointer_cache;
307 }
308
pointer_cache_free(rdpPointerCache * pointer_cache)309 void pointer_cache_free(rdpPointerCache* pointer_cache)
310 {
311 if (pointer_cache != NULL)
312 {
313 UINT32 i;
314 rdpPointer* pointer;
315
316 for (i = 0; i < pointer_cache->cacheSize; i++)
317 {
318 pointer = pointer_cache->entries[i];
319 pointer_free(pointer_cache->update->context, pointer);
320 }
321
322 free(pointer_cache->entries);
323 free(pointer_cache);
324 }
325 }
326
copy_pointer_color_update(rdpContext * context,const POINTER_COLOR_UPDATE * src)327 POINTER_COLOR_UPDATE* copy_pointer_color_update(rdpContext* context,
328 const POINTER_COLOR_UPDATE* src)
329 {
330 POINTER_COLOR_UPDATE* dst = calloc(1, sizeof(POINTER_COLOR_UPDATE));
331
332 if (!dst || !src)
333 goto fail;
334
335 *dst = *src;
336
337 if (src->lengthAndMask > 0)
338 {
339 dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
340
341 if (!dst->andMaskData)
342 goto fail;
343
344 memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
345 }
346
347 if (src->lengthXorMask > 0)
348 {
349 dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
350
351 if (!dst->xorMaskData)
352 goto fail;
353
354 memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
355 }
356
357 return dst;
358 fail:
359 free_pointer_color_update(context, dst);
360 return NULL;
361 }
362
free_pointer_color_update(rdpContext * context,POINTER_COLOR_UPDATE * pointer)363 void free_pointer_color_update(rdpContext* context, POINTER_COLOR_UPDATE* pointer)
364 {
365 if (!pointer)
366 return;
367
368 free(pointer->xorMaskData);
369 free(pointer->andMaskData);
370 free(pointer);
371 }
372
copy_pointer_large_update(rdpContext * context,const POINTER_LARGE_UPDATE * src)373 POINTER_LARGE_UPDATE* copy_pointer_large_update(rdpContext* context,
374 const POINTER_LARGE_UPDATE* src)
375 {
376 POINTER_LARGE_UPDATE* dst = calloc(1, sizeof(POINTER_LARGE_UPDATE));
377
378 if (!dst || !src)
379 goto fail;
380
381 *dst = *src;
382
383 if (src->lengthAndMask > 0)
384 {
385 dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
386
387 if (!dst->andMaskData)
388 goto fail;
389
390 memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
391 }
392
393 if (src->lengthXorMask > 0)
394 {
395 dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
396
397 if (!dst->xorMaskData)
398 goto fail;
399
400 memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
401 }
402
403 return dst;
404 fail:
405 free_pointer_large_update(context, dst);
406 return NULL;
407 }
408
free_pointer_large_update(rdpContext * context,POINTER_LARGE_UPDATE * pointer)409 void free_pointer_large_update(rdpContext* context, POINTER_LARGE_UPDATE* pointer)
410 {
411 WINPR_UNUSED(context);
412 if (!pointer)
413 return;
414
415 free(pointer->xorMaskData);
416 free(pointer->andMaskData);
417 free(pointer);
418 }
419
copy_pointer_new_update(rdpContext * context,const POINTER_NEW_UPDATE * src)420 POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context, const POINTER_NEW_UPDATE* src)
421 {
422 POINTER_NEW_UPDATE* dst = calloc(1, sizeof(POINTER_NEW_UPDATE));
423
424 if (!dst || !src)
425 goto fail;
426
427 *dst = *src;
428
429 if (src->colorPtrAttr.lengthAndMask > 0)
430 {
431 dst->colorPtrAttr.andMaskData = calloc(src->colorPtrAttr.lengthAndMask, sizeof(BYTE));
432
433 if (!dst->colorPtrAttr.andMaskData)
434 goto fail;
435
436 memcpy(dst->colorPtrAttr.andMaskData, src->colorPtrAttr.andMaskData,
437 src->colorPtrAttr.lengthAndMask);
438 }
439
440 if (src->colorPtrAttr.lengthXorMask > 0)
441 {
442 dst->colorPtrAttr.xorMaskData = calloc(src->colorPtrAttr.lengthXorMask, sizeof(BYTE));
443
444 if (!dst->colorPtrAttr.xorMaskData)
445 goto fail;
446
447 memcpy(dst->colorPtrAttr.xorMaskData, src->colorPtrAttr.xorMaskData,
448 src->colorPtrAttr.lengthXorMask);
449 }
450
451 return dst;
452 fail:
453 free_pointer_new_update(context, dst);
454 return NULL;
455 }
456
free_pointer_new_update(rdpContext * context,POINTER_NEW_UPDATE * pointer)457 void free_pointer_new_update(rdpContext* context, POINTER_NEW_UPDATE* pointer)
458 {
459 if (!pointer)
460 return;
461
462 free(pointer->colorPtrAttr.xorMaskData);
463 free(pointer->colorPtrAttr.andMaskData);
464 free(pointer);
465 }
466
copy_pointer_cached_update(rdpContext * context,const POINTER_CACHED_UPDATE * pointer)467 POINTER_CACHED_UPDATE* copy_pointer_cached_update(rdpContext* context,
468 const POINTER_CACHED_UPDATE* pointer)
469 {
470 POINTER_CACHED_UPDATE* dst = calloc(1, sizeof(POINTER_CACHED_UPDATE));
471
472 if (!dst)
473 goto fail;
474
475 *dst = *pointer;
476 return dst;
477 fail:
478 free_pointer_cached_update(context, dst);
479 return NULL;
480 }
481
free_pointer_cached_update(rdpContext * context,POINTER_CACHED_UPDATE * pointer)482 void free_pointer_cached_update(rdpContext* context, POINTER_CACHED_UPDATE* pointer)
483 {
484 free(pointer);
485 }
486
free_pointer_position_update(rdpContext * context,POINTER_POSITION_UPDATE * pointer)487 void free_pointer_position_update(rdpContext* context, POINTER_POSITION_UPDATE* pointer)
488 {
489 free(pointer);
490 }
491
copy_pointer_position_update(rdpContext * context,const POINTER_POSITION_UPDATE * pointer)492 POINTER_POSITION_UPDATE* copy_pointer_position_update(rdpContext* context,
493 const POINTER_POSITION_UPDATE* pointer)
494 {
495 POINTER_POSITION_UPDATE* dst = calloc(1, sizeof(POINTER_POSITION_UPDATE));
496
497 if (!dst || !pointer)
498 goto fail;
499
500 *dst = *pointer;
501 return dst;
502 fail:
503 free_pointer_position_update(context, dst);
504 return NULL;
505 }
506
free_pointer_system_update(rdpContext * context,POINTER_SYSTEM_UPDATE * pointer)507 void free_pointer_system_update(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer)
508 {
509 free(pointer);
510 }
511
copy_pointer_system_update(rdpContext * context,const POINTER_SYSTEM_UPDATE * pointer)512 POINTER_SYSTEM_UPDATE* copy_pointer_system_update(rdpContext* context,
513 const POINTER_SYSTEM_UPDATE* pointer)
514 {
515 POINTER_SYSTEM_UPDATE* dst = calloc(1, sizeof(POINTER_SYSTEM_UPDATE));
516
517 if (!dst || !pointer)
518 goto fail;
519
520 *dst = *pointer;
521 return dst;
522 fail:
523 free_pointer_system_update(context, dst);
524 return NULL;
525 }
526