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 
19 #define JBIG2_GETDWORD(buf)                  \
20   ((static_cast<uint32_t>((buf)[0]) << 24) | \
21    (static_cast<uint32_t>((buf)[1]) << 16) | \
22    (static_cast<uint32_t>((buf)[2]) << 8) |  \
23    (static_cast<uint32_t>((buf)[3]) << 0))
24 
25 #define JBIG2_PUTDWORD(buf, val)                 \
26   ((buf)[0] = static_cast<uint8_t>((val) >> 24), \
27    (buf)[1] = static_cast<uint8_t>((val) >> 16), \
28    (buf)[2] = static_cast<uint8_t>((val) >> 8),  \
29    (buf)[3] = static_cast<uint8_t>((val) >> 0))
30 
31 namespace {
32 
33 const int kMaxImagePixels = INT_MAX - 31;
34 const int kMaxImageBytes = kMaxImagePixels / 8;
35 
BitIndexToByte(int index)36 int BitIndexToByte(int index) {
37   return index / 8;
38 }
39 
BitIndexToAlignedByte(int index)40 int BitIndexToAlignedByte(int index) {
41   return index / 32 * 4;
42 }
43 
44 }  // namespace
45 
CJBig2_Image(int32_t w,int32_t h)46 CJBig2_Image::CJBig2_Image(int32_t w, int32_t h) {
47   if (w <= 0 || h <= 0 || w > kMaxImagePixels)
48     return;
49 
50   int32_t stride_pixels = FxAlignToBoundary<32>(w);
51   if (h > kMaxImagePixels / stride_pixels)
52     return;
53 
54   m_nWidth = w;
55   m_nHeight = h;
56   m_nStride = stride_pixels / 8;
57   m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>(
58       FX_Alloc2D(uint8_t, m_nStride, m_nHeight)));
59 }
60 
CJBig2_Image(int32_t w,int32_t h,int32_t stride,uint8_t * pBuf)61 CJBig2_Image::CJBig2_Image(int32_t w,
62                            int32_t h,
63                            int32_t stride,
64                            uint8_t* pBuf) {
65   if (w < 0 || h < 0)
66     return;
67 
68   // Stride must be word-aligned.
69   if (stride < 0 || stride > kMaxImageBytes || stride % 4 != 0)
70     return;
71 
72   int32_t stride_pixels = 8 * stride;
73   if (stride_pixels < w || h > kMaxImagePixels / stride_pixels)
74     return;
75 
76   m_nWidth = w;
77   m_nHeight = h;
78   m_nStride = stride;
79   m_pData.Reset(pBuf);
80 }
81 
CJBig2_Image(const CJBig2_Image & other)82 CJBig2_Image::CJBig2_Image(const CJBig2_Image& other)
83     : m_nWidth(other.m_nWidth),
84       m_nHeight(other.m_nHeight),
85       m_nStride(other.m_nStride) {
86   if (other.m_pData) {
87     m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>(
88         FX_Alloc2D(uint8_t, m_nStride, m_nHeight)));
89     memcpy(data(), other.data(), m_nStride * m_nHeight);
90   }
91 }
92 
93 CJBig2_Image::~CJBig2_Image() = default;
94 
95 // static
IsValidImageSize(int32_t w,int32_t h)96 bool CJBig2_Image::IsValidImageSize(int32_t w, int32_t h) {
97   return w > 0 && w <= JBIG2_MAX_IMAGE_SIZE && h > 0 &&
98          h <= JBIG2_MAX_IMAGE_SIZE;
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   ASSERT(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 1;
674 }
675