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