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 BYTE* data = brush->data;
73
74 if (brush->style & CACHED_BRUSH)
75 {
76 brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
77 brush->style = 0x03;
78 }
79
80 WINPR_ASSERT(cache->brush);
81 IFCALLRET(cache->brush->PatBlt, ret, context, patblt);
82 brush->style = style;
83 brush->data = data;
84 return ret;
85}
86
87static BOOL update_gdi_polygon_sc(rdpContext* context, const POLYGON_SC_ORDER* polygon_sc)
88{
89 rdpCache* cache = nullptr;
90 WINPR_ASSERT(context);
91 cache = context->cache;
92 WINPR_ASSERT(cache);
93 WINPR_ASSERT(cache->brush);
94 return IFCALLRESULT(TRUE, cache->brush->PolygonSC, context, polygon_sc);
95}
96
97static BOOL update_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
98{
99 BOOL ret = TRUE;
100
101 WINPR_ASSERT(context);
102 WINPR_ASSERT(polygon_cb);
103
104 rdpCache* cache = context->cache;
105 WINPR_ASSERT(cache);
106
107 rdpBrush* brush = &polygon_cb->brush;
108 WINPR_ASSERT(brush->style <= UINT8_MAX);
109 const BYTE style = (UINT8)brush->style;
110 BYTE* data = brush->data;
111
112 if (brush->style & CACHED_BRUSH)
113 {
114 brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
115 brush->style = 0x03;
116 }
117
118 WINPR_ASSERT(cache->brush);
119 IFCALLRET(cache->brush->PolygonCB, ret, context, polygon_cb);
120 brush->style = style;
121 brush->data = data;
122 return ret;
123}
124
125static BOOL update_gdi_cache_brush(rdpContext* context, const CACHE_BRUSH_ORDER* cacheBrush)
126{
127 UINT32 length = 0;
128 void* data = nullptr;
129 rdpCache* cache = nullptr;
130
131 WINPR_ASSERT(context);
132 WINPR_ASSERT(cacheBrush);
133
134 cache = context->cache;
135 WINPR_ASSERT(cache);
136
137 length = cacheBrush->bpp * 64 / 8;
138 data = malloc(length);
139
140 if (!data)
141 return FALSE;
142
143 CopyMemory(data, cacheBrush->data, length);
144 brush_cache_put(cache->brush, cacheBrush->index, data, cacheBrush->bpp);
145 return TRUE;
146}
147
148void* brush_cache_get(rdpBrushCache* brushCache, UINT32 index, UINT32* bpp)
149{
150 void* entry = nullptr;
151
152 if (!brushCache)
153 return nullptr;
154
155 if (!bpp)
156 return nullptr;
157
158 if (*bpp == 1)
159 {
160 if (index >= brushCache->maxMonoEntries)
161 {
162 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", *bpp, index);
163 return nullptr;
164 }
165
166 *bpp = brushCache->monoEntries[index].bpp;
167 entry = brushCache->monoEntries[index].entry;
168 }
169 else
170 {
171 if (index >= brushCache->maxEntries)
172 {
173 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", *bpp, index);
174 return nullptr;
175 }
176
177 *bpp = brushCache->entries[index].bpp;
178 entry = brushCache->entries[index].entry;
179 }
180
181 if (entry == nullptr)
182 {
183 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) at index: 0x%08" PRIX32 "", *bpp, index);
184 return nullptr;
185 }
186
187 return entry;
188}
189
190void brush_cache_put(rdpBrushCache* brushCache, UINT32 index, void* entry, UINT32 bpp)
191{
192 WINPR_ASSERT(brushCache);
193
194 if (bpp == 1)
195 {
196 if (index >= brushCache->maxMonoEntries)
197 {
198 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", bpp, index);
199 free(entry);
200 return;
201 }
202
203 WINPR_ASSERT(brushCache->monoEntries);
204 free(brushCache->monoEntries[index].entry);
205 brushCache->monoEntries[index].bpp = bpp;
206 brushCache->monoEntries[index].entry = entry;
207 }
208 else
209 {
210 if (index >= brushCache->maxEntries)
211 {
212 WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", bpp, index);
213 free(entry);
214 return;
215 }
216
217 WINPR_ASSERT(brushCache->entries);
218 free(brushCache->entries[index].entry);
219 brushCache->entries[index].bpp = bpp;
220 brushCache->entries[index].entry = entry;
221 }
222}
223
224void brush_cache_register_callbacks(rdpUpdate* update)
225{
226 WINPR_ASSERT(update);
227 WINPR_ASSERT(update->context);
228 WINPR_ASSERT(update->primary);
229 WINPR_ASSERT(update->secondary);
230
231 if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
232 {
233 rdpCache* cache = update->context->cache;
234 WINPR_ASSERT(cache);
235 WINPR_ASSERT(cache->brush);
236
237 cache->brush->PatBlt = update->primary->PatBlt;
238 cache->brush->PolygonSC = update->primary->PolygonSC;
239 cache->brush->PolygonCB = update->primary->PolygonCB;
240 update->primary->PatBlt = update_gdi_patblt;
241 update->primary->PolygonSC = update_gdi_polygon_sc;
242 update->primary->PolygonCB = update_gdi_polygon_cb;
243 update->secondary->CacheBrush = update_gdi_cache_brush;
244 }
245}
246
247rdpBrushCache* brush_cache_new(rdpContext* context)
248{
249 rdpBrushCache* brushCache = nullptr;
250
251 WINPR_ASSERT(context);
252
253 brushCache = (rdpBrushCache*)calloc(1, sizeof(rdpBrushCache));
254
255 if (!brushCache)
256 return nullptr;
257
258 brushCache->context = context;
259 brushCache->maxEntries = 64;
260 brushCache->maxMonoEntries = 64;
261 brushCache->entries = (BRUSH_ENTRY*)calloc(brushCache->maxEntries, sizeof(BRUSH_ENTRY));
262
263 if (!brushCache->entries)
264 goto fail;
265
266 brushCache->monoEntries = (BRUSH_ENTRY*)calloc(brushCache->maxMonoEntries, sizeof(BRUSH_ENTRY));
267
268 if (!brushCache->monoEntries)
269 goto fail;
270
271 return brushCache;
272fail:
273 WINPR_PRAGMA_DIAG_PUSH
274 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
275 brush_cache_free(brushCache);
276 WINPR_PRAGMA_DIAG_POP
277 return nullptr;
278}
279
280void brush_cache_free(rdpBrushCache* brushCache)
281{
282 if (brushCache)
283 {
284 if (brushCache->entries)
285 {
286 for (size_t i = 0; i < brushCache->maxEntries; i++)
287 free(brushCache->entries[i].entry);
288
289 free(brushCache->entries);
290 }
291
292 if (brushCache->monoEntries)
293 {
294 for (size_t i = 0; i < brushCache->maxMonoEntries; i++)
295 free(brushCache->monoEntries[i].entry);
296
297 free(brushCache->monoEntries);
298 }
299
300 free(brushCache);
301 }
302}
303
304void free_cache_brush_order(rdpContext* context, CACHE_BRUSH_ORDER* order)
305{
306 WINPR_UNUSED(context);
307 free(order);
308}
309
310CACHE_BRUSH_ORDER* copy_cache_brush_order(rdpContext* context, const CACHE_BRUSH_ORDER* order)
311{
312 CACHE_BRUSH_ORDER* dst = nullptr;
313
314 WINPR_ASSERT(context);
315
316 dst = calloc(1, sizeof(CACHE_BRUSH_ORDER));
317
318 if (!dst || !order)
319 goto fail;
320
321 *dst = *order;
322 return dst;
323fail:
324 free_cache_brush_order(context, dst);
325 return nullptr;
326}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.