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 <limits.h>
8
9#include "JBig2_Image.h"
10#include "core/include/fxcrt/fx_coordinates.h"
11#include "core/include/fxcrt/fx_safe_types.h"
12
13CJBig2_Image::CJBig2_Image(int32_t w, int32_t h) {
14  m_nWidth = w;
15  m_nHeight = h;
16  if (m_nWidth <= 0 || m_nHeight <= 0 || m_nWidth > INT_MAX - 31) {
17    m_pData = NULL;
18    m_bNeedFree = FALSE;
19    return;
20  }
21  m_nStride = ((w + 31) >> 5) << 2;
22  if (m_nStride * m_nHeight > 0 && 104857600 / (int)m_nStride > m_nHeight) {
23    m_pData = FX_Alloc2D(uint8_t, m_nStride, m_nHeight);
24  } else {
25    m_pData = NULL;
26  }
27  m_bNeedFree = TRUE;
28}
29CJBig2_Image::CJBig2_Image(int32_t w,
30                           int32_t h,
31                           int32_t stride,
32                           uint8_t* pBuf) {
33  m_nWidth = w;
34  m_nHeight = h;
35  m_nStride = stride;
36  m_pData = pBuf;
37  m_bNeedFree = FALSE;
38}
39CJBig2_Image::CJBig2_Image(const CJBig2_Image& im) {
40  m_nWidth = im.m_nWidth;
41  m_nHeight = im.m_nHeight;
42  m_nStride = im.m_nStride;
43  if (im.m_pData) {
44    m_pData = FX_Alloc2D(uint8_t, m_nStride, m_nHeight);
45    JBIG2_memcpy(m_pData, im.m_pData, m_nStride * m_nHeight);
46  } else {
47    m_pData = NULL;
48  }
49  m_bNeedFree = TRUE;
50}
51CJBig2_Image::~CJBig2_Image() {
52  if (m_bNeedFree) {
53    FX_Free(m_pData);
54  }
55}
56FX_BOOL CJBig2_Image::getPixel(int32_t x, int32_t y) {
57  if (!m_pData) {
58    return 0;
59  }
60  int32_t m, n;
61  if (x < 0 || x >= m_nWidth) {
62    return 0;
63  }
64  if (y < 0 || y >= m_nHeight) {
65    return 0;
66  }
67  m = y * m_nStride + (x >> 3);
68  n = x & 7;
69  return ((m_pData[m] >> (7 - n)) & 1);
70}
71
72int32_t CJBig2_Image::setPixel(int32_t x, int32_t y, FX_BOOL v) {
73  if (!m_pData) {
74    return 0;
75  }
76  int32_t m, n;
77  if (x < 0 || x >= m_nWidth) {
78    return 0;
79  }
80  if (y < 0 || y >= m_nHeight) {
81    return 0;
82  }
83  m = y * m_nStride + (x >> 3);
84  n = x & 7;
85  if (v) {
86    m_pData[m] |= 1 << (7 - n);
87  } else {
88    m_pData[m] &= ~(1 << (7 - n));
89  }
90  return 1;
91}
92void CJBig2_Image::copyLine(int32_t hTo, int32_t hFrom) {
93  if (!m_pData) {
94    return;
95  }
96  if (hFrom < 0 || hFrom >= m_nHeight) {
97    JBIG2_memset(m_pData + hTo * m_nStride, 0, m_nStride);
98  } else {
99    JBIG2_memcpy(m_pData + hTo * m_nStride, m_pData + hFrom * m_nStride,
100                 m_nStride);
101  }
102}
103void CJBig2_Image::fill(FX_BOOL v) {
104  if (!m_pData) {
105    return;
106  }
107  JBIG2_memset(m_pData, v ? 0xff : 0, m_nStride * m_nHeight);
108}
109FX_BOOL CJBig2_Image::composeTo(CJBig2_Image* pDst,
110                                int32_t x,
111                                int32_t y,
112                                JBig2ComposeOp op) {
113  if (!m_pData) {
114    return FALSE;
115  }
116  return composeTo_opt2(pDst, x, y, op);
117}
118FX_BOOL CJBig2_Image::composeTo(CJBig2_Image* pDst,
119                                int32_t x,
120                                int32_t y,
121                                JBig2ComposeOp op,
122                                const FX_RECT* pSrcRect) {
123  if (!m_pData) {
124    return FALSE;
125  }
126  if (NULL == pSrcRect || *pSrcRect == FX_RECT(0, 0, m_nWidth, m_nHeight)) {
127    return composeTo_opt2(pDst, x, y, op);
128  }
129  return composeTo_opt2(pDst, x, y, op, pSrcRect);
130}
131
132FX_BOOL CJBig2_Image::composeFrom(int32_t x,
133                                  int32_t y,
134                                  CJBig2_Image* pSrc,
135                                  JBig2ComposeOp op) {
136  if (!m_pData) {
137    return FALSE;
138  }
139  return pSrc->composeTo(this, x, y, op);
140}
141FX_BOOL CJBig2_Image::composeFrom(int32_t x,
142                                  int32_t y,
143                                  CJBig2_Image* pSrc,
144                                  JBig2ComposeOp op,
145                                  const FX_RECT* pSrcRect) {
146  if (!m_pData) {
147    return FALSE;
148  }
149  return pSrc->composeTo(this, x, y, op, pSrcRect);
150}
151#define JBIG2_GETDWORD(buf) \
152  ((FX_DWORD)(((buf)[0] << 24) | ((buf)[1] << 16) | ((buf)[2] << 8) | (buf)[3]))
153CJBig2_Image* CJBig2_Image::subImage(int32_t x,
154                                     int32_t y,
155                                     int32_t w,
156                                     int32_t h) {
157  int32_t m, n, j;
158  uint8_t *pLineSrc, *pLineDst;
159  FX_DWORD wTmp;
160  uint8_t *pSrc, *pSrcEnd, *pDst, *pDstEnd;
161  if (w == 0 || h == 0) {
162    return NULL;
163  }
164  CJBig2_Image* pImage = new CJBig2_Image(w, h);
165  if (!m_pData) {
166    pImage->fill(0);
167    return pImage;
168  }
169  if (!pImage->m_pData) {
170    return pImage;
171  }
172  pLineSrc = m_pData + m_nStride * y;
173  pLineDst = pImage->m_pData;
174  m = (x >> 5) << 2;
175  n = x & 31;
176  if (n == 0) {
177    for (j = 0; j < h; j++) {
178      pSrc = pLineSrc + m;
179      pSrcEnd = pLineSrc + m_nStride;
180      pDst = pLineDst;
181      pDstEnd = pLineDst + pImage->m_nStride;
182      for (; pDst < pDstEnd; pSrc += 4, pDst += 4) {
183        *((FX_DWORD*)pDst) = *((FX_DWORD*)pSrc);
184      }
185      pLineSrc += m_nStride;
186      pLineDst += pImage->m_nStride;
187    }
188  } else {
189    for (j = 0; j < h; j++) {
190      pSrc = pLineSrc + m;
191      pSrcEnd = pLineSrc + m_nStride;
192      pDst = pLineDst;
193      pDstEnd = pLineDst + pImage->m_nStride;
194      for (; pDst < pDstEnd; pSrc += 4, pDst += 4) {
195        if (pSrc + 4 < pSrcEnd) {
196          wTmp = (JBIG2_GETDWORD(pSrc) << n) |
197                 (JBIG2_GETDWORD(pSrc + 4) >> (32 - n));
198        } else {
199          wTmp = JBIG2_GETDWORD(pSrc) << n;
200        }
201        pDst[0] = (uint8_t)(wTmp >> 24);
202        pDst[1] = (uint8_t)(wTmp >> 16);
203        pDst[2] = (uint8_t)(wTmp >> 8);
204        pDst[3] = (uint8_t)wTmp;
205      }
206      pLineSrc += m_nStride;
207      pLineDst += pImage->m_nStride;
208    }
209  }
210  return pImage;
211}
212void CJBig2_Image::expand(int32_t h, FX_BOOL v) {
213  if (!m_pData || h <= m_nHeight) {
214    return;
215  }
216  FX_DWORD dwH = pdfium::base::checked_cast<FX_DWORD>(h);
217  FX_DWORD dwStride = pdfium::base::checked_cast<FX_DWORD>(m_nStride);
218  FX_DWORD dwHeight = pdfium::base::checked_cast<FX_DWORD>(m_nHeight);
219  FX_SAFE_DWORD safeMemSize = dwH;
220  safeMemSize *= dwStride;
221  if (!safeMemSize.IsValid()) {
222    return;
223  }
224  // The guaranteed reallocated memory is to be < 4GB (unsigned int).
225  m_pData = FX_Realloc(uint8_t, m_pData, safeMemSize.ValueOrDie());
226
227  // The result of dwHeight * dwStride doesn't overflow after the
228  // checking of safeMemSize.
229  // The same as the result of (dwH - dwHeight) * dwStride) because
230  // dwH - dwHeight is always less than dwH(h) which is checked in
231  // the calculation of dwH * dwStride.
232  JBIG2_memset(m_pData + dwHeight * dwStride, v ? 0xff : 0,
233               (dwH - dwHeight) * dwStride);
234  m_nHeight = h;
235}
236FX_BOOL CJBig2_Image::composeTo_opt2(CJBig2_Image* pDst,
237                                     int32_t x,
238                                     int32_t y,
239                                     JBig2ComposeOp op) {
240  int32_t xs0 = 0, ys0 = 0, xs1 = 0, ys1 = 0, xd0 = 0, yd0 = 0, xd1 = 0,
241          yd1 = 0, xx = 0, yy = 0, w = 0, h = 0, middleDwords = 0, lineLeft = 0;
242
243  FX_DWORD s1 = 0, d1 = 0, d2 = 0, shift = 0, shift1 = 0, shift2 = 0, tmp = 0,
244           tmp1 = 0, tmp2 = 0, maskL = 0, maskR = 0, maskM = 0;
245
246  uint8_t *lineSrc = NULL, *lineDst = NULL, *sp = NULL, *dp = NULL;
247
248  if (!m_pData) {
249    return FALSE;
250  }
251  if (x < -1048576 || x > 1048576 || y < -1048576 || y > 1048576) {
252    return FALSE;
253  }
254  if (y < 0) {
255    ys0 = -y;
256  }
257  if (y + m_nHeight > pDst->m_nHeight) {
258    ys1 = pDst->m_nHeight - y;
259  } else {
260    ys1 = m_nHeight;
261  }
262  if (x < 0) {
263    xs0 = -x;
264  }
265  if (x + m_nWidth > pDst->m_nWidth) {
266    xs1 = pDst->m_nWidth - x;
267  } else {
268    xs1 = m_nWidth;
269  }
270  if ((ys0 >= ys1) || (xs0 >= xs1)) {
271    return 0;
272  }
273  w = xs1 - xs0;
274  h = ys1 - ys0;
275  if (y >= 0) {
276    yd0 = y;
277  }
278  if (x >= 0) {
279    xd0 = x;
280  }
281  xd1 = xd0 + w;
282  yd1 = yd0 + h;
283  d1 = xd0 & 31;
284  d2 = xd1 & 31;
285  s1 = xs0 & 31;
286  maskL = 0xffffffff >> d1;
287  maskR = 0xffffffff << ((32 - (xd1 & 31)) % 32);
288  maskM = maskL & maskR;
289  lineSrc = m_pData + ys0 * m_nStride + ((xs0 >> 5) << 2);
290  lineLeft = m_nStride - ((xs0 >> 5) << 2);
291  lineDst = pDst->m_pData + yd0 * pDst->m_nStride + ((xd0 >> 5) << 2);
292  if ((xd0 & ~31) == ((xd1 - 1) & ~31)) {
293    if ((xs0 & ~31) == ((xs1 - 1) & ~31)) {
294      if (s1 > d1) {
295        shift = s1 - d1;
296        for (yy = yd0; yy < yd1; yy++) {
297          tmp1 = JBIG2_GETDWORD(lineSrc) << shift;
298          tmp2 = JBIG2_GETDWORD(lineDst);
299          switch (op) {
300            case JBIG2_COMPOSE_OR:
301              tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
302              break;
303            case JBIG2_COMPOSE_AND:
304              tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
305              break;
306            case JBIG2_COMPOSE_XOR:
307              tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
308              break;
309            case JBIG2_COMPOSE_XNOR:
310              tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
311              break;
312            case JBIG2_COMPOSE_REPLACE:
313              tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
314              break;
315          }
316          lineDst[0] = (uint8_t)(tmp >> 24);
317          lineDst[1] = (uint8_t)(tmp >> 16);
318          lineDst[2] = (uint8_t)(tmp >> 8);
319          lineDst[3] = (uint8_t)tmp;
320          lineSrc += m_nStride;
321          lineDst += pDst->m_nStride;
322        }
323      } else {
324        shift = d1 - s1;
325        for (yy = yd0; yy < yd1; yy++) {
326          tmp1 = JBIG2_GETDWORD(lineSrc) >> shift;
327          tmp2 = JBIG2_GETDWORD(lineDst);
328          switch (op) {
329            case JBIG2_COMPOSE_OR:
330              tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
331              break;
332            case JBIG2_COMPOSE_AND:
333              tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
334              break;
335            case JBIG2_COMPOSE_XOR:
336              tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
337              break;
338            case JBIG2_COMPOSE_XNOR:
339              tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
340              break;
341            case JBIG2_COMPOSE_REPLACE:
342              tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
343              break;
344          }
345          lineDst[0] = (uint8_t)(tmp >> 24);
346          lineDst[1] = (uint8_t)(tmp >> 16);
347          lineDst[2] = (uint8_t)(tmp >> 8);
348          lineDst[3] = (uint8_t)tmp;
349          lineSrc += m_nStride;
350          lineDst += pDst->m_nStride;
351        }
352      }
353    } else {
354      shift1 = s1 - d1;
355      shift2 = 32 - shift1;
356      for (yy = yd0; yy < yd1; yy++) {
357        tmp1 = (JBIG2_GETDWORD(lineSrc) << shift1) |
358               (JBIG2_GETDWORD(lineSrc + 4) >> shift2);
359        tmp2 = JBIG2_GETDWORD(lineDst);
360        switch (op) {
361          case JBIG2_COMPOSE_OR:
362            tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
363            break;
364          case JBIG2_COMPOSE_AND:
365            tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
366            break;
367          case JBIG2_COMPOSE_XOR:
368            tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
369            break;
370          case JBIG2_COMPOSE_XNOR:
371            tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
372            break;
373          case JBIG2_COMPOSE_REPLACE:
374            tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
375            break;
376        }
377        lineDst[0] = (uint8_t)(tmp >> 24);
378        lineDst[1] = (uint8_t)(tmp >> 16);
379        lineDst[2] = (uint8_t)(tmp >> 8);
380        lineDst[3] = (uint8_t)tmp;
381        lineSrc += m_nStride;
382        lineDst += pDst->m_nStride;
383      }
384    }
385  } else {
386    if (s1 > d1) {
387      shift1 = s1 - d1;
388      shift2 = 32 - shift1;
389      middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
390      for (yy = yd0; yy < yd1; yy++) {
391        sp = lineSrc;
392        dp = lineDst;
393        if (d1 != 0) {
394          tmp1 = (JBIG2_GETDWORD(sp) << shift1) |
395                 (JBIG2_GETDWORD(sp + 4) >> shift2);
396          tmp2 = JBIG2_GETDWORD(dp);
397          switch (op) {
398            case JBIG2_COMPOSE_OR:
399              tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
400              break;
401            case JBIG2_COMPOSE_AND:
402              tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
403              break;
404            case JBIG2_COMPOSE_XOR:
405              tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
406              break;
407            case JBIG2_COMPOSE_XNOR:
408              tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
409              break;
410            case JBIG2_COMPOSE_REPLACE:
411              tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
412              break;
413          }
414          dp[0] = (uint8_t)(tmp >> 24);
415          dp[1] = (uint8_t)(tmp >> 16);
416          dp[2] = (uint8_t)(tmp >> 8);
417          dp[3] = (uint8_t)tmp;
418          sp += 4;
419          dp += 4;
420        }
421        for (xx = 0; xx < middleDwords; xx++) {
422          tmp1 = (JBIG2_GETDWORD(sp) << shift1) |
423                 (JBIG2_GETDWORD(sp + 4) >> shift2);
424          tmp2 = JBIG2_GETDWORD(dp);
425          switch (op) {
426            case JBIG2_COMPOSE_OR:
427              tmp = tmp1 | tmp2;
428              break;
429            case JBIG2_COMPOSE_AND:
430              tmp = tmp1 & tmp2;
431              break;
432            case JBIG2_COMPOSE_XOR:
433              tmp = tmp1 ^ tmp2;
434              break;
435            case JBIG2_COMPOSE_XNOR:
436              tmp = ~(tmp1 ^ tmp2);
437              break;
438            case JBIG2_COMPOSE_REPLACE:
439              tmp = tmp1;
440              break;
441          }
442          dp[0] = (uint8_t)(tmp >> 24);
443          dp[1] = (uint8_t)(tmp >> 16);
444          dp[2] = (uint8_t)(tmp >> 8);
445          dp[3] = (uint8_t)tmp;
446          sp += 4;
447          dp += 4;
448        }
449        if (d2 != 0) {
450          tmp1 =
451              (JBIG2_GETDWORD(sp) << shift1) |
452              (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >>
453               shift2);
454          tmp2 = JBIG2_GETDWORD(dp);
455          switch (op) {
456            case JBIG2_COMPOSE_OR:
457              tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
458              break;
459            case JBIG2_COMPOSE_AND:
460              tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
461              break;
462            case JBIG2_COMPOSE_XOR:
463              tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
464              break;
465            case JBIG2_COMPOSE_XNOR:
466              tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
467              break;
468            case JBIG2_COMPOSE_REPLACE:
469              tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
470              break;
471          }
472          dp[0] = (uint8_t)(tmp >> 24);
473          dp[1] = (uint8_t)(tmp >> 16);
474          dp[2] = (uint8_t)(tmp >> 8);
475          dp[3] = (uint8_t)tmp;
476        }
477        lineSrc += m_nStride;
478        lineDst += pDst->m_nStride;
479      }
480    } else if (s1 == d1) {
481      middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
482      for (yy = yd0; yy < yd1; yy++) {
483        sp = lineSrc;
484        dp = lineDst;
485        if (d1 != 0) {
486          tmp1 = JBIG2_GETDWORD(sp);
487          tmp2 = JBIG2_GETDWORD(dp);
488          switch (op) {
489            case JBIG2_COMPOSE_OR:
490              tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
491              break;
492            case JBIG2_COMPOSE_AND:
493              tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
494              break;
495            case JBIG2_COMPOSE_XOR:
496              tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
497              break;
498            case JBIG2_COMPOSE_XNOR:
499              tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
500              break;
501            case JBIG2_COMPOSE_REPLACE:
502              tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
503              break;
504          }
505          dp[0] = (uint8_t)(tmp >> 24);
506          dp[1] = (uint8_t)(tmp >> 16);
507          dp[2] = (uint8_t)(tmp >> 8);
508          dp[3] = (uint8_t)tmp;
509          sp += 4;
510          dp += 4;
511        }
512        for (xx = 0; xx < middleDwords; xx++) {
513          tmp1 = JBIG2_GETDWORD(sp);
514          tmp2 = JBIG2_GETDWORD(dp);
515          switch (op) {
516            case JBIG2_COMPOSE_OR:
517              tmp = tmp1 | tmp2;
518              break;
519            case JBIG2_COMPOSE_AND:
520              tmp = tmp1 & tmp2;
521              break;
522            case JBIG2_COMPOSE_XOR:
523              tmp = tmp1 ^ tmp2;
524              break;
525            case JBIG2_COMPOSE_XNOR:
526              tmp = ~(tmp1 ^ tmp2);
527              break;
528            case JBIG2_COMPOSE_REPLACE:
529              tmp = tmp1;
530              break;
531          }
532          dp[0] = (uint8_t)(tmp >> 24);
533          dp[1] = (uint8_t)(tmp >> 16);
534          dp[2] = (uint8_t)(tmp >> 8);
535          dp[3] = (uint8_t)tmp;
536          sp += 4;
537          dp += 4;
538        }
539        if (d2 != 0) {
540          tmp1 = JBIG2_GETDWORD(sp);
541          tmp2 = JBIG2_GETDWORD(dp);
542          switch (op) {
543            case JBIG2_COMPOSE_OR:
544              tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
545              break;
546            case JBIG2_COMPOSE_AND:
547              tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
548              break;
549            case JBIG2_COMPOSE_XOR:
550              tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
551              break;
552            case JBIG2_COMPOSE_XNOR:
553              tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
554              break;
555            case JBIG2_COMPOSE_REPLACE:
556              tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
557              break;
558          }
559          dp[0] = (uint8_t)(tmp >> 24);
560          dp[1] = (uint8_t)(tmp >> 16);
561          dp[2] = (uint8_t)(tmp >> 8);
562          dp[3] = (uint8_t)tmp;
563        }
564        lineSrc += m_nStride;
565        lineDst += pDst->m_nStride;
566      }
567    } else {
568      shift1 = d1 - s1;
569      shift2 = 32 - shift1;
570      middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
571      for (yy = yd0; yy < yd1; yy++) {
572        sp = lineSrc;
573        dp = lineDst;
574        if (d1 != 0) {
575          tmp1 = JBIG2_GETDWORD(sp) >> shift1;
576          tmp2 = JBIG2_GETDWORD(dp);
577          switch (op) {
578            case JBIG2_COMPOSE_OR:
579              tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
580              break;
581            case JBIG2_COMPOSE_AND:
582              tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
583              break;
584            case JBIG2_COMPOSE_XOR:
585              tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
586              break;
587            case JBIG2_COMPOSE_XNOR:
588              tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
589              break;
590            case JBIG2_COMPOSE_REPLACE:
591              tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
592              break;
593          }
594          dp[0] = (uint8_t)(tmp >> 24);
595          dp[1] = (uint8_t)(tmp >> 16);
596          dp[2] = (uint8_t)(tmp >> 8);
597          dp[3] = (uint8_t)tmp;
598          dp += 4;
599        }
600        for (xx = 0; xx < middleDwords; xx++) {
601          tmp1 = (JBIG2_GETDWORD(sp) << shift2) |
602                 ((JBIG2_GETDWORD(sp + 4)) >> shift1);
603          tmp2 = JBIG2_GETDWORD(dp);
604          switch (op) {
605            case JBIG2_COMPOSE_OR:
606              tmp = tmp1 | tmp2;
607              break;
608            case JBIG2_COMPOSE_AND:
609              tmp = tmp1 & tmp2;
610              break;
611            case JBIG2_COMPOSE_XOR:
612              tmp = tmp1 ^ tmp2;
613              break;
614            case JBIG2_COMPOSE_XNOR:
615              tmp = ~(tmp1 ^ tmp2);
616              break;
617            case JBIG2_COMPOSE_REPLACE:
618              tmp = tmp1;
619              break;
620          }
621          dp[0] = (uint8_t)(tmp >> 24);
622          dp[1] = (uint8_t)(tmp >> 16);
623          dp[2] = (uint8_t)(tmp >> 8);
624          dp[3] = (uint8_t)tmp;
625          sp += 4;
626          dp += 4;
627        }
628        if (d2 != 0) {
629          tmp1 =
630              (JBIG2_GETDWORD(sp) << shift2) |
631              (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >>
632               shift1);
633          tmp2 = JBIG2_GETDWORD(dp);
634          switch (op) {
635            case JBIG2_COMPOSE_OR:
636              tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
637              break;
638            case JBIG2_COMPOSE_AND:
639              tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
640              break;
641            case JBIG2_COMPOSE_XOR:
642              tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
643              break;
644            case JBIG2_COMPOSE_XNOR:
645              tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
646              break;
647            case JBIG2_COMPOSE_REPLACE:
648              tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
649              break;
650          }
651          dp[0] = (uint8_t)(tmp >> 24);
652          dp[1] = (uint8_t)(tmp >> 16);
653          dp[2] = (uint8_t)(tmp >> 8);
654          dp[3] = (uint8_t)tmp;
655        }
656        lineSrc += m_nStride;
657        lineDst += pDst->m_nStride;
658      }
659    }
660  }
661  return 1;
662}
663FX_BOOL CJBig2_Image::composeTo_opt2(CJBig2_Image* pDst,
664                                     int32_t x,
665                                     int32_t y,
666                                     JBig2ComposeOp op,
667                                     const FX_RECT* pSrcRect) {
668  int32_t xs0, ys0, xs1, ys1, xd0, yd0, xd1, yd1, xx, yy, w, h, middleDwords,
669      lineLeft;
670  FX_DWORD s1, d1, d2, shift, shift1, shift2, tmp, tmp1, tmp2, maskL, maskR,
671      maskM;
672  uint8_t *lineSrc, *lineDst, *sp, *dp;
673  int32_t sw, sh;
674  if (!m_pData) {
675    return FALSE;
676  }
677  if (x < -1048576 || x > 1048576 || y < -1048576 || y > 1048576) {
678    return FALSE;
679  }
680  sw = pSrcRect->Width();
681  sh = pSrcRect->Height();
682  if (y < 0) {
683    ys0 = -y;
684  } else {
685    ys0 = 0;
686  }
687  if (y + sh > pDst->m_nHeight) {
688    ys1 = pDst->m_nHeight - y;
689  } else {
690    ys1 = sh;
691  }
692  if (x < 0) {
693    xs0 = -x;
694  } else {
695    xs0 = 0;
696  }
697  if (x + sw > pDst->m_nWidth) {
698    xs1 = pDst->m_nWidth - x;
699  } else {
700    xs1 = sw;
701  }
702  if ((ys0 >= ys1) || (xs0 >= xs1)) {
703    return 0;
704  }
705  w = xs1 - xs0;
706  h = ys1 - ys0;
707  if (y < 0) {
708    yd0 = 0;
709  } else {
710    yd0 = y;
711  }
712  if (x < 0) {
713    xd0 = 0;
714  } else {
715    xd0 = x;
716  }
717  xd1 = xd0 + w;
718  yd1 = yd0 + h;
719  d1 = xd0 & 31;
720  d2 = xd1 & 31;
721  s1 = xs0 & 31;
722  maskL = 0xffffffff >> d1;
723  maskR = 0xffffffff << ((32 - (xd1 & 31)) % 32);
724  maskM = maskL & maskR;
725  lineSrc = m_pData + (pSrcRect->top + ys0) * m_nStride +
726            (((xs0 + pSrcRect->left) >> 5) << 2);
727  lineLeft = m_nStride - ((xs0 >> 5) << 2);
728  lineDst = pDst->m_pData + yd0 * pDst->m_nStride + ((xd0 >> 5) << 2);
729  if ((xd0 & ~31) == ((xd1 - 1) & ~31)) {
730    if ((xs0 & ~31) == ((xs1 - 1) & ~31)) {
731      if (s1 > d1) {
732        shift = s1 - d1;
733        for (yy = yd0; yy < yd1; yy++) {
734          tmp1 = JBIG2_GETDWORD(lineSrc) << shift;
735          tmp2 = JBIG2_GETDWORD(lineDst);
736          switch (op) {
737            case JBIG2_COMPOSE_OR:
738              tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
739              break;
740            case JBIG2_COMPOSE_AND:
741              tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
742              break;
743            case JBIG2_COMPOSE_XOR:
744              tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
745              break;
746            case JBIG2_COMPOSE_XNOR:
747              tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
748              break;
749            case JBIG2_COMPOSE_REPLACE:
750              tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
751              break;
752          }
753          lineDst[0] = (uint8_t)(tmp >> 24);
754          lineDst[1] = (uint8_t)(tmp >> 16);
755          lineDst[2] = (uint8_t)(tmp >> 8);
756          lineDst[3] = (uint8_t)tmp;
757          lineSrc += m_nStride;
758          lineDst += pDst->m_nStride;
759        }
760      } else {
761        shift = d1 - s1;
762        for (yy = yd0; yy < yd1; yy++) {
763          tmp1 = JBIG2_GETDWORD(lineSrc) >> shift;
764          tmp2 = JBIG2_GETDWORD(lineDst);
765          switch (op) {
766            case JBIG2_COMPOSE_OR:
767              tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
768              break;
769            case JBIG2_COMPOSE_AND:
770              tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
771              break;
772            case JBIG2_COMPOSE_XOR:
773              tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
774              break;
775            case JBIG2_COMPOSE_XNOR:
776              tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
777              break;
778            case JBIG2_COMPOSE_REPLACE:
779              tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
780              break;
781          }
782          lineDst[0] = (uint8_t)(tmp >> 24);
783          lineDst[1] = (uint8_t)(tmp >> 16);
784          lineDst[2] = (uint8_t)(tmp >> 8);
785          lineDst[3] = (uint8_t)tmp;
786          lineSrc += m_nStride;
787          lineDst += pDst->m_nStride;
788        }
789      }
790    } else {
791      shift1 = s1 - d1;
792      shift2 = 32 - shift1;
793      for (yy = yd0; yy < yd1; yy++) {
794        tmp1 = (JBIG2_GETDWORD(lineSrc) << shift1) |
795               (JBIG2_GETDWORD(lineSrc + 4) >> shift2);
796        tmp2 = JBIG2_GETDWORD(lineDst);
797        switch (op) {
798          case JBIG2_COMPOSE_OR:
799            tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM);
800            break;
801          case JBIG2_COMPOSE_AND:
802            tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM);
803            break;
804          case JBIG2_COMPOSE_XOR:
805            tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM);
806            break;
807          case JBIG2_COMPOSE_XNOR:
808            tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM);
809            break;
810          case JBIG2_COMPOSE_REPLACE:
811            tmp = (tmp2 & ~maskM) | (tmp1 & maskM);
812            break;
813        }
814        lineDst[0] = (uint8_t)(tmp >> 24);
815        lineDst[1] = (uint8_t)(tmp >> 16);
816        lineDst[2] = (uint8_t)(tmp >> 8);
817        lineDst[3] = (uint8_t)tmp;
818        lineSrc += m_nStride;
819        lineDst += pDst->m_nStride;
820      }
821    }
822  } else {
823    if (s1 > d1) {
824      shift1 = s1 - d1;
825      shift2 = 32 - shift1;
826      middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
827      for (yy = yd0; yy < yd1; yy++) {
828        sp = lineSrc;
829        dp = lineDst;
830        if (d1 != 0) {
831          tmp1 = (JBIG2_GETDWORD(sp) << shift1) |
832                 (JBIG2_GETDWORD(sp + 4) >> shift2);
833          tmp2 = JBIG2_GETDWORD(dp);
834          switch (op) {
835            case JBIG2_COMPOSE_OR:
836              tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
837              break;
838            case JBIG2_COMPOSE_AND:
839              tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
840              break;
841            case JBIG2_COMPOSE_XOR:
842              tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
843              break;
844            case JBIG2_COMPOSE_XNOR:
845              tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
846              break;
847            case JBIG2_COMPOSE_REPLACE:
848              tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
849              break;
850          }
851          dp[0] = (uint8_t)(tmp >> 24);
852          dp[1] = (uint8_t)(tmp >> 16);
853          dp[2] = (uint8_t)(tmp >> 8);
854          dp[3] = (uint8_t)tmp;
855          sp += 4;
856          dp += 4;
857        }
858        for (xx = 0; xx < middleDwords; xx++) {
859          tmp1 = (JBIG2_GETDWORD(sp) << shift1) |
860                 (JBIG2_GETDWORD(sp + 4) >> shift2);
861          tmp2 = JBIG2_GETDWORD(dp);
862          switch (op) {
863            case JBIG2_COMPOSE_OR:
864              tmp = tmp1 | tmp2;
865              break;
866            case JBIG2_COMPOSE_AND:
867              tmp = tmp1 & tmp2;
868              break;
869            case JBIG2_COMPOSE_XOR:
870              tmp = tmp1 ^ tmp2;
871              break;
872            case JBIG2_COMPOSE_XNOR:
873              tmp = ~(tmp1 ^ tmp2);
874              break;
875            case JBIG2_COMPOSE_REPLACE:
876              tmp = tmp1;
877              break;
878          }
879          dp[0] = (uint8_t)(tmp >> 24);
880          dp[1] = (uint8_t)(tmp >> 16);
881          dp[2] = (uint8_t)(tmp >> 8);
882          dp[3] = (uint8_t)tmp;
883          sp += 4;
884          dp += 4;
885        }
886        if (d2 != 0) {
887          tmp1 =
888              (JBIG2_GETDWORD(sp) << shift1) |
889              (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >>
890               shift2);
891          tmp2 = JBIG2_GETDWORD(dp);
892          switch (op) {
893            case JBIG2_COMPOSE_OR:
894              tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
895              break;
896            case JBIG2_COMPOSE_AND:
897              tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
898              break;
899            case JBIG2_COMPOSE_XOR:
900              tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
901              break;
902            case JBIG2_COMPOSE_XNOR:
903              tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
904              break;
905            case JBIG2_COMPOSE_REPLACE:
906              tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
907              break;
908          }
909          dp[0] = (uint8_t)(tmp >> 24);
910          dp[1] = (uint8_t)(tmp >> 16);
911          dp[2] = (uint8_t)(tmp >> 8);
912          dp[3] = (uint8_t)tmp;
913        }
914        lineSrc += m_nStride;
915        lineDst += pDst->m_nStride;
916      }
917    } else if (s1 == d1) {
918      middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
919      for (yy = yd0; yy < yd1; yy++) {
920        sp = lineSrc;
921        dp = lineDst;
922        if (d1 != 0) {
923          tmp1 = JBIG2_GETDWORD(sp);
924          tmp2 = JBIG2_GETDWORD(dp);
925          switch (op) {
926            case JBIG2_COMPOSE_OR:
927              tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
928              break;
929            case JBIG2_COMPOSE_AND:
930              tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
931              break;
932            case JBIG2_COMPOSE_XOR:
933              tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
934              break;
935            case JBIG2_COMPOSE_XNOR:
936              tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
937              break;
938            case JBIG2_COMPOSE_REPLACE:
939              tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
940              break;
941          }
942          dp[0] = (uint8_t)(tmp >> 24);
943          dp[1] = (uint8_t)(tmp >> 16);
944          dp[2] = (uint8_t)(tmp >> 8);
945          dp[3] = (uint8_t)tmp;
946          sp += 4;
947          dp += 4;
948        }
949        for (xx = 0; xx < middleDwords; xx++) {
950          tmp1 = JBIG2_GETDWORD(sp);
951          tmp2 = JBIG2_GETDWORD(dp);
952          switch (op) {
953            case JBIG2_COMPOSE_OR:
954              tmp = tmp1 | tmp2;
955              break;
956            case JBIG2_COMPOSE_AND:
957              tmp = tmp1 & tmp2;
958              break;
959            case JBIG2_COMPOSE_XOR:
960              tmp = tmp1 ^ tmp2;
961              break;
962            case JBIG2_COMPOSE_XNOR:
963              tmp = ~(tmp1 ^ tmp2);
964              break;
965            case JBIG2_COMPOSE_REPLACE:
966              tmp = tmp1;
967              break;
968          }
969          dp[0] = (uint8_t)(tmp >> 24);
970          dp[1] = (uint8_t)(tmp >> 16);
971          dp[2] = (uint8_t)(tmp >> 8);
972          dp[3] = (uint8_t)tmp;
973          sp += 4;
974          dp += 4;
975        }
976        if (d2 != 0) {
977          tmp1 = JBIG2_GETDWORD(sp);
978          tmp2 = JBIG2_GETDWORD(dp);
979          switch (op) {
980            case JBIG2_COMPOSE_OR:
981              tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
982              break;
983            case JBIG2_COMPOSE_AND:
984              tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
985              break;
986            case JBIG2_COMPOSE_XOR:
987              tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
988              break;
989            case JBIG2_COMPOSE_XNOR:
990              tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
991              break;
992            case JBIG2_COMPOSE_REPLACE:
993              tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
994              break;
995          }
996          dp[0] = (uint8_t)(tmp >> 24);
997          dp[1] = (uint8_t)(tmp >> 16);
998          dp[2] = (uint8_t)(tmp >> 8);
999          dp[3] = (uint8_t)tmp;
1000        }
1001        lineSrc += m_nStride;
1002        lineDst += pDst->m_nStride;
1003      }
1004    } else {
1005      shift1 = d1 - s1;
1006      shift2 = 32 - shift1;
1007      middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5);
1008      for (yy = yd0; yy < yd1; yy++) {
1009        sp = lineSrc;
1010        dp = lineDst;
1011        if (d1 != 0) {
1012          tmp1 = JBIG2_GETDWORD(sp) >> shift1;
1013          tmp2 = JBIG2_GETDWORD(dp);
1014          switch (op) {
1015            case JBIG2_COMPOSE_OR:
1016              tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL);
1017              break;
1018            case JBIG2_COMPOSE_AND:
1019              tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL);
1020              break;
1021            case JBIG2_COMPOSE_XOR:
1022              tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL);
1023              break;
1024            case JBIG2_COMPOSE_XNOR:
1025              tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL);
1026              break;
1027            case JBIG2_COMPOSE_REPLACE:
1028              tmp = (tmp2 & ~maskL) | (tmp1 & maskL);
1029              break;
1030          }
1031          dp[0] = (uint8_t)(tmp >> 24);
1032          dp[1] = (uint8_t)(tmp >> 16);
1033          dp[2] = (uint8_t)(tmp >> 8);
1034          dp[3] = (uint8_t)tmp;
1035          dp += 4;
1036        }
1037        for (xx = 0; xx < middleDwords; xx++) {
1038          tmp1 = (JBIG2_GETDWORD(sp) << shift2) |
1039                 ((JBIG2_GETDWORD(sp + 4)) >> shift1);
1040          tmp2 = JBIG2_GETDWORD(dp);
1041          switch (op) {
1042            case JBIG2_COMPOSE_OR:
1043              tmp = tmp1 | tmp2;
1044              break;
1045            case JBIG2_COMPOSE_AND:
1046              tmp = tmp1 & tmp2;
1047              break;
1048            case JBIG2_COMPOSE_XOR:
1049              tmp = tmp1 ^ tmp2;
1050              break;
1051            case JBIG2_COMPOSE_XNOR:
1052              tmp = ~(tmp1 ^ tmp2);
1053              break;
1054            case JBIG2_COMPOSE_REPLACE:
1055              tmp = tmp1;
1056              break;
1057          }
1058          dp[0] = (uint8_t)(tmp >> 24);
1059          dp[1] = (uint8_t)(tmp >> 16);
1060          dp[2] = (uint8_t)(tmp >> 8);
1061          dp[3] = (uint8_t)tmp;
1062          sp += 4;
1063          dp += 4;
1064        }
1065        if (d2 != 0) {
1066          tmp1 =
1067              (JBIG2_GETDWORD(sp) << shift2) |
1068              (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >>
1069               shift1);
1070          tmp2 = JBIG2_GETDWORD(dp);
1071          switch (op) {
1072            case JBIG2_COMPOSE_OR:
1073              tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR);
1074              break;
1075            case JBIG2_COMPOSE_AND:
1076              tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR);
1077              break;
1078            case JBIG2_COMPOSE_XOR:
1079              tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR);
1080              break;
1081            case JBIG2_COMPOSE_XNOR:
1082              tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR);
1083              break;
1084            case JBIG2_COMPOSE_REPLACE:
1085              tmp = (tmp2 & ~maskR) | (tmp1 & maskR);
1086              break;
1087          }
1088          dp[0] = (uint8_t)(tmp >> 24);
1089          dp[1] = (uint8_t)(tmp >> 16);
1090          dp[2] = (uint8_t)(tmp >> 8);
1091          dp[3] = (uint8_t)tmp;
1092        }
1093        lineSrc += m_nStride;
1094        lineDst += pDst->m_nStride;
1095      }
1096    }
1097  }
1098  return 1;
1099}
1100