FreeRDP
Loading...
Searching...
No Matches
libfreerdp/codec/include/bitmap.h
1
22#include <winpr/assert.h>
23#include <winpr/cast.h>
24#include <winpr/wtypes.h>
25
26/* do not compile the file directly */
27
31WINPR_ATTR_NODISCARD
32static inline BYTE* WRITEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
33 const BYTE* WINPR_RESTRICT pbDestEnd, UINT32 rowDelta,
34 BYTE bitmask, PIXEL fgPel, UINT32 cBits)
35{
36 PIXEL xorPixel = 0;
37 BYTE mask = 0x01;
38
39 if (cBits > 8)
40 {
41 WLog_ERR(TAG, "cBits %" PRIu32 " > 8", cBits);
42 return nullptr;
43 }
44
45 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
46 return nullptr;
47
48 UNROLL(cBits, {
49 PIXEL data = 0;
50 DESTREADPIXEL(xorPixel, pbDest - rowDelta);
51
52 if (bitmask & mask)
53 data = xorPixel ^ fgPel;
54 else
55 data = xorPixel;
56
57 DESTWRITEPIXEL(pbDest, data);
58 mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
59 });
60 return pbDest;
61}
62
67WINPR_ATTR_NODISCARD
68static inline BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
69 const BYTE* WINPR_RESTRICT pbDestEnd, BYTE bitmask,
70 PIXEL fgPel, UINT32 cBits)
71{
72 BYTE mask = 0x01;
73
74 if (cBits > 8)
75 {
76 WLog_ERR(TAG, "cBits %" PRIu32 " > 8", cBits);
77 return nullptr;
78 }
79
80 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
81 return nullptr;
82
83 UNROLL(cBits, {
84 PIXEL data;
85
86 if (bitmask & mask)
87 data = fgPel;
88 else
89 data = BLACK_PIXEL;
90
91 DESTWRITEPIXEL(pbDest, data);
92 mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
93 });
94 return pbDest;
95}
96
100WINPR_ATTR_NODISCARD
101static inline BOOL RLEDECOMPRESS(const BYTE* WINPR_RESTRICT pbSrcBuffer, UINT32 cbSrcBuffer,
102 BYTE* WINPR_RESTRICT pbDestBuffer, UINT32 rowDelta, UINT32 width,
103 UINT32 height)
104{
105 const BYTE* pbSrc = pbSrcBuffer;
106 BYTE* pbDest = pbDestBuffer;
107 PIXEL temp = 0;
108 PIXEL fgPel = WHITE_PIXEL;
109 BOOL fInsertFgPel = FALSE;
110 BOOL fFirstLine = TRUE;
111 BYTE bitmask = 0;
112 PIXEL pixelA = 0;
113 PIXEL pixelB = 0;
114 UINT32 runLength = 0;
115 UINT32 code = 0;
116 UINT32 advance = 0;
117 RLEEXTRA
118
119 if ((rowDelta == 0) || (rowDelta < width))
120 {
121 WLog_ERR(TAG, "Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32, rowDelta,
122 width);
123 return FALSE;
124 }
125
126 if (!pbSrcBuffer || !pbDestBuffer)
127 {
128 WLog_ERR(TAG, "Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p",
129 WINPR_CXX_COMPAT_CAST(const void*, pbSrcBuffer),
130 WINPR_CXX_COMPAT_CAST(const void*, pbDestBuffer));
131 return FALSE;
132 }
133
134 const BYTE* pbEnd = &pbSrcBuffer[cbSrcBuffer];
135 const BYTE* pbDestEnd = &pbDestBuffer[1ULL * rowDelta * height];
136
137 while (pbSrc < pbEnd)
138 {
139 /* Watch out for the end of the first scanline. */
140 if (fFirstLine)
141 {
142 if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta)
143 {
144 fFirstLine = FALSE;
145 fInsertFgPel = FALSE;
146 }
147 }
148
149 /*
150 Extract the compression order code ID from the compression
151 order header.
152 */
153 code = ExtractCodeId(*pbSrc);
154
155#if defined(WITH_DEBUG_CODECS)
156 WLog_VRB(TAG, "pbSrc=%p code=%s, rem=%" PRIuz, pbSrc, rle_code_str(code), pbEnd - pbSrc);
157#endif
158
159 /* Handle Background Run Orders. */
160 if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN))
161 {
162 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
163 if (advance == 0)
164 return FALSE;
165 pbSrc = pbSrc + advance;
166
167 if (fFirstLine)
168 {
169 if (fInsertFgPel)
170 {
171 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
172 return FALSE;
173
174 DESTWRITEPIXEL(pbDest, fgPel);
175 runLength = runLength - 1;
176 }
177
178 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
179 return FALSE;
180
181 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); });
182 }
183 else
184 {
185 if (fInsertFgPel)
186 {
187 DESTREADPIXEL(temp, pbDest - rowDelta);
188
189 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
190 return FALSE;
191
192 DESTWRITEPIXEL(pbDest, temp ^ fgPel);
193 runLength--;
194 }
195
196 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
197 return FALSE;
198
199 UNROLL(runLength, {
200 DESTREADPIXEL(temp, pbDest - rowDelta);
201 DESTWRITEPIXEL(pbDest, temp);
202 });
203 }
204
205 /* A follow-on background run order will need a foreground pel inserted. */
206 fInsertFgPel = TRUE;
207 continue;
208 }
209
210 /* For any of the other run-types a follow-on background run
211 order does not need a foreground pel inserted. */
212 fInsertFgPel = FALSE;
213
214 switch (code)
215 {
216 /* Handle Foreground Run Orders. */
217 case REGULAR_FG_RUN:
218 case MEGA_MEGA_FG_RUN:
219 case LITE_SET_FG_FG_RUN:
220 case MEGA_MEGA_SET_FG_RUN:
221 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
222 if (advance == 0)
223 return FALSE;
224 pbSrc = pbSrc + advance;
225
226 if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
227 {
228 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
229 return FALSE;
230 SRCREADPIXEL(fgPel, pbSrc);
231 }
232
233 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
234 return FALSE;
235
236 if (fFirstLine)
237 {
238 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); });
239 }
240 else
241 {
242 UNROLL(runLength, {
243 DESTREADPIXEL(temp, pbDest - rowDelta);
244 DESTWRITEPIXEL(pbDest, temp ^ fgPel);
245 });
246 }
247
248 break;
249
250 /* Handle Dithered Run Orders. */
251 case LITE_DITHERED_RUN:
252 case MEGA_MEGA_DITHERED_RUN:
253 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
254 if (advance == 0)
255 return FALSE;
256 pbSrc = pbSrc + advance;
257 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
258 return FALSE;
259 SRCREADPIXEL(pixelA, pbSrc);
260 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
261 return FALSE;
262 SRCREADPIXEL(pixelB, pbSrc);
263
264 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
265 return FALSE;
266
267 UNROLL(runLength, {
268 DESTWRITEPIXEL(pbDest, pixelA);
269 DESTWRITEPIXEL(pbDest, pixelB);
270 });
271 break;
272
273 /* Handle Color Run Orders. */
274 case REGULAR_COLOR_RUN:
275 case MEGA_MEGA_COLOR_RUN:
276 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
277 if (advance == 0)
278 return FALSE;
279 pbSrc = pbSrc + advance;
280 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
281 return FALSE;
282 SRCREADPIXEL(pixelA, pbSrc);
283
284 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
285 return FALSE;
286
287 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); });
288 break;
289
290 /* Handle Foreground/Background Image Orders. */
291 case REGULAR_FGBG_IMAGE:
292 case MEGA_MEGA_FGBG_IMAGE:
293 case LITE_SET_FG_FGBG_IMAGE:
294 case MEGA_MEGA_SET_FGBG_IMAGE:
295 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
296 if (advance == 0)
297 return FALSE;
298 pbSrc = pbSrc + advance;
299
300 if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
301 {
302 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
303 return FALSE;
304 SRCREADPIXEL(fgPel, pbSrc);
305 }
306
307 if (!buffer_within_range(pbSrc, runLength / 8, pbEnd))
308 return FALSE;
309 if (fFirstLine)
310 {
311 while (runLength > 8)
312 {
313 bitmask = *pbSrc;
314 pbSrc = pbSrc + 1;
315 pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8);
316
317 if (!pbDest)
318 return FALSE;
319
320 runLength = runLength - 8;
321 }
322 }
323 else
324 {
325 while (runLength > 8)
326 {
327 bitmask = *pbSrc++;
328
329 pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
330
331 if (!pbDest)
332 return FALSE;
333
334 runLength = runLength - 8;
335 }
336 }
337
338 if (runLength > 0)
339 {
340 if (!buffer_within_range(pbSrc, 1, pbEnd))
341 return FALSE;
342 bitmask = *pbSrc++;
343
344 if (fFirstLine)
345 {
346 pbDest =
347 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength);
348 }
349 else
350 {
351 pbDest =
352 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength);
353 }
354
355 if (!pbDest)
356 return FALSE;
357 }
358
359 break;
360
361 /* Handle Color Image Orders. */
362 case REGULAR_COLOR_IMAGE:
363 case MEGA_MEGA_COLOR_IMAGE:
364 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
365 if (advance == 0)
366 return FALSE;
367 pbSrc = pbSrc + advance;
368 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
369 return FALSE;
370 if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength))
371 return FALSE;
372
373 UNROLL(runLength, {
374 SRCREADPIXEL(temp, pbSrc);
375 DESTWRITEPIXEL(pbDest, temp);
376 });
377 break;
378
379 /* Handle Special Order 1. */
380 case SPECIAL_FGBG_1:
381 if (!buffer_within_range(pbSrc, 1, pbEnd))
382 return FALSE;
383 pbSrc = pbSrc + 1;
384
385 if (fFirstLine)
386 {
387 pbDest =
388 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8);
389 }
390 else
391 {
392 pbDest =
393 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
394 }
395
396 if (!pbDest)
397 return FALSE;
398
399 break;
400
401 /* Handle Special Order 2. */
402 case SPECIAL_FGBG_2:
403 if (!buffer_within_range(pbSrc, 1, pbEnd))
404 return FALSE;
405 pbSrc = pbSrc + 1;
406
407 if (fFirstLine)
408 {
409 pbDest =
410 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8);
411 }
412 else
413 {
414 pbDest =
415 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
416 }
417
418 if (!pbDest)
419 return FALSE;
420
421 break;
422
423 /* Handle White Order. */
424 case SPECIAL_WHITE:
425 if (!buffer_within_range(pbSrc, 1, pbEnd))
426 return FALSE;
427 pbSrc = pbSrc + 1;
428
429 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
430 return FALSE;
431
432 DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
433 break;
434
435 /* Handle Black Order. */
436 case SPECIAL_BLACK:
437 if (!buffer_within_range(pbSrc, 1, pbEnd))
438 return FALSE;
439 pbSrc = pbSrc + 1;
440
441 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
442 return FALSE;
443
444 DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
445 break;
446
447 default:
448 WLog_ERR(TAG, "invalid code 0x%08" PRIx32 ", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p",
449 code, WINPR_CXX_COMPAT_CAST(const void*, pbSrcBuffer),
450 WINPR_CXX_COMPAT_CAST(const void*, pbSrc),
451 WINPR_CXX_COMPAT_CAST(const void*, pbEnd));
452 return FALSE;
453 }
454 }
455
456 return TRUE;
457}