FreeRDP
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 
36 typedef struct
37 {
38  UINT32 bpp;
39  void* entry;
40 } BRUSH_ENTRY;
41 
42 struct 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 
59 static 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 
85 static 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 
95 static 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 
121 static 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 
144 void* 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 
186 void 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 
220 void 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 
243 rdpBrushCache* 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;
268 fail:
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 
276 void 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 
300 void free_cache_brush_order(rdpContext* context, CACHE_BRUSH_ORDER* order)
301 {
302  WINPR_UNUSED(context);
303  free(order);
304 }
305 
306 CACHE_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;
319 fail:
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.