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 "core/fxcrt/fx_safe_types.h"
10 #include "core/fxge/dib/cfx_dibbase.h"
11 #include "core/fxge/dib/cfx_dibitmap.h"
12 #include "core/fxge/dib/cstretchengine.h"
13 #include "core/fxge/dib/fx_dib.h"
14 #include "third_party/base/check.h"
15 #include "third_party/base/check_op.h"
16 #include "third_party/base/span.h"
17
18 namespace {
19
20 const int kMaxProgressiveStretchPixels = 1000000;
21
SourceSizeWithinLimit(int width,int height)22 bool SourceSizeWithinLimit(int width, int height) {
23 return !height || width < kMaxProgressiveStretchPixels / height;
24 }
25
GetStretchedFormat(const CFX_DIBBase & src)26 FXDIB_Format GetStretchedFormat(const CFX_DIBBase& src) {
27 FXDIB_Format format = src.GetFormat();
28 if (format == FXDIB_Format::k1bppMask)
29 return FXDIB_Format::k8bppMask;
30 if (format == FXDIB_Format::k1bppRgb)
31 return FXDIB_Format::k8bppRgb;
32 if (format == FXDIB_Format::k8bppRgb && src.HasPalette())
33 return FXDIB_Format::kRgb;
34 return format;
35 }
36
37 // Builds a new palette with a size of `CFX_DIBBase::kPaletteSize` from the
38 // existing palette in `source`. Note: The caller must make sure that the
39 // parameters meet the following conditions:
40 // source - The format must be `FXDIB_Format::k1bppRgb` and it must
41 // have a palette.
42 // palette_span - The size must be `CFX_DIBBase::kPaletteSize` to be able
43 // to hold the new palette.
44
BuildPaletteFrom1BppSource(const RetainPtr<const CFX_DIBBase> & source,pdfium::span<FX_ARGB> palette_span)45 void BuildPaletteFrom1BppSource(const RetainPtr<const CFX_DIBBase>& source,
46 pdfium::span<FX_ARGB> palette_span) {
47 DCHECK_EQ(FXDIB_Format::k1bppRgb, source->GetFormat());
48 DCHECK(source->HasPalette());
49 DCHECK_EQ(CFX_DIBBase::kPaletteSize, palette_span.size());
50
51 int a0;
52 int r0;
53 int g0;
54 int b0;
55 std::tie(a0, r0, g0, b0) = ArgbDecode(source->GetPaletteArgb(0));
56 int a1;
57 int r1;
58 int g1;
59 int b1;
60 std::tie(a1, r1, g1, b1) = ArgbDecode(source->GetPaletteArgb(1));
61 DCHECK_EQ(255, a0);
62 DCHECK_EQ(255, a1);
63
64 for (int i = 0; i < static_cast<int>(CFX_DIBBase::kPaletteSize); ++i) {
65 int r = r0 + (r1 - r0) * i / 255;
66 int g = g0 + (g1 - g0) * i / 255;
67 int b = b0 + (b1 - b0) * i / 255;
68 palette_span[i] = ArgbEncode(255, r, g, b);
69 }
70 }
71
72 } // namespace
73
CFX_ImageStretcher(ScanlineComposerIface * pDest,const RetainPtr<const CFX_DIBBase> & pSource,int dest_width,int dest_height,const FX_RECT & bitmap_rect,const FXDIB_ResampleOptions & options)74 CFX_ImageStretcher::CFX_ImageStretcher(
75 ScanlineComposerIface* pDest,
76 const RetainPtr<const CFX_DIBBase>& pSource,
77 int dest_width,
78 int dest_height,
79 const FX_RECT& bitmap_rect,
80 const FXDIB_ResampleOptions& options)
81 : m_pDest(pDest),
82 m_pSource(pSource),
83 m_ResampleOptions(options),
84 m_DestWidth(dest_width),
85 m_DestHeight(dest_height),
86 m_ClipRect(bitmap_rect),
87 m_DestFormat(GetStretchedFormat(*pSource)) {
88 DCHECK(m_ClipRect.Valid());
89 }
90
91 CFX_ImageStretcher::~CFX_ImageStretcher() = default;
92
Start()93 bool CFX_ImageStretcher::Start() {
94 if (m_DestWidth == 0 || m_DestHeight == 0)
95 return false;
96
97 if (m_pSource->GetFormat() == FXDIB_Format::k1bppRgb &&
98 m_pSource->HasPalette()) {
99 FX_ARGB pal[CFX_DIBBase::kPaletteSize];
100 BuildPaletteFrom1BppSource(m_pSource, pal);
101 if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat,
102 pal)) {
103 return false;
104 }
105 } else if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(),
106 m_DestFormat, {})) {
107 return false;
108 }
109 return StartStretch();
110 }
111
Continue(PauseIndicatorIface * pPause)112 bool CFX_ImageStretcher::Continue(PauseIndicatorIface* pPause) {
113 return ContinueStretch(pPause);
114 }
115
source()116 RetainPtr<const CFX_DIBBase> CFX_ImageStretcher::source() {
117 return m_pSource;
118 }
119
StartStretch()120 bool CFX_ImageStretcher::StartStretch() {
121 m_pStretchEngine = std::make_unique<CStretchEngine>(
122 m_pDest, m_DestFormat, m_DestWidth, m_DestHeight, m_ClipRect, m_pSource,
123 m_ResampleOptions);
124 m_pStretchEngine->StartStretchHorz();
125 if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) {
126 m_pStretchEngine->Continue(nullptr);
127 return false;
128 }
129 return true;
130 }
131
ContinueStretch(PauseIndicatorIface * pPause)132 bool CFX_ImageStretcher::ContinueStretch(PauseIndicatorIface* pPause) {
133 return m_pStretchEngine && m_pStretchEngine->Continue(pPause);
134 }
135