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