1 // Copyright 2017 The PDFium Authors
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 "core/fxge/dib/cfx_imagestretcher.h"
8
9 #include <utility>
10
11 #include "core/fxcrt/check.h"
12 #include "core/fxcrt/check_op.h"
13 #include "core/fxcrt/data_vector.h"
14 #include "core/fxcrt/fx_safe_types.h"
15 #include "core/fxcrt/span.h"
16 #include "core/fxge/dib/cfx_dibbase.h"
17 #include "core/fxge/dib/cfx_dibitmap.h"
18 #include "core/fxge/dib/cstretchengine.h"
19 #include "core/fxge/dib/fx_dib.h"
20
21 namespace {
22
23 const int kMaxProgressiveStretchPixels = 1000000;
24
SourceSizeWithinLimit(int width,int height)25 bool SourceSizeWithinLimit(int width, int height) {
26 return !height || width < kMaxProgressiveStretchPixels / height;
27 }
28
GetStretchedFormat(const CFX_DIBBase & src)29 FXDIB_Format GetStretchedFormat(const CFX_DIBBase& src) {
30 FXDIB_Format format = src.GetFormat();
31 if (format == FXDIB_Format::k1bppMask)
32 return FXDIB_Format::k8bppMask;
33 if (format == FXDIB_Format::k1bppRgb)
34 return FXDIB_Format::k8bppRgb;
35 if (format == FXDIB_Format::k8bppRgb && src.HasPalette())
36 return FXDIB_Format::kBgr;
37 return format;
38 }
39
40 // Builds a new palette with a size of `CFX_DIBBase::kPaletteSize` from the
41 // existing palette in `source`.
BuildPaletteFrom1BppSource(const RetainPtr<const CFX_DIBBase> & source)42 DataVector<uint32_t> BuildPaletteFrom1BppSource(
43 const RetainPtr<const CFX_DIBBase>& source) {
44 DCHECK_EQ(FXDIB_Format::k1bppRgb, source->GetFormat());
45 DCHECK(source->HasPalette());
46
47 const FX_BGRA_STRUCT<uint8_t> bgra0 =
48 ArgbToBGRAStruct(source->GetPaletteArgb(0));
49 const FX_BGRA_STRUCT<uint8_t> bgra1 =
50 ArgbToBGRAStruct(source->GetPaletteArgb(1));
51 CHECK_EQ(255, bgra0.alpha);
52 CHECK_EQ(255, bgra1.alpha);
53
54 DataVector<uint32_t> palette(CFX_DIBBase::kPaletteSize);
55 for (int i = 0; i < static_cast<int>(CFX_DIBBase::kPaletteSize); ++i) {
56 int r = bgra0.red + (bgra1.red - bgra0.red) * i / 255;
57 int g = bgra0.green + (bgra1.green - bgra0.green) * i / 255;
58 int b = bgra0.blue + (bgra1.blue - bgra0.blue) * i / 255;
59 palette[i] = ArgbEncode(255, r, g, b);
60 }
61 return palette;
62 }
63
64 } // namespace
65
CFX_ImageStretcher(ScanlineComposerIface * pDest,RetainPtr<const CFX_DIBBase> source,int dest_width,int dest_height,const FX_RECT & bitmap_rect,const FXDIB_ResampleOptions & options)66 CFX_ImageStretcher::CFX_ImageStretcher(ScanlineComposerIface* pDest,
67 RetainPtr<const CFX_DIBBase> source,
68 int dest_width,
69 int dest_height,
70 const FX_RECT& bitmap_rect,
71 const FXDIB_ResampleOptions& options)
72 : m_pDest(pDest),
73 m_pSource(std::move(source)),
74 m_ResampleOptions(options),
75 m_DestWidth(dest_width),
76 m_DestHeight(dest_height),
77 m_ClipRect(bitmap_rect),
78 m_DestFormat(GetStretchedFormat(*m_pSource)) {
79 DCHECK(m_ClipRect.Valid());
80 }
81
82 CFX_ImageStretcher::~CFX_ImageStretcher() = default;
83
Start()84 bool CFX_ImageStretcher::Start() {
85 if (m_DestWidth == 0 || m_DestHeight == 0)
86 return false;
87
88 if (m_pSource->GetFormat() == FXDIB_Format::k1bppRgb &&
89 m_pSource->HasPalette()) {
90 if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat,
91 BuildPaletteFrom1BppSource(m_pSource))) {
92 return false;
93 }
94 } else if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(),
95 m_DestFormat, {})) {
96 return false;
97 }
98 return StartStretch();
99 }
100
Continue(PauseIndicatorIface * pPause)101 bool CFX_ImageStretcher::Continue(PauseIndicatorIface* pPause) {
102 return ContinueStretch(pPause);
103 }
104
source()105 RetainPtr<const CFX_DIBBase> CFX_ImageStretcher::source() {
106 return m_pSource;
107 }
108
StartStretch()109 bool CFX_ImageStretcher::StartStretch() {
110 m_pStretchEngine = std::make_unique<CStretchEngine>(
111 m_pDest, m_DestFormat, m_DestWidth, m_DestHeight, m_ClipRect, m_pSource,
112 m_ResampleOptions);
113 m_pStretchEngine->StartStretchHorz();
114 if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) {
115 m_pStretchEngine->Continue(nullptr);
116 return false;
117 }
118 return true;
119 }
120
ContinueStretch(PauseIndicatorIface * pPause)121 bool CFX_ImageStretcher::ContinueStretch(PauseIndicatorIface* pPause) {
122 return m_pStretchEngine && m_pStretchEngine->Continue(pPause);
123 }
124