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