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