FreeRDP
Loading...
Searching...
No Matches
cache/brush.c
1
20#include <freerdp/config.h>
21
22#include <stdio.h>
23#include <winpr/crt.h>
24#include <winpr/assert.h>
25
26#include <freerdp/log.h>
27#include <freerdp/update.h>
28#include <freerdp/freerdp.h>
29#include <winpr/stream.h>
30
31#include "brush.h"
32#include "cache.h"
33
34#define TAG FREERDP_TAG("cache.brush")
35
36typedef struct
37{
38 UINT32 bpp;
39 void* entry;
40} BRUSH_ENTRY;
41
42struct rdp_brush_cache
43{
44 pPatBlt PatBlt; /* 0 */
45 pCacheBrush CacheBrush; /* 1 */
46 pPolygonSC PolygonSC; /* 2 */
47 pPolygonCB PolygonCB; /* 3 */
48 UINT32 paddingA[16 - 4]; /* 4 */
49
50 UINT32 maxEntries; /* 16 */
51 UINT32 maxMonoEntries; /* 17 */
52 BRUSH_ENTRY* entries; /* 18 */
53 BRUSH_ENTRY* monoEntries; /* 19 */
54 UINT32 paddingB[32 - 20]; /* 20 */
55
56 rdpContext* context;
57};
58
59static BOOL update_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
60{
61 BOOL ret = TRUE;
62
63 WINPR_ASSERT(context);
64 WINPR_ASSERT(patblt);
65
66 const rdpCache* cache = context->cache;
67 WINPR_ASSERT(cache);
68
69 rdpBrush* brush = &patblt->brush;
70 WINPR_ASSERT(brush->style <= UINT8_MAX);
71 const BYTE style = (BYTE)brush->style;
72
73 if (brush->style & CACHED_BRUSH)
74 {
75 brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
76 brush->style = 0x03;
77 }
78
79 WINPR_ASSERT(cache->brush);
80 IFCALLRET(cache->brush->PatBlt, ret, context, patblt);
81 brush->style = style;
82 return ret;
83}
84
85static BOOL update_gdi_polygon_sc(rdpContext* context, const POLYGON_SC_ORDER* polygon_sc)
86{
87 rdpCache* cache = NULL;
88 WINPR_ASSERT(context);
89 cache = context->cache;
90 WINPR_ASSERT(cache);
91 WINPR_ASSERT(cache->brush);
92 return IFCALLRESULT(TRUE, cache->brush->PolygonSC, context, polygon_sc);
93}
94
95static BOOL update_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
96{
97 BOOL ret = TRUE;
98
99 WINPR_ASSERT(context);
100 WINPR_ASSERT(polygon_cb);
101
102 rdpCache* cache = context->cache;
103 WINPR_ASSERT(cache);
104
105 rdpBrush* brush = &polygon_cb->brush;
106 WINPR_ASSERT(brush->style <= UINT8_MAX);
107 const BYTE style = (UINT8)brush->style;
108
109 if (brush->style & CACHED_BRUSH)
110 {
111 brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
112 brush->style = 0x03;
113 }
114
115 WINPR_ASSERT(cache->brush);
116 IFCALLRET(cache->brush->PolygonCB, ret, context, polygon_cb);
117 brush->style = style;
118 return ret;
119}
120
121static BOOL update_gdi_cache_brush(rdpContext* context, const CACHE_BRUSH_ORDER* cacheBrush)
122{
123 UINT32 length = 0;
124 void* data = NULL;
125 rdpCache* cache = NULL;
126
127 WINPR_ASSERT(context);
128 WINPR_ASSERT(cacheBrush);
129
130 cache = context->cache;
131 WINPR_ASSERT(cache);
132
133 length = cacheBrush->bpp * 64 / 8;
134 data = malloc(length);
135
136 if (!data)
137 return FALSE;
138
139 CopyMemory(data, cacheBrush->data, length);
140 brush_cache_put(cache->brush, cacheBrush->index, data, cacheBrush->bpp);
141 return TRUE;
142}
143
144void* brush_cache_get(rdpBrushCache* brushCache, UINT32 index, UINT32* bpp)
145{
146 void* entry = NULL;
147
148 if (!brushCache)
149 return NULL;
150
151 if (!bpp)
152 return NULL;
153
154 if (*bpp == 1)
155 {
156 if (index >= brushCache->maxMonoEntries)
157 {
158 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", *bpp, index);
159 return NULL;
160 }
161
162 *bpp = brushCache->monoEntries[index].bpp;
163 entry = brushCache->monoEntries[index].entry;
164 }
165 else
166 {
167 if (index >= brushCache->maxEntries)
168 {
169 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", *bpp, index);
170 return NULL;
171 }
172
173 *bpp = brushCache->entries[index].bpp;
174 entry = brushCache->entries[index].entry;
175 }
176
177 if (entry == NULL)
178 {
179 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) at index: 0x%08" PRIX32 "", *bpp, index);
180 return NULL;
181 }
182
183 return entry;
184}
185
186void brush_cache_put(rdpBrushCache* brushCache, UINT32 index, void* entry, UINT32 bpp)
187{
188 WINPR_ASSERT(brushCache);
189
190 if (bpp == 1)
191 {
192 if (index >= brushCache->maxMonoEntries)
193 {
194 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", bpp, index);
195 free(entry);
196 return;
197 }
198
199 WINPR_ASSERT(brushCache->monoEntries);
200 free(brushCache->monoEntries[index].entry);
201 brushCache->monoEntries[index].bpp = bpp;
202 brushCache->monoEntries[index].entry = entry;
203 }
204 else
205 {
206 if (index >= brushCache->maxEntries)
207 {
208 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", bpp, index);
209 free(entry);
210 return;
211 }
212
213 WINPR_ASSERT(brushCache->entries);
214 free(brushCache->entries[index].entry);
215 brushCache->entries[index].bpp = bpp;
216 brushCache->entries[index].entry = entry;
217 }
218}
219
220void brush_cache_register_callbacks(rdpUpdate* update)
221{
222 WINPR_ASSERT(update);
223 WINPR_ASSERT(update->context);
224 WINPR_ASSERT(update->primary);
225 WINPR_ASSERT(update->secondary);
226
227 if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
228 {
229 rdpCache* cache = update->context->cache;
230 WINPR_ASSERT(cache);
231 WINPR_ASSERT(cache->brush);
232
233 cache->brush->PatBlt = update->primary->PatBlt;
234 cache->brush->PolygonSC = update->primary->PolygonSC;
235 cache->brush->PolygonCB = update->primary->PolygonCB;
236 update->primary->PatBlt = update_gdi_patblt;
237 update->primary->PolygonSC = update_gdi_polygon_sc;
238 update->primary->PolygonCB = update_gdi_polygon_cb;
239 update->secondary->CacheBrush = update_gdi_cache_brush;
240 }
241}
242
243rdpBrushCache* brush_cache_new(rdpContext* context)
244{
245 rdpBrushCache* brushCache = NULL;
246
247 WINPR_ASSERT(context);
248
249 brushCache = (rdpBrushCache*)calloc(1, sizeof(rdpBrushCache));
250
251 if (!brushCache)
252 return NULL;
253
254 brushCache->context = context;
255 brushCache->maxEntries = 64;
256 brushCache->maxMonoEntries = 64;
257 brushCache->entries = (BRUSH_ENTRY*)calloc(brushCache->maxEntries, sizeof(BRUSH_ENTRY));
258
259 if (!brushCache->entries)
260 goto fail;
261
262 brushCache->monoEntries = (BRUSH_ENTRY*)calloc(brushCache->maxMonoEntries, sizeof(BRUSH_ENTRY));
263
264 if (!brushCache->monoEntries)
265 goto fail;
266
267 return brushCache;
268fail:
269 WINPR_PRAGMA_DIAG_PUSH
270 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
271 brush_cache_free(brushCache);
272 WINPR_PRAGMA_DIAG_POP
273 return NULL;
274}
275
276void brush_cache_free(rdpBrushCache* brushCache)
277{
278 if (brushCache)
279 {
280 if (brushCache->entries)
281 {
282 for (size_t i = 0; i < brushCache->maxEntries; i++)
283 free(brushCache->entries[i].entry);
284
285 free(brushCache->entries);
286 }
287
288 if (brushCache->monoEntries)
289 {
290 for (size_t i = 0; i < brushCache->maxMonoEntries; i++)
291 free(brushCache->monoEntries[i].entry);
292
293 free(brushCache->monoEntries);
294 }
295
296 free(brushCache);
297 }
298}
299
300void free_cache_brush_order(rdpContext* context, CACHE_BRUSH_ORDER* order)
301{
302 WINPR_UNUSED(context);
303 free(order);
304}
305
306CACHE_BRUSH_ORDER* copy_cache_brush_order(rdpContext* context, const CACHE_BRUSH_ORDER* order)
307{
308 CACHE_BRUSH_ORDER* dst = NULL;
309
310 WINPR_ASSERT(context);
311
312 dst = calloc(1, sizeof(CACHE_BRUSH_ORDER));
313
314 if (!dst || !order)
315 goto fail;
316
317 *dst = *order;
318 return dst;
319fail:
320 free_cache_brush_order(context, dst);
321 return NULL;
322}
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.