// Copyright 2017 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/fxge/dib/cstretchengine.h" #include #include #include "core/fxcrt/pauseindicator_iface.h" #include "core/fxge/dib/cfx_dibitmap.h" #include "core/fxge/dib/cfx_dibsource.h" #include "core/fxge/dib/ifx_scanlinecomposer.h" #include "core/fxge/fx_dib.h" namespace { const int kMaxDestValue = 16711680; } // namespace CStretchEngine::CWeightTable::CWeightTable() : m_DestMin(0), m_ItemSize(0), m_dwWeightTablesSize(0) {} CStretchEngine::CWeightTable::~CWeightTable() {} size_t CStretchEngine::CWeightTable::GetPixelWeightSize() const { return m_ItemSize / sizeof(int) - 2; } bool CStretchEngine::CWeightTable::Calc(int dest_len, int dest_min, int dest_max, int src_len, int src_min, int src_max, int flags) { m_WeightTables.clear(); m_dwWeightTablesSize = 0; const double scale = static_cast(src_len) / dest_len; const double base = dest_len < 0 ? src_len : 0; const int ext_size = flags & FXDIB_BICUBIC_INTERPOL ? 3 : 1; m_ItemSize = sizeof(int) * 2 + static_cast(sizeof(int) * (ceil(fabs(static_cast(scale))) + ext_size)); m_DestMin = dest_min; if (dest_max - dest_min > static_cast((1U << 30) - 4) / m_ItemSize) return false; m_dwWeightTablesSize = (dest_max - dest_min) * m_ItemSize + 4; m_WeightTables.resize(m_dwWeightTablesSize); if ((flags & FXDIB_NOSMOOTH) != 0 || fabs(static_cast(scale)) < 1.0f) { for (int dest_pixel = dest_min; dest_pixel < dest_max; ++dest_pixel) { PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel); double src_pos = dest_pixel * scale + scale / 2 + base; if (flags & FXDIB_INTERPOL) { pixel_weights.m_SrcStart = static_cast(floor(static_cast(src_pos) - 1.0f / 2)); pixel_weights.m_SrcEnd = static_cast(floor(static_cast(src_pos) + 1.0f / 2)); pixel_weights.m_SrcStart = std::max(pixel_weights.m_SrcStart, src_min); pixel_weights.m_SrcEnd = std::min(pixel_weights.m_SrcEnd, src_max - 1); if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) { pixel_weights.m_Weights[0] = 65536; } else { pixel_weights.m_Weights[1] = FXSYS_round(static_cast( src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * 65536); pixel_weights.m_Weights[0] = 65536 - pixel_weights.m_Weights[1]; } } else if (flags & FXDIB_BICUBIC_INTERPOL) { pixel_weights.m_SrcStart = static_cast(floor(static_cast(src_pos) - 1.0f / 2)); pixel_weights.m_SrcEnd = static_cast(floor(static_cast(src_pos) + 1.0f / 2)); int start = pixel_weights.m_SrcStart - 1; int end = pixel_weights.m_SrcEnd + 1; start = std::max(start, src_min); end = std::min(end, src_max - 1); if (pixel_weights.m_SrcStart < src_min) { src_pos += src_min - pixel_weights.m_SrcStart; pixel_weights.m_SrcStart = src_min; } pixel_weights.m_SrcEnd = std::min(pixel_weights.m_SrcEnd, src_max - 1); int weight = FXSYS_round( static_cast(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * 256); if (start == end) { pixel_weights.m_Weights[0] = (SDP_Table[256 + weight] + SDP_Table[weight] + SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8; } else if ((start == pixel_weights.m_SrcStart && (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd || end == pixel_weights.m_SrcEnd) && start < end) || (start < pixel_weights.m_SrcStart && pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd && end == pixel_weights.m_SrcEnd)) { if (start < pixel_weights.m_SrcStart) { pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8; pixel_weights.m_Weights[1] = (SDP_Table[weight] + SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8; } else { if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) { pixel_weights.m_Weights[0] = (SDP_Table[256 + weight] + SDP_Table[weight] + SDP_Table[256 - weight]) << 8; pixel_weights.m_Weights[1] = SDP_Table[512 - weight] << 8; } else { pixel_weights.m_Weights[0] = (SDP_Table[256 + weight] + SDP_Table[weight]) << 8; pixel_weights.m_Weights[1] = (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8; } } if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) { pixel_weights.m_SrcEnd = end; } if (start < pixel_weights.m_SrcStart) { pixel_weights.m_SrcStart = start; } } else if (start == pixel_weights.m_SrcStart && start < pixel_weights.m_SrcEnd && pixel_weights.m_SrcEnd < end) { pixel_weights.m_Weights[0] = (SDP_Table[256 + weight] + SDP_Table[weight]) << 8; pixel_weights.m_Weights[1] = SDP_Table[256 - weight] << 8; pixel_weights.m_Weights[2] = SDP_Table[512 - weight] << 8; pixel_weights.m_SrcEnd = end; } else if (start < pixel_weights.m_SrcStart && pixel_weights.m_SrcStart < pixel_weights.m_SrcEnd && pixel_weights.m_SrcEnd == end) { pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8; pixel_weights.m_Weights[1] = SDP_Table[weight] << 8; pixel_weights.m_Weights[2] = (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8; pixel_weights.m_SrcStart = start; } else { pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8; pixel_weights.m_Weights[1] = SDP_Table[weight] << 8; pixel_weights.m_Weights[2] = SDP_Table[256 - weight] << 8; pixel_weights.m_Weights[3] = SDP_Table[512 - weight] << 8; pixel_weights.m_SrcStart = start; pixel_weights.m_SrcEnd = end; } } else { int pixel_pos = static_cast(floor(static_cast(src_pos))); pixel_weights.m_SrcStart = std::max(pixel_pos, src_min); pixel_weights.m_SrcEnd = std::min(pixel_pos, src_max - 1); pixel_weights.m_Weights[0] = 65536; } } return true; } for (int dest_pixel = dest_min; dest_pixel < dest_max; ++dest_pixel) { PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel); double src_start = dest_pixel * scale + base; double src_end = src_start + scale; int start_i = floor(std::min(src_start, src_end)); int end_i = floor(std::max(src_start, src_end)); start_i = std::max(start_i, src_min); end_i = std::min(end_i, src_max - 1); if (start_i > end_i) { start_i = std::min(start_i, src_max - 1); pixel_weights.m_SrcStart = start_i; pixel_weights.m_SrcEnd = start_i; continue; } pixel_weights.m_SrcStart = start_i; pixel_weights.m_SrcEnd = end_i; for (int j = start_i; j <= end_i; ++j) { double dest_start = (j - base) / scale; double dest_end = (j + 1 - base) / scale; if (dest_start > dest_end) std::swap(dest_start, dest_end); double area_start = std::max(dest_start, static_cast(dest_pixel)); double area_end = std::min(dest_end, static_cast(dest_pixel + 1)); double weight = std::max(0.0, area_end - area_start); if (weight == 0 && j == end_i) { --pixel_weights.m_SrcEnd; break; } size_t idx = j - start_i; if (idx >= GetPixelWeightSize()) return false; pixel_weights.m_Weights[idx] = FXSYS_round(weight * 65536); } } return true; } PixelWeight* CStretchEngine::CWeightTable::GetPixelWeight(int pixel) const { ASSERT(pixel >= m_DestMin); return reinterpret_cast(const_cast( m_WeightTables.data() + (pixel - m_DestMin) * m_ItemSize)); } int* CStretchEngine::CWeightTable::GetValueFromPixelWeight(PixelWeight* pWeight, int index) const { if (index < pWeight->m_SrcStart) return nullptr; size_t idx = index - pWeight->m_SrcStart; return idx < GetPixelWeightSize() ? &pWeight->m_Weights[idx] : nullptr; } CStretchEngine::CStretchEngine(IFX_ScanlineComposer* pDestBitmap, FXDIB_Format dest_format, int dest_width, int dest_height, const FX_RECT& clip_rect, const RetainPtr& pSrcBitmap, int flags) { m_State = 0; m_DestFormat = dest_format; m_DestBpp = dest_format & 0xff; m_SrcBpp = pSrcBitmap->GetFormat() & 0xff; m_bHasAlpha = pSrcBitmap->GetFormat() & 0x200; m_pSrcPalette = pSrcBitmap->GetPalette(); m_pDestBitmap = pDestBitmap; m_DestWidth = dest_width; m_DestHeight = dest_height; m_DestClip = clip_rect; uint32_t size = clip_rect.Width(); if (size && m_DestBpp > static_cast(INT_MAX / size)) return; size *= m_DestBpp; if (size > INT_MAX - 31) return; size += 31; size = size / 32 * 4; m_DestScanline.resize(size); if (dest_format == FXDIB_Rgb32) std::fill(m_DestScanline.begin(), m_DestScanline.end(), 255); m_InterPitch = (m_DestClip.Width() * m_DestBpp + 31) / 32 * 4; m_ExtraMaskPitch = (m_DestClip.Width() * 8 + 31) / 32 * 4; m_pSource = pSrcBitmap; m_SrcWidth = pSrcBitmap->GetWidth(); m_SrcHeight = pSrcBitmap->GetHeight(); m_SrcPitch = (m_SrcWidth * m_SrcBpp + 31) / 32 * 4; if ((flags & FXDIB_NOSMOOTH) == 0) { bool bInterpol = flags & FXDIB_INTERPOL || flags & FXDIB_BICUBIC_INTERPOL; if (!bInterpol && abs(dest_width) != 0 && abs(dest_height) / 8 < static_cast(m_SrcWidth) * m_SrcHeight / abs(dest_width)) { flags = FXDIB_INTERPOL; } m_Flags = flags; } else { m_Flags = FXDIB_NOSMOOTH; if (flags & FXDIB_DOWNSAMPLE) m_Flags |= FXDIB_DOWNSAMPLE; } double scale_x = static_cast(m_SrcWidth) / m_DestWidth; double scale_y = static_cast(m_SrcHeight) / m_DestHeight; double base_x = m_DestWidth > 0 ? 0.0f : m_DestWidth; double base_y = m_DestHeight > 0 ? 0.0f : m_DestHeight; double src_left = scale_x * (clip_rect.left + base_x); double src_right = scale_x * (clip_rect.right + base_x); double src_top = scale_y * (clip_rect.top + base_y); double src_bottom = scale_y * (clip_rect.bottom + base_y); if (src_left > src_right) std::swap(src_left, src_right); if (src_top > src_bottom) std::swap(src_top, src_bottom); m_SrcClip.left = static_cast(floor(src_left)); m_SrcClip.right = static_cast(ceil(src_right)); m_SrcClip.top = static_cast(floor(src_top)); m_SrcClip.bottom = static_cast(ceil(src_bottom)); FX_RECT src_rect(0, 0, m_SrcWidth, m_SrcHeight); m_SrcClip.Intersect(src_rect); if (m_SrcBpp == 1) { if (m_DestBpp == 8) m_TransMethod = 1; else m_TransMethod = 2; } else if (m_SrcBpp == 8) { if (m_DestBpp == 8) { if (!m_bHasAlpha) m_TransMethod = 3; else m_TransMethod = 4; } else { if (!m_bHasAlpha) m_TransMethod = 5; else m_TransMethod = 6; } } else { if (!m_bHasAlpha) m_TransMethod = 7; else m_TransMethod = 8; } } CStretchEngine::~CStretchEngine() {} bool CStretchEngine::Continue(PauseIndicatorIface* pPause) { while (m_State == 1) { if (ContinueStretchHorz(pPause)) return true; m_State = 2; StretchVert(); } return false; } bool CStretchEngine::StartStretchHorz() { if (m_DestWidth == 0 || m_InterPitch == 0 || m_DestScanline.empty()) return false; if (m_SrcClip.Height() == 0 || m_SrcClip.Height() > (1 << 29) / m_InterPitch) { return false; } m_InterBuf.resize(m_SrcClip.Height() * m_InterPitch); if (m_pSource && m_bHasAlpha && m_pSource->m_pAlphaMask) { m_ExtraAlphaBuf.resize(m_SrcClip.Height(), m_ExtraMaskPitch); uint32_t size = (m_DestClip.Width() * 8 + 31) / 32 * 4; m_DestMaskScanline.resize(size); } bool ret = m_WeightTable.Calc(m_DestWidth, m_DestClip.left, m_DestClip.right, m_SrcWidth, m_SrcClip.left, m_SrcClip.right, m_Flags); if (!ret) return false; m_CurRow = m_SrcClip.top; m_State = 1; return true; } bool CStretchEngine::ContinueStretchHorz(PauseIndicatorIface* pPause) { if (!m_DestWidth) return false; if (m_pSource->SkipToScanline(m_CurRow, pPause)) return true; int Bpp = m_DestBpp / 8; static const int kStrechPauseRows = 10; int rows_to_go = kStrechPauseRows; for (; m_CurRow < m_SrcClip.bottom; ++m_CurRow) { if (rows_to_go == 0) { if (pPause && pPause->NeedToPauseNow()) return true; rows_to_go = kStrechPauseRows; } const uint8_t* src_scan = m_pSource->GetScanline(m_CurRow); uint8_t* dest_scan = m_InterBuf.data() + (m_CurRow - m_SrcClip.top) * m_InterPitch; const uint8_t* src_scan_mask = nullptr; uint8_t* dest_scan_mask = nullptr; if (!m_ExtraAlphaBuf.empty()) { src_scan_mask = m_pSource->m_pAlphaMask->GetScanline(m_CurRow); dest_scan_mask = m_ExtraAlphaBuf.data() + (m_CurRow - m_SrcClip.top) * m_ExtraMaskPitch; } // TODO(npm): reduce duplicated code here switch (m_TransMethod) { case 1: case 2: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col); int dest_a = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return false; int pixel_weight = *pWeight; if (src_scan[j / 8] & (1 << (7 - j % 8))) dest_a += pixel_weight * 255; } if (m_Flags & FXDIB_BICUBIC_INTERPOL) dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue); *dest_scan++ = static_cast(dest_a >> 16); } break; } case 3: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col); int dest_a = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return false; int pixel_weight = *pWeight; dest_a += pixel_weight * src_scan[j]; } if (m_Flags & FXDIB_BICUBIC_INTERPOL) dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue); *dest_scan++ = static_cast(dest_a >> 16); } break; } case 4: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col); int dest_a = 0; int dest_r = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return false; int pixel_weight = *pWeight; pixel_weight = pixel_weight * src_scan_mask[j] / 255; dest_r += pixel_weight * src_scan[j]; dest_a += pixel_weight; } if (m_Flags & FXDIB_BICUBIC_INTERPOL) { dest_r = pdfium::clamp(dest_r, 0, kMaxDestValue); dest_a = pdfium::clamp(dest_a, 0, 65536); } *dest_scan++ = static_cast(dest_r >> 16); *dest_scan_mask++ = static_cast((dest_a * 255) >> 16); } break; } case 5: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col); int dest_r_y = 0; int dest_g_m = 0; int dest_b_c = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return false; int pixel_weight = *pWeight; unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]]; if (m_DestFormat == FXDIB_Rgb) { dest_r_y += pixel_weight * static_cast(argb_cmyk >> 16); dest_g_m += pixel_weight * static_cast(argb_cmyk >> 8); dest_b_c += pixel_weight * static_cast(argb_cmyk); } else { dest_b_c += pixel_weight * static_cast(argb_cmyk >> 24); dest_g_m += pixel_weight * static_cast(argb_cmyk >> 16); dest_r_y += pixel_weight * static_cast(argb_cmyk >> 8); } } if (m_Flags & FXDIB_BICUBIC_INTERPOL) { dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue); dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue); dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue); } *dest_scan++ = static_cast(dest_b_c >> 16); *dest_scan++ = static_cast(dest_g_m >> 16); *dest_scan++ = static_cast(dest_r_y >> 16); } break; } case 6: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col); int dest_a = 0; int dest_r_y = 0; int dest_g_m = 0; int dest_b_c = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return false; int pixel_weight = *pWeight; pixel_weight = pixel_weight * src_scan_mask[j] / 255; unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]]; if (m_DestFormat == FXDIB_Rgba) { dest_r_y += pixel_weight * static_cast(argb_cmyk >> 16); dest_g_m += pixel_weight * static_cast(argb_cmyk >> 8); dest_b_c += pixel_weight * static_cast(argb_cmyk); } else { dest_b_c += pixel_weight * static_cast(argb_cmyk >> 24); dest_g_m += pixel_weight * static_cast(argb_cmyk >> 16); dest_r_y += pixel_weight * static_cast(argb_cmyk >> 8); } dest_a += pixel_weight; } if (m_Flags & FXDIB_BICUBIC_INTERPOL) { dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue); dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue); dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue); dest_a = pdfium::clamp(dest_a, 0, 65536); } *dest_scan++ = static_cast(dest_b_c >> 16); *dest_scan++ = static_cast(dest_g_m >> 16); *dest_scan++ = static_cast(dest_r_y >> 16); *dest_scan_mask++ = static_cast((dest_a * 255) >> 16); } break; } case 7: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col); int dest_r_y = 0; int dest_g_m = 0; int dest_b_c = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return false; int pixel_weight = *pWeight; const uint8_t* src_pixel = src_scan + j * Bpp; dest_b_c += pixel_weight * (*src_pixel++); dest_g_m += pixel_weight * (*src_pixel++); dest_r_y += pixel_weight * (*src_pixel); } if (m_Flags & FXDIB_BICUBIC_INTERPOL) { dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue); dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue); dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue); } *dest_scan++ = static_cast((dest_b_c) >> 16); *dest_scan++ = static_cast((dest_g_m) >> 16); *dest_scan++ = static_cast((dest_r_y) >> 16); dest_scan += Bpp - 3; } break; } case 8: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col); int dest_a = 0; int dest_r_y = 0; int dest_g_m = 0; int dest_b_c = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return false; int pixel_weight = *pWeight; const uint8_t* src_pixel = src_scan + j * Bpp; if (m_DestFormat == FXDIB_Argb) { pixel_weight = pixel_weight * src_pixel[3] / 255; } else { pixel_weight = pixel_weight * src_scan_mask[j] / 255; } dest_b_c += pixel_weight * (*src_pixel++); dest_g_m += pixel_weight * (*src_pixel++); dest_r_y += pixel_weight * (*src_pixel); dest_a += pixel_weight; } if (m_Flags & FXDIB_BICUBIC_INTERPOL) { dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue); dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue); dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue); dest_a = pdfium::clamp(dest_a, 0, 65536); } *dest_scan++ = static_cast((dest_b_c) >> 16); *dest_scan++ = static_cast((dest_g_m) >> 16); *dest_scan++ = static_cast((dest_r_y) >> 16); if (m_DestFormat == FXDIB_Argb) *dest_scan = static_cast((dest_a * 255) >> 16); if (dest_scan_mask) *dest_scan_mask++ = static_cast((dest_a * 255) >> 16); dest_scan += Bpp - 3; } break; } } rows_to_go--; } return false; } void CStretchEngine::StretchVert() { if (m_DestHeight == 0) return; CWeightTable table; bool ret = table.Calc(m_DestHeight, m_DestClip.top, m_DestClip.bottom, m_SrcHeight, m_SrcClip.top, m_SrcClip.bottom, m_Flags); if (!ret) return; const int DestBpp = m_DestBpp / 8; for (int row = m_DestClip.top; row < m_DestClip.bottom; ++row) { unsigned char* dest_scan = m_DestScanline.data(); unsigned char* dest_scan_mask = m_DestMaskScanline.data(); PixelWeight* pWeights = table.GetPixelWeight(row); switch (m_TransMethod) { case 1: case 2: case 3: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { unsigned char* src_scan = m_InterBuf.data() + (col - m_DestClip.left) * DestBpp; int dest_a = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = table.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return; int pixel_weight = *pWeight; dest_a += pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch]; } if (m_Flags & FXDIB_BICUBIC_INTERPOL) dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue); *dest_scan = static_cast(dest_a >> 16); dest_scan += DestBpp; } break; } case 4: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { unsigned char* src_scan = m_InterBuf.data() + (col - m_DestClip.left) * DestBpp; unsigned char* src_scan_mask = m_ExtraAlphaBuf.data() + (col - m_DestClip.left); int dest_a = 0; int dest_k = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = table.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return; int pixel_weight = *pWeight; dest_k += pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch]; dest_a += pixel_weight * src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch]; } if (m_Flags & FXDIB_BICUBIC_INTERPOL) { dest_k = pdfium::clamp(dest_k, 0, kMaxDestValue); dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue); } *dest_scan = static_cast(dest_k >> 16); dest_scan += DestBpp; *dest_scan_mask++ = static_cast(dest_a >> 16); } break; } case 5: case 7: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { unsigned char* src_scan = m_InterBuf.data() + (col - m_DestClip.left) * DestBpp; int dest_r_y = 0; int dest_g_m = 0; int dest_b_c = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = table.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return; int pixel_weight = *pWeight; const uint8_t* src_pixel = src_scan + (j - m_SrcClip.top) * m_InterPitch; dest_b_c += pixel_weight * (*src_pixel++); dest_g_m += pixel_weight * (*src_pixel++); dest_r_y += pixel_weight * (*src_pixel); } if (m_Flags & FXDIB_BICUBIC_INTERPOL) { dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue); dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue); dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue); } dest_scan[0] = static_cast((dest_b_c) >> 16); dest_scan[1] = static_cast((dest_g_m) >> 16); dest_scan[2] = static_cast((dest_r_y) >> 16); dest_scan += DestBpp; } break; } case 6: case 8: { for (int col = m_DestClip.left; col < m_DestClip.right; ++col) { unsigned char* src_scan = m_InterBuf.data() + (col - m_DestClip.left) * DestBpp; unsigned char* src_scan_mask = nullptr; if (m_DestFormat != FXDIB_Argb) src_scan_mask = m_ExtraAlphaBuf.data() + (col - m_DestClip.left); int dest_a = 0; int dest_r_y = 0; int dest_g_m = 0; int dest_b_c = 0; for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) { int* pWeight = table.GetValueFromPixelWeight(pWeights, j); if (!pWeight) return; int pixel_weight = *pWeight; const uint8_t* src_pixel = src_scan + (j - m_SrcClip.top) * m_InterPitch; int mask_v = 255; if (src_scan_mask) mask_v = src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch]; dest_b_c += pixel_weight * (*src_pixel++); dest_g_m += pixel_weight * (*src_pixel++); dest_r_y += pixel_weight * (*src_pixel); if (m_DestFormat == FXDIB_Argb) dest_a += pixel_weight * (*(src_pixel + 1)); else dest_a += pixel_weight * mask_v; } if (m_Flags & FXDIB_BICUBIC_INTERPOL) { dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue); dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue); dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue); dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue); } if (dest_a) { int r = static_cast(dest_r_y) * 255 / dest_a; int g = static_cast(dest_g_m) * 255 / dest_a; int b = static_cast(dest_b_c) * 255 / dest_a; dest_scan[0] = pdfium::clamp(b, 0, 255); dest_scan[1] = pdfium::clamp(g, 0, 255); dest_scan[2] = pdfium::clamp(r, 0, 255); } if (m_DestFormat == FXDIB_Argb) dest_scan[3] = static_cast((dest_a) >> 16); else *dest_scan_mask = static_cast((dest_a) >> 16); dest_scan += DestBpp; if (dest_scan_mask) dest_scan_mask++; } break; } } m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_DestScanline.data(), m_DestMaskScanline.data()); } }