1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxcodec/jbig2/JBig2_Image.h"
8
9 #include <limits.h>
10 #include <stddef.h>
11
12 #include <algorithm>
13 #include <memory>
14
15 #include "core/fxcrt/check.h"
16 #include "core/fxcrt/compiler_specific.h"
17 #include "core/fxcrt/fx_2d_size.h"
18 #include "core/fxcrt/fx_coordinates.h"
19 #include "core/fxcrt/fx_memcpy_wrappers.h"
20 #include "core/fxcrt/fx_memory.h"
21 #include "core/fxcrt/fx_safe_types.h"
22
23 #define JBIG2_GETDWORD(buf) \
24 ((static_cast<uint32_t>((buf)[0]) << 24) | \
25 (static_cast<uint32_t>((buf)[1]) << 16) | \
26 (static_cast<uint32_t>((buf)[2]) << 8) | \
27 (static_cast<uint32_t>((buf)[3]) << 0))
28
29 #define JBIG2_PUTDWORD(buf, val) \
30 ((buf)[0] = static_cast<uint8_t>((val) >> 24), \
31 (buf)[1] = static_cast<uint8_t>((val) >> 16), \
32 (buf)[2] = static_cast<uint8_t>((val) >> 8), \
33 (buf)[3] = static_cast<uint8_t>((val) >> 0))
34
35 namespace {
36
37 const int kMaxImagePixels = INT_MAX - 31;
38 const int kMaxImageBytes = kMaxImagePixels / 8;
39
BitIndexToByte(int index)40 int BitIndexToByte(int index) {
41 return index / 8;
42 }
43
BitIndexToAlignedByte(int index)44 int BitIndexToAlignedByte(int index) {
45 return index / 32 * 4;
46 }
47
48 } // namespace
49
CJBig2_Image(int32_t w,int32_t h)50 CJBig2_Image::CJBig2_Image(int32_t w, int32_t h) {
51 if (w <= 0 || h <= 0 || w > kMaxImagePixels)
52 return;
53
54 int32_t stride_pixels = FxAlignToBoundary<32>(w);
55 if (h > kMaxImagePixels / stride_pixels)
56 return;
57
58 m_nWidth = w;
59 m_nHeight = h;
60 m_nStride = stride_pixels / 8;
61 m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>(
62 FX_Alloc2D(uint8_t, m_nStride, m_nHeight)));
63 }
64
CJBig2_Image(int32_t w,int32_t h,int32_t stride,pdfium::span<uint8_t> pBuf)65 CJBig2_Image::CJBig2_Image(int32_t w,
66 int32_t h,
67 int32_t stride,
68 pdfium::span<uint8_t> pBuf) {
69 if (w < 0 || h < 0)
70 return;
71
72 // Stride must be word-aligned.
73 if (stride < 0 || stride > kMaxImageBytes || stride % 4 != 0)
74 return;
75
76 int32_t stride_pixels = 8 * stride;
77 if (stride_pixels < w || h > kMaxImagePixels / stride_pixels)
78 return;
79
80 m_nWidth = w;
81 m_nHeight = h;
82 m_nStride = stride;
83 m_pData.Reset(pBuf.data());
84 }
85
CJBig2_Image(const CJBig2_Image & other)86 CJBig2_Image::CJBig2_Image(const CJBig2_Image& other)
87 : m_nWidth(other.m_nWidth),
88 m_nHeight(other.m_nHeight),
89 m_nStride(other.m_nStride) {
90 if (other.m_pData) {
91 m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>(
92 FX_Alloc2D(uint8_t, m_nStride, m_nHeight)));
93 UNSAFE_TODO(FXSYS_memcpy(data(), other.data(), m_nStride * m_nHeight));
94 }
95 }
96
97 CJBig2_Image::~CJBig2_Image() = default;
98
99 // static
IsValidImageSize(int32_t w,int32_t h)100 bool CJBig2_Image::IsValidImageSize(int32_t w, int32_t h) {
101 return w > 0 && w <= kJBig2MaxImageSize && h > 0 && h <= kJBig2MaxImageSize;
102 }
103
GetPixel(int32_t x,int32_t y) const104 int CJBig2_Image::GetPixel(int32_t x, int32_t y) const {
105 if (!m_pData)
106 return 0;
107
108 if (x < 0 || x >= m_nWidth)
109 return 0;
110
111 const uint8_t* pLine = GetLine(y);
112 if (!pLine)
113 return 0;
114
115 int32_t m = BitIndexToByte(x);
116 int32_t n = x & 7;
117 return UNSAFE_TODO((pLine[m] >> (7 - n)) & 1);
118 }
119
SetPixel(int32_t x,int32_t y,int v)120 void CJBig2_Image::SetPixel(int32_t x, int32_t y, int v) {
121 if (!m_pData)
122 return;
123
124 if (x < 0 || x >= m_nWidth)
125 return;
126
127 uint8_t* pLine = GetLine(y);
128 if (!pLine)
129 return;
130
131 int32_t m = BitIndexToByte(x);
132 int32_t n = 1 << (7 - (x & 7));
133 if (v) {
134 UNSAFE_TODO(pLine[m]) |= n;
135 } else {
136 UNSAFE_TODO(pLine[m]) &= ~n;
137 }
138 }
139
CopyLine(int32_t hTo,int32_t hFrom)140 void CJBig2_Image::CopyLine(int32_t hTo, int32_t hFrom) {
141 if (!m_pData)
142 return;
143
144 uint8_t* pDst = GetLine(hTo);
145 if (!pDst)
146 return;
147
148 const uint8_t* pSrc = GetLine(hFrom);
149 UNSAFE_TODO({
150 if (!pSrc) {
151 FXSYS_memset(pDst, 0, m_nStride);
152 return;
153 }
154 FXSYS_memcpy(pDst, pSrc, m_nStride);
155 });
156 }
157
Fill(bool v)158 void CJBig2_Image::Fill(bool v) {
159 if (!m_pData)
160 return;
161
162 UNSAFE_TODO(
163 FXSYS_memset(data(), v ? 0xff : 0, Fx2DSizeOrDie(m_nStride, m_nHeight)));
164 }
165
ComposeTo(CJBig2_Image * pDst,int32_t x,int32_t y,JBig2ComposeOp op)166 bool CJBig2_Image::ComposeTo(CJBig2_Image* pDst,
167 int32_t x,
168 int32_t y,
169 JBig2ComposeOp op) {
170 return m_pData &&
171 ComposeToInternal(pDst, x, y, op, FX_RECT(0, 0, m_nWidth, m_nHeight));
172 }
173
ComposeToWithRect(CJBig2_Image * pDst,int32_t x,int32_t y,const FX_RECT & rtSrc,JBig2ComposeOp op)174 bool CJBig2_Image::ComposeToWithRect(CJBig2_Image* pDst,
175 int32_t x,
176 int32_t y,
177 const FX_RECT& rtSrc,
178 JBig2ComposeOp op) {
179 return m_pData && ComposeToInternal(pDst, x, y, op, rtSrc);
180 }
181
ComposeFrom(int32_t x,int32_t y,CJBig2_Image * pSrc,JBig2ComposeOp op)182 bool CJBig2_Image::ComposeFrom(int32_t x,
183 int32_t y,
184 CJBig2_Image* pSrc,
185 JBig2ComposeOp op) {
186 return m_pData && pSrc->ComposeTo(this, x, y, op);
187 }
188
ComposeFromWithRect(int32_t x,int32_t y,CJBig2_Image * pSrc,const FX_RECT & rtSrc,JBig2ComposeOp op)189 bool CJBig2_Image::ComposeFromWithRect(int32_t x,
190 int32_t y,
191 CJBig2_Image* pSrc,
192 const FX_RECT& rtSrc,
193 JBig2ComposeOp op) {
194 return m_pData && pSrc->ComposeToWithRect(this, x, y, rtSrc, op);
195 }
196
SubImage(int32_t x,int32_t y,int32_t w,int32_t h)197 std::unique_ptr<CJBig2_Image> CJBig2_Image::SubImage(int32_t x,
198 int32_t y,
199 int32_t w,
200 int32_t h) {
201 auto pImage = std::make_unique<CJBig2_Image>(w, h);
202 if (!pImage->data() || !m_pData)
203 return pImage;
204
205 if (x < 0 || x >= m_nWidth || y < 0 || y >= m_nHeight)
206 return pImage;
207
208 // Fast case when byte-aligned, normal slow case otherwise.
209 if ((x & 7) == 0)
210 SubImageFast(x, y, w, h, pImage.get());
211 else
212 SubImageSlow(x, y, w, h, pImage.get());
213
214 return pImage;
215 }
216
SubImageFast(int32_t x,int32_t y,int32_t w,int32_t h,CJBig2_Image * pImage)217 void CJBig2_Image::SubImageFast(int32_t x,
218 int32_t y,
219 int32_t w,
220 int32_t h,
221 CJBig2_Image* pImage) {
222 int32_t m = BitIndexToByte(x);
223 int32_t bytes_to_copy = std::min(pImage->m_nStride, m_nStride - m);
224 int32_t lines_to_copy = std::min(pImage->m_nHeight, m_nHeight - y);
225 for (int32_t j = 0; j < lines_to_copy; j++) {
226 UNSAFE_TODO(FXSYS_memcpy(pImage->GetLineUnsafe(j), GetLineUnsafe(y + j) + m,
227 bytes_to_copy));
228 }
229 }
230
SubImageSlow(int32_t x,int32_t y,int32_t w,int32_t h,CJBig2_Image * pImage)231 void CJBig2_Image::SubImageSlow(int32_t x,
232 int32_t y,
233 int32_t w,
234 int32_t h,
235 CJBig2_Image* pImage) {
236 int32_t m = BitIndexToAlignedByte(x);
237 int32_t n = x & 31;
238 int32_t bytes_to_copy = std::min(pImage->m_nStride, m_nStride - m);
239 int32_t lines_to_copy = std::min(pImage->m_nHeight, m_nHeight - y);
240 UNSAFE_TODO({
241 for (int32_t j = 0; j < lines_to_copy; j++) {
242 const uint8_t* pLineSrc = GetLineUnsafe(y + j);
243 uint8_t* pLineDst = pImage->GetLineUnsafe(j);
244 const uint8_t* pSrc = pLineSrc + m;
245 const uint8_t* pSrcEnd = pLineSrc + m_nStride;
246 uint8_t* pDstEnd = pLineDst + bytes_to_copy;
247 for (uint8_t* pDst = pLineDst; pDst < pDstEnd; pSrc += 4, pDst += 4) {
248 uint32_t wTmp = JBIG2_GETDWORD(pSrc) << n;
249 if (pSrc + 4 < pSrcEnd) {
250 wTmp |= (JBIG2_GETDWORD(pSrc + 4) >> (32 - n));
251 }
252 JBIG2_PUTDWORD(pDst, wTmp);
253 }
254 }
255 });
256 }
257
Expand(int32_t h,bool v)258 void CJBig2_Image::Expand(int32_t h, bool v) {
259 if (!m_pData || h <= m_nHeight || h > kMaxImageBytes / m_nStride)
260 return;
261
262 // Won't die unless kMaxImageBytes were to be increased someday.
263 const size_t current_size = Fx2DSizeOrDie(m_nHeight, m_nStride);
264 const size_t desired_size = Fx2DSizeOrDie(h, m_nStride);
265
266 if (m_pData.IsOwned()) {
267 m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>(FX_Realloc(
268 uint8_t, m_pData.ReleaseAndClear().release(), desired_size)));
269 } else {
270 uint8_t* pExternalBuffer = data();
271 m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>(
272 FX_Alloc(uint8_t, desired_size)));
273 UNSAFE_TODO(FXSYS_memcpy(data(), pExternalBuffer, current_size));
274 }
275 UNSAFE_TODO(FXSYS_memset(data() + current_size, v ? 0xff : 0,
276 desired_size - current_size));
277 m_nHeight = h;
278 }
279
ComposeToInternal(CJBig2_Image * pDst,int32_t x,int32_t y,JBig2ComposeOp op,const FX_RECT & rtSrc)280 bool CJBig2_Image::ComposeToInternal(CJBig2_Image* pDst,
281 int32_t x,
282 int32_t y,
283 JBig2ComposeOp op,
284 const FX_RECT& rtSrc) {
285 DCHECK(m_pData);
286
287 // TODO(weili): Check whether the range check is correct. Should x>=1048576?
288 if (x < -1048576 || x > 1048576 || y < -1048576 || y > 1048576)
289 return false;
290
291 int32_t sw = rtSrc.Width();
292 int32_t sh = rtSrc.Height();
293
294 int32_t xs0 = x < 0 ? -x : 0;
295 int32_t xs1;
296 FX_SAFE_INT32 iChecked = pDst->m_nWidth;
297 iChecked -= x;
298 if (iChecked.IsValid() && sw > iChecked.ValueOrDie())
299 xs1 = iChecked.ValueOrDie();
300 else
301 xs1 = sw;
302
303 int32_t ys0 = y < 0 ? -y : 0;
304 int32_t ys1;
305 iChecked = pDst->m_nHeight;
306 iChecked -= y;
307 if (iChecked.IsValid() && sh > iChecked.ValueOrDie())
308 ys1 = iChecked.ValueOrDie();
309 else
310 ys1 = sh;
311
312 if (ys0 >= ys1 || xs0 >= xs1)
313 return false;
314
315 int32_t xd0 = std::max(x, 0);
316 int32_t yd0 = std::max(y, 0);
317 int32_t w = xs1 - xs0;
318 int32_t h = ys1 - ys0;
319 int32_t xd1 = xd0 + w;
320 int32_t yd1 = yd0 + h;
321 uint32_t d1 = xd0 & 31;
322 uint32_t d2 = xd1 & 31;
323 uint32_t s1 = xs0 & 31;
324 uint32_t maskL = 0xffffffff >> d1;
325 uint32_t maskR = 0xffffffff << ((32 - (xd1 & 31)) % 32);
326 uint32_t maskM = maskL & maskR;
327 UNSAFE_TODO({
328 const uint8_t* lineSrc = GetLineUnsafe(rtSrc.top + ys0) +
329 BitIndexToAlignedByte(xs0 + rtSrc.left);
330 const uint8_t* lineSrcEnd = data() + Fx2DSizeOrDie(m_nHeight, m_nStride);
331 int32_t lineLeft = m_nStride - BitIndexToAlignedByte(xs0);
332 uint8_t* lineDst = pDst->GetLineUnsafe(yd0) + BitIndexToAlignedByte(xd0);
333 if ((xd0 & ~31) == ((xd1 - 1) & ~31)) {
334 if ((xs0 & ~31) == ((xs1 - 1) & ~31)) {
335 if (s1 > d1) {
336 uint32_t shift = s1 - d1;
337 for (int32_t yy = yd0; yy < yd1; yy++) {
338 if (lineSrc >= lineSrcEnd) {
339 return false;
340 }
341 uint32_t tmp1 = JBIG2_GETDWORD(lineSrc) << shift;
342 uint32_t tmp2 = JBIG2_GETDWORD(lineDst);
343 uint32_t tmp = 0;
344 switch (op) {
345 case JBIG2_COMPOSE_OR:
346 tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
347 break;
348 case JBIG2_COMPOSE_AND:
349 tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
350 break;
351 case JBIG2_COMPOSE_XOR:
352 tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
353 break;
354 case JBIG2_COMPOSE_XNOR:
355 tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
356 break;
357 case JBIG2_COMPOSE_REPLACE:
358 tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
359 break;
360 }
361 JBIG2_PUTDWORD(lineDst, tmp);
362 lineSrc += m_nStride;
363 lineDst += pDst->m_nStride;
364 }
365 } else {
366 uint32_t shift = d1 - s1;
367 for (int32_t yy = yd0; yy < yd1; yy++) {
368 if (lineSrc >= lineSrcEnd) {
369 return false;
370 }
371 uint32_t tmp1 = JBIG2_GETDWORD(lineSrc) >> shift;
372 uint32_t tmp2 = JBIG2_GETDWORD(lineDst);
373 uint32_t tmp = 0;
374 switch (op) {
375 case JBIG2_COMPOSE_OR:
376 tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
377 break;
378 case JBIG2_COMPOSE_AND:
379 tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
380 break;
381 case JBIG2_COMPOSE_XOR:
382 tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
383 break;
384 case JBIG2_COMPOSE_XNOR:
385 tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
386 break;
387 case JBIG2_COMPOSE_REPLACE:
388 tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
389 break;
390 }
391 JBIG2_PUTDWORD(lineDst, tmp);
392 lineSrc += m_nStride;
393 lineDst += pDst->m_nStride;
394 }
395 }
396 } else {
397 uint32_t shift1 = s1 - d1;
398 uint32_t shift2 = 32 - shift1;
399 for (int32_t yy = yd0; yy < yd1; yy++) {
400 if (lineSrc >= lineSrcEnd)
401 return false;
402 uint32_t tmp1 = (JBIG2_GETDWORD(lineSrc) << shift1) |
403 (JBIG2_GETDWORD(lineSrc + 4) >> shift2);
404 uint32_t tmp2 = JBIG2_GETDWORD(lineDst);
405 uint32_t tmp = 0;
406 switch (op) {
407 case JBIG2_COMPOSE_OR:
408 tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
409 break;
410 case JBIG2_COMPOSE_AND:
411 tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
412 break;
413 case JBIG2_COMPOSE_XOR:
414 tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
415 break;
416 case JBIG2_COMPOSE_XNOR:
417 tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
418 break;
419 case JBIG2_COMPOSE_REPLACE:
420 tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
421 break;
422 }
423 JBIG2_PUTDWORD(lineDst, tmp);
424 lineSrc += m_nStride;
425 lineDst += pDst->m_nStride;
426 }
427 }
428 } else {
429 if (s1 > d1) {
430 uint32_t shift1 = s1 - d1;
431 uint32_t shift2 = 32 - shift1;
432 int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
433 for (int32_t yy = yd0; yy < yd1; yy++) {
434 if (lineSrc >= lineSrcEnd) {
435 return false;
436 }
437 const uint8_t* sp = lineSrc;
438 uint8_t* dp = lineDst;
439 if (d1 != 0) {
440 uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift1) |
441 (JBIG2_GETDWORD(sp + 4) >> shift2);
442 uint32_t tmp2 = JBIG2_GETDWORD(dp);
443 uint32_t tmp = 0;
444 switch (op) {
445 case JBIG2_COMPOSE_OR:
446 tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
447 break;
448 case JBIG2_COMPOSE_AND:
449 tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
450 break;
451 case JBIG2_COMPOSE_XOR:
452 tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
453 break;
454 case JBIG2_COMPOSE_XNOR:
455 tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
456 break;
457 case JBIG2_COMPOSE_REPLACE:
458 tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
459 break;
460 }
461 JBIG2_PUTDWORD(dp, tmp);
462 sp += 4;
463 dp += 4;
464 }
465 for (int32_t xx = 0; xx < middleDwords; xx++) {
466 uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift1) |
467 (JBIG2_GETDWORD(sp + 4) >> shift2);
468 uint32_t tmp2 = JBIG2_GETDWORD(dp);
469 uint32_t tmp = 0;
470 switch (op) {
471 case JBIG2_COMPOSE_OR:
472 tmp = tmp1 | tmp2;
473 break;
474 case JBIG2_COMPOSE_AND:
475 tmp = tmp1 & tmp2;
476 break;
477 case JBIG2_COMPOSE_XOR:
478 tmp = tmp1 ^ tmp2;
479 break;
480 case JBIG2_COMPOSE_XNOR:
481 tmp = ~(tmp1 ^ tmp2);
482 break;
483 case JBIG2_COMPOSE_REPLACE:
484 tmp = tmp1;
485 break;
486 }
487 JBIG2_PUTDWORD(dp, tmp);
488 sp += 4;
489 dp += 4;
490 }
491 if (d2 != 0) {
492 uint32_t tmp1 =
493 (JBIG2_GETDWORD(sp) << shift1) |
494 (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >>
495 shift2);
496 uint32_t tmp2 = JBIG2_GETDWORD(dp);
497 uint32_t tmp = 0;
498 switch (op) {
499 case JBIG2_COMPOSE_OR:
500 tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
501 break;
502 case JBIG2_COMPOSE_AND:
503 tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
504 break;
505 case JBIG2_COMPOSE_XOR:
506 tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
507 break;
508 case JBIG2_COMPOSE_XNOR:
509 tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
510 break;
511 case JBIG2_COMPOSE_REPLACE:
512 tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
513 break;
514 }
515 JBIG2_PUTDWORD(dp, tmp);
516 }
517 lineSrc += m_nStride;
518 lineDst += pDst->m_nStride;
519 }
520 } else if (s1 == d1) {
521 int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
522 for (int32_t yy = yd0; yy < yd1; yy++) {
523 if (lineSrc >= lineSrcEnd) {
524 return false;
525 }
526 const uint8_t* sp = lineSrc;
527 uint8_t* dp = lineDst;
528 if (d1 != 0) {
529 uint32_t tmp1 = JBIG2_GETDWORD(sp);
530 uint32_t tmp2 = JBIG2_GETDWORD(dp);
531 uint32_t tmp = 0;
532 switch (op) {
533 case JBIG2_COMPOSE_OR:
534 tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
535 break;
536 case JBIG2_COMPOSE_AND:
537 tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
538 break;
539 case JBIG2_COMPOSE_XOR:
540 tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
541 break;
542 case JBIG2_COMPOSE_XNOR:
543 tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
544 break;
545 case JBIG2_COMPOSE_REPLACE:
546 tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
547 break;
548 }
549 JBIG2_PUTDWORD(dp, tmp);
550 sp += 4;
551 dp += 4;
552 }
553 for (int32_t xx = 0; xx < middleDwords; xx++) {
554 uint32_t tmp1 = JBIG2_GETDWORD(sp);
555 uint32_t tmp2 = JBIG2_GETDWORD(dp);
556 uint32_t tmp = 0;
557 switch (op) {
558 case JBIG2_COMPOSE_OR:
559 tmp = tmp1 | tmp2;
560 break;
561 case JBIG2_COMPOSE_AND:
562 tmp = tmp1 & tmp2;
563 break;
564 case JBIG2_COMPOSE_XOR:
565 tmp = tmp1 ^ tmp2;
566 break;
567 case JBIG2_COMPOSE_XNOR:
568 tmp = ~(tmp1 ^ tmp2);
569 break;
570 case JBIG2_COMPOSE_REPLACE:
571 tmp = tmp1;
572 break;
573 }
574 JBIG2_PUTDWORD(dp, tmp);
575 sp += 4;
576 dp += 4;
577 }
578 if (d2 != 0) {
579 uint32_t tmp1 = JBIG2_GETDWORD(sp);
580 uint32_t tmp2 = JBIG2_GETDWORD(dp);
581 uint32_t tmp = 0;
582 switch (op) {
583 case JBIG2_COMPOSE_OR:
584 tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
585 break;
586 case JBIG2_COMPOSE_AND:
587 tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
588 break;
589 case JBIG2_COMPOSE_XOR:
590 tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
591 break;
592 case JBIG2_COMPOSE_XNOR:
593 tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
594 break;
595 case JBIG2_COMPOSE_REPLACE:
596 tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
597 break;
598 }
599 JBIG2_PUTDWORD(dp, tmp);
600 }
601 lineSrc += m_nStride;
602 lineDst += pDst->m_nStride;
603 }
604 } else {
605 uint32_t shift1 = d1 - s1;
606 uint32_t shift2 = 32 - shift1;
607 int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
608 for (int32_t yy = yd0; yy < yd1; yy++) {
609 if (lineSrc >= lineSrcEnd) {
610 return false;
611 }
612 const uint8_t* sp = lineSrc;
613 uint8_t* dp = lineDst;
614 if (d1 != 0) {
615 uint32_t tmp1 = JBIG2_GETDWORD(sp) >> shift1;
616 uint32_t tmp2 = JBIG2_GETDWORD(dp);
617 uint32_t tmp = 0;
618 switch (op) {
619 case JBIG2_COMPOSE_OR:
620 tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
621 break;
622 case JBIG2_COMPOSE_AND:
623 tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
624 break;
625 case JBIG2_COMPOSE_XOR:
626 tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
627 break;
628 case JBIG2_COMPOSE_XNOR:
629 tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
630 break;
631 case JBIG2_COMPOSE_REPLACE:
632 tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
633 break;
634 }
635 JBIG2_PUTDWORD(dp, tmp);
636 dp += 4;
637 }
638 for (int32_t xx = 0; xx < middleDwords; xx++) {
639 uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift2) |
640 ((JBIG2_GETDWORD(sp + 4)) >> shift1);
641 uint32_t tmp2 = JBIG2_GETDWORD(dp);
642 uint32_t tmp = 0;
643 switch (op) {
644 case JBIG2_COMPOSE_OR:
645 tmp = tmp1 | tmp2;
646 break;
647 case JBIG2_COMPOSE_AND:
648 tmp = tmp1 & tmp2;
649 break;
650 case JBIG2_COMPOSE_XOR:
651 tmp = tmp1 ^ tmp2;
652 break;
653 case JBIG2_COMPOSE_XNOR:
654 tmp = ~(tmp1 ^ tmp2);
655 break;
656 case JBIG2_COMPOSE_REPLACE:
657 tmp = tmp1;
658 break;
659 }
660 JBIG2_PUTDWORD(dp, tmp);
661 sp += 4;
662 dp += 4;
663 }
664 if (d2 != 0) {
665 uint32_t tmp1 =
666 (JBIG2_GETDWORD(sp) << shift2) |
667 (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >>
668 shift1);
669 uint32_t tmp2 = JBIG2_GETDWORD(dp);
670 uint32_t tmp = 0;
671 switch (op) {
672 case JBIG2_COMPOSE_OR:
673 tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
674 break;
675 case JBIG2_COMPOSE_AND:
676 tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
677 break;
678 case JBIG2_COMPOSE_XOR:
679 tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
680 break;
681 case JBIG2_COMPOSE_XNOR:
682 tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
683 break;
684 case JBIG2_COMPOSE_REPLACE:
685 tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
686 break;
687 }
688 JBIG2_PUTDWORD(dp, tmp);
689 }
690 lineSrc += m_nStride;
691 lineDst += pDst->m_nStride;
692 }
693 }
694 }
695 });
696 return true;
697 }
698