// Copyright 2014 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "core/fxcodec/jbig2/JBig2_Image.h" #include <limits.h> #include <algorithm> #include <memory> #include "core/fxcrt/fx_coordinates.h" #include "core/fxcrt/fx_memory.h" #include "core/fxcrt/fx_safe_types.h" #include "third_party/base/ptr_util.h" namespace { const int kMaxImagePixels = INT_MAX - 31; const int kMaxImageBytes = kMaxImagePixels / 8; } // namespace CJBig2_Image::CJBig2_Image(int32_t w, int32_t h) : m_pData(nullptr), m_nWidth(0), m_nHeight(0), m_nStride(0) { if (w <= 0 || h <= 0 || w > kMaxImagePixels) return; int32_t stride_pixels = (w + 31) & ~31; if (h > kMaxImagePixels / stride_pixels) return; m_nWidth = w; m_nHeight = h; m_nStride = stride_pixels / 8; m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>( FX_Alloc2D(uint8_t, m_nStride, m_nHeight))); } CJBig2_Image::CJBig2_Image(int32_t w, int32_t h, int32_t stride, uint8_t* pBuf) : m_pData(nullptr), m_nWidth(0), m_nHeight(0), m_nStride(0) { if (w < 0 || h < 0 || stride < 0 || stride > kMaxImageBytes) return; int32_t stride_pixels = 8 * stride; if (stride_pixels < w || h > kMaxImagePixels / stride_pixels) return; m_nWidth = w; m_nHeight = h; m_nStride = stride; m_pData.Reset(pBuf); } CJBig2_Image::CJBig2_Image(const CJBig2_Image& other) : m_pData(nullptr), m_nWidth(other.m_nWidth), m_nHeight(other.m_nHeight), m_nStride(other.m_nStride) { if (other.m_pData) { m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>( FX_Alloc2D(uint8_t, m_nStride, m_nHeight))); JBIG2_memcpy(data(), other.data(), m_nStride * m_nHeight); } } CJBig2_Image::~CJBig2_Image() {} int CJBig2_Image::getPixel(int32_t x, int32_t y) const { if (!m_pData) return 0; if (x < 0 || x >= m_nWidth) return 0; if (y < 0 || y >= m_nHeight) return 0; int32_t m = y * m_nStride + (x >> 3); int32_t n = x & 7; return ((data()[m] >> (7 - n)) & 1); } int32_t CJBig2_Image::setPixel(int32_t x, int32_t y, int v) { if (!m_pData) return 0; if (x < 0 || x >= m_nWidth) return 0; if (y < 0 || y >= m_nHeight) return 0; int32_t m = y * m_nStride + (x >> 3); int32_t n = x & 7; if (v) data()[m] |= 1 << (7 - n); else data()[m] &= ~(1 << (7 - n)); return 1; } void CJBig2_Image::copyLine(int32_t hTo, int32_t hFrom) { if (!m_pData) return; if (hFrom < 0 || hFrom >= m_nHeight) { JBIG2_memset(data() + hTo * m_nStride, 0, m_nStride); } else { JBIG2_memcpy(data() + hTo * m_nStride, data() + hFrom * m_nStride, m_nStride); } } void CJBig2_Image::fill(bool v) { if (!m_pData) return; JBIG2_memset(data(), v ? 0xff : 0, m_nStride * m_nHeight); } bool CJBig2_Image::composeTo(CJBig2_Image* pDst, int32_t x, int32_t y, JBig2ComposeOp op) { if (!m_pData) return false; return composeTo_opt2(pDst, x, y, op); } bool CJBig2_Image::composeTo(CJBig2_Image* pDst, int32_t x, int32_t y, JBig2ComposeOp op, const FX_RECT* pSrcRect) { if (!m_pData) return false; if (!pSrcRect || *pSrcRect == FX_RECT(0, 0, m_nWidth, m_nHeight)) return composeTo_opt2(pDst, x, y, op); return composeTo_opt2(pDst, x, y, op, pSrcRect); } bool CJBig2_Image::composeFrom(int32_t x, int32_t y, CJBig2_Image* pSrc, JBig2ComposeOp op) { if (!m_pData) return false; return pSrc->composeTo(this, x, y, op); } bool CJBig2_Image::composeFrom(int32_t x, int32_t y, CJBig2_Image* pSrc, JBig2ComposeOp op, const FX_RECT* pSrcRect) { return m_pData ? pSrc->composeTo(this, x, y, op, pSrcRect) : false; } #define JBIG2_GETDWORD(buf) \ ((uint32_t)(((buf)[0] << 24) | ((buf)[1] << 16) | ((buf)[2] << 8) | (buf)[3])) std::unique_ptr<CJBig2_Image> CJBig2_Image::subImage(int32_t x, int32_t y, int32_t w, int32_t h) { int32_t m; int32_t n; int32_t j; uint8_t* pLineSrc; uint8_t* pLineDst; uint32_t wTmp; uint8_t* pSrc; uint8_t* pSrcEnd; uint8_t* pDst; uint8_t* pDstEnd; if (w == 0 || h == 0) return nullptr; auto pImage = pdfium::MakeUnique<CJBig2_Image>(w, h); if (!m_pData) { pImage->fill(0); return pImage; } if (!pImage->m_pData) return pImage; pLineSrc = data() + m_nStride * y; pLineDst = pImage->data(); m = (x >> 5) << 2; n = x & 31; if (n == 0) { for (j = 0; j < h; j++) { pSrc = pLineSrc + m; pSrcEnd = pLineSrc + m_nStride; pDst = pLineDst; pDstEnd = pLineDst + pImage->m_nStride; for (; pDst < pDstEnd; pSrc += 4, pDst += 4) { *((uint32_t*)pDst) = *((uint32_t*)pSrc); } pLineSrc += m_nStride; pLineDst += pImage->m_nStride; } } else { for (j = 0; j < h; j++) { pSrc = pLineSrc + m; pSrcEnd = pLineSrc + m_nStride; pDst = pLineDst; pDstEnd = pLineDst + pImage->m_nStride; for (; pDst < pDstEnd; pSrc += 4, pDst += 4) { if (pSrc + 4 < pSrcEnd) { wTmp = (JBIG2_GETDWORD(pSrc) << n) | (JBIG2_GETDWORD(pSrc + 4) >> (32 - n)); } else { wTmp = JBIG2_GETDWORD(pSrc) << n; } pDst[0] = (uint8_t)(wTmp >> 24); pDst[1] = (uint8_t)(wTmp >> 16); pDst[2] = (uint8_t)(wTmp >> 8); pDst[3] = (uint8_t)wTmp; } pLineSrc += m_nStride; pLineDst += pImage->m_nStride; } } return pImage; } void CJBig2_Image::expand(int32_t h, bool v) { if (!m_pData || h <= m_nHeight || h > kMaxImageBytes / m_nStride) return; if (m_pData.IsOwned()) { m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>( FX_Realloc(uint8_t, m_pData.Release().release(), h * m_nStride))); } else { uint8_t* pExternalBuffer = data(); m_pData.Reset(std::unique_ptr<uint8_t, FxFreeDeleter>( FX_Alloc(uint8_t, h * m_nStride))); JBIG2_memcpy(data(), pExternalBuffer, m_nHeight * m_nStride); } JBIG2_memset(data() + m_nHeight * m_nStride, v ? 0xff : 0, (h - m_nHeight) * m_nStride); m_nHeight = h; } bool CJBig2_Image::composeTo_opt2(CJBig2_Image* pDst, int32_t x, int32_t y, JBig2ComposeOp op) { if (!m_pData) return false; if (x < -1048576 || x > 1048576 || y < -1048576 || y > 1048576) return false; int32_t xs0 = x < 0 ? -x : 0; int32_t xs1; FX_SAFE_INT32 iChecked = pDst->m_nWidth; iChecked -= x; if (iChecked.IsValid() && m_nWidth > iChecked.ValueOrDie()) xs1 = iChecked.ValueOrDie(); else xs1 = m_nWidth; int32_t ys0 = y < 0 ? -y : 0; int32_t ys1; iChecked = pDst->m_nHeight; iChecked -= y; if (iChecked.IsValid() && m_nHeight > iChecked.ValueOrDie()) ys1 = pDst->m_nHeight - y; else ys1 = m_nHeight; if (ys0 >= ys1 || xs0 >= xs1) return false; int32_t xd0 = std::max(x, 0); int32_t yd0 = std::max(y, 0); int32_t w = xs1 - xs0; int32_t h = ys1 - ys0; int32_t xd1 = xd0 + w; int32_t yd1 = yd0 + h; uint32_t d1 = xd0 & 31; uint32_t d2 = xd1 & 31; uint32_t s1 = xs0 & 31; uint32_t maskL = 0xffffffff >> d1; uint32_t maskR = 0xffffffff << ((32 - (xd1 & 31)) % 32); uint32_t maskM = maskL & maskR; uint8_t* lineSrc = data() + ys0 * m_nStride + ((xs0 >> 5) << 2); int32_t lineLeft = m_nStride - ((xs0 >> 5) << 2); uint8_t* lineDst = pDst->data() + yd0 * pDst->m_nStride + ((xd0 >> 5) << 2); if ((xd0 & ~31) == ((xd1 - 1) & ~31)) { if ((xs0 & ~31) == ((xs1 - 1) & ~31)) { if (s1 > d1) { uint32_t shift = s1 - d1; for (int32_t yy = yd0; yy < yd1; yy++) { uint32_t tmp1 = JBIG2_GETDWORD(lineSrc) << shift; uint32_t tmp2 = JBIG2_GETDWORD(lineDst); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskM) | (tmp1 & maskM); break; } lineDst[0] = (uint8_t)(tmp >> 24); lineDst[1] = (uint8_t)(tmp >> 16); lineDst[2] = (uint8_t)(tmp >> 8); lineDst[3] = (uint8_t)tmp; lineSrc += m_nStride; lineDst += pDst->m_nStride; } } else { uint32_t shift = d1 - s1; for (int32_t yy = yd0; yy < yd1; yy++) { uint32_t tmp1 = JBIG2_GETDWORD(lineSrc) >> shift; uint32_t tmp2 = JBIG2_GETDWORD(lineDst); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskM) | (tmp1 & maskM); break; } lineDst[0] = (uint8_t)(tmp >> 24); lineDst[1] = (uint8_t)(tmp >> 16); lineDst[2] = (uint8_t)(tmp >> 8); lineDst[3] = (uint8_t)tmp; lineSrc += m_nStride; lineDst += pDst->m_nStride; } } } else { uint32_t shift1 = s1 - d1; uint32_t shift2 = 32 - shift1; for (int32_t yy = yd0; yy < yd1; yy++) { uint32_t tmp1 = (JBIG2_GETDWORD(lineSrc) << shift1) | (JBIG2_GETDWORD(lineSrc + 4) >> shift2); uint32_t tmp2 = JBIG2_GETDWORD(lineDst); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskM) | (tmp1 & maskM); break; } lineDst[0] = (uint8_t)(tmp >> 24); lineDst[1] = (uint8_t)(tmp >> 16); lineDst[2] = (uint8_t)(tmp >> 8); lineDst[3] = (uint8_t)tmp; lineSrc += m_nStride; lineDst += pDst->m_nStride; } } } else { uint8_t* sp = nullptr; uint8_t* dp = nullptr; if (s1 > d1) { uint32_t shift1 = s1 - d1; uint32_t shift2 = 32 - shift1; int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); for (int32_t yy = yd0; yy < yd1; yy++) { sp = lineSrc; dp = lineDst; if (d1 != 0) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift1) | (JBIG2_GETDWORD(sp + 4) >> shift2); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskL) | (tmp1 & maskL); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } for (int32_t xx = 0; xx < middleDwords; xx++) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift1) | (JBIG2_GETDWORD(sp + 4) >> shift2); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = tmp1 | tmp2; break; case JBIG2_COMPOSE_AND: tmp = tmp1 & tmp2; break; case JBIG2_COMPOSE_XOR: tmp = tmp1 ^ tmp2; break; case JBIG2_COMPOSE_XNOR: tmp = ~(tmp1 ^ tmp2); break; case JBIG2_COMPOSE_REPLACE: tmp = tmp1; break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } if (d2 != 0) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift1) | (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >> shift2); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskR) | (tmp1 & maskR); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; } lineSrc += m_nStride; lineDst += pDst->m_nStride; } } else if (s1 == d1) { int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); for (int32_t yy = yd0; yy < yd1; yy++) { sp = lineSrc; dp = lineDst; if (d1 != 0) { uint32_t tmp1 = JBIG2_GETDWORD(sp); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskL) | (tmp1 & maskL); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } for (int32_t xx = 0; xx < middleDwords; xx++) { uint32_t tmp1 = JBIG2_GETDWORD(sp); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = tmp1 | tmp2; break; case JBIG2_COMPOSE_AND: tmp = tmp1 & tmp2; break; case JBIG2_COMPOSE_XOR: tmp = tmp1 ^ tmp2; break; case JBIG2_COMPOSE_XNOR: tmp = ~(tmp1 ^ tmp2); break; case JBIG2_COMPOSE_REPLACE: tmp = tmp1; break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } if (d2 != 0) { uint32_t tmp1 = JBIG2_GETDWORD(sp); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskR) | (tmp1 & maskR); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; } lineSrc += m_nStride; lineDst += pDst->m_nStride; } } else { uint32_t shift1 = d1 - s1; uint32_t shift2 = 32 - shift1; int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); for (int32_t yy = yd0; yy < yd1; yy++) { sp = lineSrc; dp = lineDst; if (d1 != 0) { uint32_t tmp1 = JBIG2_GETDWORD(sp) >> shift1; uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskL) | (tmp1 & maskL); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; dp += 4; } for (int32_t xx = 0; xx < middleDwords; xx++) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift2) | ((JBIG2_GETDWORD(sp + 4)) >> shift1); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = tmp1 | tmp2; break; case JBIG2_COMPOSE_AND: tmp = tmp1 & tmp2; break; case JBIG2_COMPOSE_XOR: tmp = tmp1 ^ tmp2; break; case JBIG2_COMPOSE_XNOR: tmp = ~(tmp1 ^ tmp2); break; case JBIG2_COMPOSE_REPLACE: tmp = tmp1; break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } if (d2 != 0) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift2) | (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >> shift1); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskR) | (tmp1 & maskR); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; } lineSrc += m_nStride; lineDst += pDst->m_nStride; } } } return true; } bool CJBig2_Image::composeTo_opt2(CJBig2_Image* pDst, int32_t x, int32_t y, JBig2ComposeOp op, const FX_RECT* pSrcRect) { if (!m_pData) return false; // TODO(weili): Check whether the range check is correct. Should x>=1048576? if (x < -1048576 || x > 1048576 || y < -1048576 || y > 1048576) { return false; } int32_t sw = pSrcRect->Width(); int32_t sh = pSrcRect->Height(); int32_t ys0 = y < 0 ? -y : 0; int32_t ys1 = y + sh > pDst->m_nHeight ? pDst->m_nHeight - y : sh; int32_t xs0 = x < 0 ? -x : 0; int32_t xs1 = x + sw > pDst->m_nWidth ? pDst->m_nWidth - x : sw; if ((ys0 >= ys1) || (xs0 >= xs1)) { return 0; } int32_t w = xs1 - xs0; int32_t h = ys1 - ys0; int32_t yd0 = y < 0 ? 0 : y; int32_t xd0 = x < 0 ? 0 : x; int32_t xd1 = xd0 + w; int32_t yd1 = yd0 + h; int32_t d1 = xd0 & 31; int32_t d2 = xd1 & 31; int32_t s1 = xs0 & 31; int32_t maskL = 0xffffffff >> d1; int32_t maskR = 0xffffffff << ((32 - (xd1 & 31)) % 32); int32_t maskM = maskL & maskR; uint8_t* lineSrc = data() + (pSrcRect->top + ys0) * m_nStride + (((xs0 + pSrcRect->left) >> 5) << 2); int32_t lineLeft = m_nStride - ((xs0 >> 5) << 2); uint8_t* lineDst = pDst->data() + yd0 * pDst->m_nStride + ((xd0 >> 5) << 2); if ((xd0 & ~31) == ((xd1 - 1) & ~31)) { if ((xs0 & ~31) == ((xs1 - 1) & ~31)) { if (s1 > d1) { uint32_t shift = s1 - d1; for (int32_t yy = yd0; yy < yd1; yy++) { uint32_t tmp1 = JBIG2_GETDWORD(lineSrc) << shift; uint32_t tmp2 = JBIG2_GETDWORD(lineDst); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskM) | (tmp1 & maskM); break; } lineDst[0] = (uint8_t)(tmp >> 24); lineDst[1] = (uint8_t)(tmp >> 16); lineDst[2] = (uint8_t)(tmp >> 8); lineDst[3] = (uint8_t)tmp; lineSrc += m_nStride; lineDst += pDst->m_nStride; } } else { uint32_t shift = d1 - s1; for (int32_t yy = yd0; yy < yd1; yy++) { uint32_t tmp1 = JBIG2_GETDWORD(lineSrc) >> shift; uint32_t tmp2 = JBIG2_GETDWORD(lineDst); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskM) | (tmp1 & maskM); break; } lineDst[0] = (uint8_t)(tmp >> 24); lineDst[1] = (uint8_t)(tmp >> 16); lineDst[2] = (uint8_t)(tmp >> 8); lineDst[3] = (uint8_t)tmp; lineSrc += m_nStride; lineDst += pDst->m_nStride; } } } else { uint32_t shift1 = s1 - d1; uint32_t shift2 = 32 - shift1; for (int32_t yy = yd0; yy < yd1; yy++) { uint32_t tmp1 = (JBIG2_GETDWORD(lineSrc) << shift1) | (JBIG2_GETDWORD(lineSrc + 4) >> shift2); uint32_t tmp2 = JBIG2_GETDWORD(lineDst); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskM) | (tmp1 & maskM); break; } lineDst[0] = (uint8_t)(tmp >> 24); lineDst[1] = (uint8_t)(tmp >> 16); lineDst[2] = (uint8_t)(tmp >> 8); lineDst[3] = (uint8_t)tmp; lineSrc += m_nStride; lineDst += pDst->m_nStride; } } } else { if (s1 > d1) { uint32_t shift1 = s1 - d1; uint32_t shift2 = 32 - shift1; int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); for (int32_t yy = yd0; yy < yd1; yy++) { uint8_t* sp = lineSrc; uint8_t* dp = lineDst; if (d1 != 0) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift1) | (JBIG2_GETDWORD(sp + 4) >> shift2); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskL) | (tmp1 & maskL); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } for (int32_t xx = 0; xx < middleDwords; xx++) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift1) | (JBIG2_GETDWORD(sp + 4) >> shift2); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = tmp1 | tmp2; break; case JBIG2_COMPOSE_AND: tmp = tmp1 & tmp2; break; case JBIG2_COMPOSE_XOR: tmp = tmp1 ^ tmp2; break; case JBIG2_COMPOSE_XNOR: tmp = ~(tmp1 ^ tmp2); break; case JBIG2_COMPOSE_REPLACE: tmp = tmp1; break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } if (d2 != 0) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift1) | (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >> shift2); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskR) | (tmp1 & maskR); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; } lineSrc += m_nStride; lineDst += pDst->m_nStride; } } else if (s1 == d1) { int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); for (int32_t yy = yd0; yy < yd1; yy++) { uint8_t* sp = lineSrc; uint8_t* dp = lineDst; if (d1 != 0) { uint32_t tmp1 = JBIG2_GETDWORD(sp); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskL) | (tmp1 & maskL); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } for (int32_t xx = 0; xx < middleDwords; xx++) { uint32_t tmp1 = JBIG2_GETDWORD(sp); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = tmp1 | tmp2; break; case JBIG2_COMPOSE_AND: tmp = tmp1 & tmp2; break; case JBIG2_COMPOSE_XOR: tmp = tmp1 ^ tmp2; break; case JBIG2_COMPOSE_XNOR: tmp = ~(tmp1 ^ tmp2); break; case JBIG2_COMPOSE_REPLACE: tmp = tmp1; break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } if (d2 != 0) { uint32_t tmp1 = JBIG2_GETDWORD(sp); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskR) | (tmp1 & maskR); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; } lineSrc += m_nStride; lineDst += pDst->m_nStride; } } else { uint32_t shift1 = d1 - s1; uint32_t shift2 = 32 - shift1; int32_t middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); for (int32_t yy = yd0; yy < yd1; yy++) { uint8_t* sp = lineSrc; uint8_t* dp = lineDst; if (d1 != 0) { uint32_t tmp1 = JBIG2_GETDWORD(sp) >> shift1; uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskL) | (tmp1 & maskL); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; dp += 4; } for (int32_t xx = 0; xx < middleDwords; xx++) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift2) | ((JBIG2_GETDWORD(sp + 4)) >> shift1); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = tmp1 | tmp2; break; case JBIG2_COMPOSE_AND: tmp = tmp1 & tmp2; break; case JBIG2_COMPOSE_XOR: tmp = tmp1 ^ tmp2; break; case JBIG2_COMPOSE_XNOR: tmp = ~(tmp1 ^ tmp2); break; case JBIG2_COMPOSE_REPLACE: tmp = tmp1; break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; sp += 4; dp += 4; } if (d2 != 0) { uint32_t tmp1 = (JBIG2_GETDWORD(sp) << shift2) | (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >> shift1); uint32_t tmp2 = JBIG2_GETDWORD(dp); uint32_t tmp = 0; switch (op) { case JBIG2_COMPOSE_OR: tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); break; case JBIG2_COMPOSE_AND: tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); break; case JBIG2_COMPOSE_XOR: tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); break; case JBIG2_COMPOSE_XNOR: tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); break; case JBIG2_COMPOSE_REPLACE: tmp = (tmp2 & ~maskR) | (tmp1 & maskR); break; } dp[0] = (uint8_t)(tmp >> 24); dp[1] = (uint8_t)(tmp >> 16); dp[2] = (uint8_t)(tmp >> 8); dp[3] = (uint8_t)tmp; } lineSrc += m_nStride; lineDst += pDst->m_nStride; } } } return 1; }