• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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