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