summaryrefslogtreecommitdiff
path: root/core/fxge/dib/cfx_imagestretcher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fxge/dib/cfx_imagestretcher.cpp')
-rw-r--r--core/fxge/dib/cfx_imagestretcher.cpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/core/fxge/dib/cfx_imagestretcher.cpp b/core/fxge/dib/cfx_imagestretcher.cpp
new file mode 100644
index 0000000000..799b44432f
--- /dev/null
+++ b/core/fxge/dib/cfx_imagestretcher.cpp
@@ -0,0 +1,184 @@
+// 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/cfx_imagestretcher.h"
+
+#include <climits>
+
+#include "core/fxge/dib/dib_int.h"
+#include "core/fxge/fx_dib.h"
+#include "third_party/base/ptr_util.h"
+
+namespace {
+
+bool SourceSizeWithinLimit(int width, int height) {
+ const int kMaxProgressiveStretchPixels = 1000000;
+ return !height || width < kMaxProgressiveStretchPixels / height;
+}
+
+FXDIB_Format GetStretchedFormat(const CFX_DIBSource& src) {
+ FXDIB_Format format = src.GetFormat();
+ if (format == FXDIB_1bppMask)
+ return FXDIB_8bppMask;
+ if (format == FXDIB_1bppRgb)
+ return FXDIB_8bppRgb;
+ if (format == FXDIB_8bppRgb && src.GetPalette())
+ return FXDIB_Rgb;
+ return format;
+}
+
+} // namespace
+
+CFX_ImageStretcher::CFX_ImageStretcher(
+ IFX_ScanlineComposer* pDest,
+ const CFX_RetainPtr<CFX_DIBSource>& pSource,
+ int dest_width,
+ int dest_height,
+ const FX_RECT& bitmap_rect,
+ uint32_t flags)
+ : m_pDest(pDest),
+ m_pSource(pSource),
+ m_Flags(flags),
+ m_bFlipX(false),
+ m_bFlipY(false),
+ m_DestWidth(dest_width),
+ m_DestHeight(dest_height),
+ m_ClipRect(bitmap_rect),
+ m_DestFormat(GetStretchedFormat(*pSource)),
+ m_DestBPP(m_DestFormat & 0xff),
+ m_LineIndex(0) {}
+
+CFX_ImageStretcher::~CFX_ImageStretcher() {}
+
+bool CFX_ImageStretcher::Start() {
+ if (m_DestWidth == 0 || m_DestHeight == 0)
+ return false;
+
+ if (m_pSource->GetFormat() == FXDIB_1bppRgb && m_pSource->GetPalette()) {
+ FX_ARGB pal[256];
+ int a0, r0, g0, b0, a1, r1, g1, b1;
+ ArgbDecode(m_pSource->GetPaletteEntry(0), a0, r0, g0, b0);
+ ArgbDecode(m_pSource->GetPaletteEntry(1), a1, r1, g1, b1);
+ for (int i = 0; i < 256; i++) {
+ int a = a0 + (a1 - a0) * i / 255;
+ int r = r0 + (r1 - r0) * i / 255;
+ int g = g0 + (g1 - g0) * i / 255;
+ int b = b0 + (b1 - b0) * i / 255;
+ pal[i] = ArgbEncode(a, r, g, b);
+ }
+ if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat,
+ pal)) {
+ return false;
+ }
+ } else if (m_pSource->GetFormat() == FXDIB_1bppCmyk &&
+ m_pSource->GetPalette()) {
+ FX_CMYK pal[256];
+ int c0, m0, y0, k0, c1, m1, y1, k1;
+ CmykDecode(m_pSource->GetPaletteEntry(0), c0, m0, y0, k0);
+ CmykDecode(m_pSource->GetPaletteEntry(1), c1, m1, y1, k1);
+ for (int i = 0; i < 256; i++) {
+ int c = c0 + (c1 - c0) * i / 255;
+ int m = m0 + (m1 - m0) * i / 255;
+ int y = y0 + (y1 - y0) * i / 255;
+ int k = k0 + (k1 - k0) * i / 255;
+ pal[i] = CmykEncode(c, m, y, k);
+ }
+ if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat,
+ pal)) {
+ return false;
+ }
+ } else if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(),
+ m_DestFormat, nullptr)) {
+ return false;
+ }
+
+ if (m_Flags & FXDIB_DOWNSAMPLE)
+ return StartQuickStretch();
+ return StartStretch();
+}
+
+bool CFX_ImageStretcher::Continue(IFX_Pause* pPause) {
+ if (m_Flags & FXDIB_DOWNSAMPLE)
+ return ContinueQuickStretch(pPause);
+ return ContinueStretch(pPause);
+}
+
+bool CFX_ImageStretcher::StartStretch() {
+ m_pStretchEngine = pdfium::MakeUnique<CStretchEngine>(
+ m_pDest, m_DestFormat, m_DestWidth, m_DestHeight, m_ClipRect, m_pSource,
+ m_Flags);
+ m_pStretchEngine->StartStretchHorz();
+ if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) {
+ m_pStretchEngine->Continue(nullptr);
+ return false;
+ }
+ return true;
+}
+
+bool CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause) {
+ return m_pStretchEngine && m_pStretchEngine->Continue(pPause);
+}
+
+bool CFX_ImageStretcher::StartQuickStretch() {
+ if (m_DestWidth < 0) {
+ m_bFlipX = true;
+ m_DestWidth = -m_DestWidth;
+ }
+ if (m_DestHeight < 0) {
+ m_bFlipY = true;
+ m_DestHeight = -m_DestHeight;
+ }
+ uint32_t size = m_ClipRect.Width();
+ if (size && m_DestBPP > static_cast<int>(INT_MAX / size))
+ return false;
+
+ size *= m_DestBPP;
+ m_pScanline.reset(FX_Alloc(uint8_t, (size / 8 + 3) / 4 * 4));
+ if (m_pSource->m_pAlphaMask)
+ m_pMaskScanline.reset(FX_Alloc(uint8_t, (m_ClipRect.Width() + 3) / 4 * 4));
+
+ if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) {
+ ContinueQuickStretch(nullptr);
+ return false;
+ }
+ return true;
+}
+
+bool CFX_ImageStretcher::ContinueQuickStretch(IFX_Pause* pPause) {
+ if (!m_pScanline)
+ return false;
+
+ int result_width = m_ClipRect.Width();
+ int result_height = m_ClipRect.Height();
+ int src_height = m_pSource->GetHeight();
+ for (; m_LineIndex < result_height; m_LineIndex++) {
+ int dest_y;
+ int src_y;
+ if (m_bFlipY) {
+ dest_y = result_height - m_LineIndex - 1;
+ src_y = (m_DestHeight - (dest_y + m_ClipRect.top) - 1) * src_height /
+ m_DestHeight;
+ } else {
+ dest_y = m_LineIndex;
+ src_y = (dest_y + m_ClipRect.top) * src_height / m_DestHeight;
+ }
+ src_y = pdfium::clamp(src_y, 0, src_height - 1);
+
+ if (m_pSource->SkipToScanline(src_y, pPause))
+ return true;
+
+ m_pSource->DownSampleScanline(src_y, m_pScanline.get(), m_DestBPP,
+ m_DestWidth, m_bFlipX, m_ClipRect.left,
+ result_width);
+ if (m_pMaskScanline) {
+ m_pSource->m_pAlphaMask->DownSampleScanline(
+ src_y, m_pMaskScanline.get(), 1, m_DestWidth, m_bFlipX,
+ m_ClipRect.left, result_width);
+ }
+ m_pDest->ComposeScanline(dest_y, m_pScanline.get(), m_pMaskScanline.get());
+ }
+ return false;
+}