1 // Copyright 2016 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/fpdfapi/page/cpdf_transferfuncdib.h"
8
9 #include <utility>
10
11 #include "build/build_config.h"
12 #include "core/fpdfapi/page/cpdf_transferfunc.h"
13 #include "core/fxcrt/check.h"
14 #include "core/fxcrt/zip.h"
15 #include "core/fxge/calculate_pitch.h"
16
17 #if defined(PDF_USE_SKIA)
18 #include "core/fxcrt/notreached.h"
19 #endif
20
21 namespace {
22
MakePlatformRGBStruct(uint8_t red,uint8_t green,uint8_t blue)23 CFX_DIBBase::kPlatformRGBStruct MakePlatformRGBStruct(uint8_t red,
24 uint8_t green,
25 uint8_t blue) {
26 // Note that the return value may have an alpha value that will be set to 0.
27 return {
28 .blue = blue,
29 .green = green,
30 .red = red,
31 };
32 }
33
34 } // namespace
35
CPDF_TransferFuncDIB(RetainPtr<const CFX_DIBBase> src,RetainPtr<CPDF_TransferFunc> transfer_func)36 CPDF_TransferFuncDIB::CPDF_TransferFuncDIB(
37 RetainPtr<const CFX_DIBBase> src,
38 RetainPtr<CPDF_TransferFunc> transfer_func)
39 : src_(std::move(src)),
40 transfer_func_(std::move(transfer_func)),
41 r_samples_(transfer_func_->GetSamplesR()),
42 g_samples_(transfer_func_->GetSamplesG()),
43 b_samples_(transfer_func_->GetSamplesB()) {
44 SetWidth(src_->GetWidth());
45 SetHeight(src_->GetHeight());
46 SetFormat(GetDestFormat());
47 SetPitch(fxge::CalculatePitch32OrDie(GetBPP(), GetWidth()));
48 scanline_.resize(GetPitch());
49 CHECK(!HasPalette());
50 }
51
52 CPDF_TransferFuncDIB::~CPDF_TransferFuncDIB() = default;
53
GetDestFormat() const54 FXDIB_Format CPDF_TransferFuncDIB::GetDestFormat() const {
55 if (src_->IsMaskFormat()) {
56 return FXDIB_Format::k8bppMask;
57 }
58
59 if (src_->IsAlphaFormat()) {
60 // TODO(crbug.com/355676038): Consider adding support for
61 // `FXDIB_Format::kBgraPremul`
62 return FXDIB_Format::kBgra;
63 }
64
65 return CFX_DIBBase::kPlatformRGBFormat;
66 }
67
TranslateScanline(pdfium::span<const uint8_t> src_span) const68 void CPDF_TransferFuncDIB::TranslateScanline(
69 pdfium::span<const uint8_t> src_span) const {
70 auto scanline_span = pdfium::make_span(scanline_);
71 switch (src_->GetFormat()) {
72 case FXDIB_Format::kInvalid: {
73 break;
74 }
75 case FXDIB_Format::k1bppRgb: {
76 const auto color0 =
77 MakePlatformRGBStruct(r_samples_[0], g_samples_[0], b_samples_[0]);
78 const auto color1 = MakePlatformRGBStruct(
79 r_samples_[255], g_samples_[255], b_samples_[255]);
80 auto dest = fxcrt::reinterpret_span<kPlatformRGBStruct>(scanline_span);
81 for (int i = 0; i < GetWidth(); i++) {
82 const bool is_on = (src_span[i / 8] & (1 << (7 - i % 8)));
83 dest[i] = is_on ? color1 : color0;
84 }
85 break;
86 }
87 case FXDIB_Format::k1bppMask: {
88 const int m0 = r_samples_[0];
89 const int m1 = r_samples_[255];
90 for (int i = 0; i < GetWidth(); i++) {
91 const bool is_on = (src_span[i / 8] & (1 << (7 - i % 8)));
92 scanline_[i] = is_on ? m1 : m0;
93 }
94 break;
95 }
96 case FXDIB_Format::k8bppRgb: {
97 pdfium::span<const uint32_t> src_palette = src_->GetPaletteSpan();
98 auto dest = fxcrt::reinterpret_span<kPlatformRGBStruct>(scanline_span);
99 auto zip = fxcrt::Zip(src_span.first(GetWidth()), dest);
100 if (src_->HasPalette()) {
101 for (auto [input, output] : zip) {
102 const FX_ARGB src_argb = src_palette[input];
103 output = MakePlatformRGBStruct(r_samples_[FXARGB_B(src_argb)],
104 g_samples_[FXARGB_G(src_argb)],
105 b_samples_[FXARGB_R(src_argb)]);
106 }
107 } else {
108 for (auto [input, output] : zip) {
109 output = MakePlatformRGBStruct(r_samples_[input], g_samples_[input],
110 b_samples_[input]);
111 }
112 }
113 break;
114 }
115 case FXDIB_Format::k8bppMask: {
116 for (auto [input, output] :
117 fxcrt::Zip(src_span.first(GetWidth()), scanline_span)) {
118 output = r_samples_[input];
119 }
120 break;
121 }
122 case FXDIB_Format::kBgr: {
123 auto src =
124 fxcrt::reinterpret_span<const FX_BGR_STRUCT<uint8_t>>(src_span);
125 auto dest = fxcrt::reinterpret_span<kPlatformRGBStruct>(scanline_span);
126 for (auto [input, output] : fxcrt::Zip(src.first(GetWidth()), dest)) {
127 output = MakePlatformRGBStruct(r_samples_[input.red],
128 g_samples_[input.green],
129 b_samples_[input.blue]);
130 }
131 break;
132 }
133 case FXDIB_Format::kBgrx: {
134 auto src =
135 fxcrt::reinterpret_span<const FX_BGRA_STRUCT<uint8_t>>(src_span);
136 auto dest = fxcrt::reinterpret_span<kPlatformRGBStruct>(scanline_span);
137 for (auto [input, output] : fxcrt::Zip(src.first(GetWidth()), dest)) {
138 output = MakePlatformRGBStruct(r_samples_[input.red],
139 g_samples_[input.green],
140 b_samples_[input.blue]);
141 }
142 break;
143 }
144 case FXDIB_Format::kBgra: {
145 auto src =
146 fxcrt::reinterpret_span<const FX_BGRA_STRUCT<uint8_t>>(src_span);
147 auto dest =
148 fxcrt::reinterpret_span<FX_BGRA_STRUCT<uint8_t>>(scanline_span);
149 for (auto [input, output] : fxcrt::Zip(src.first(GetWidth()), dest)) {
150 output = {
151 .blue = b_samples_[input.blue],
152 .green = g_samples_[input.green],
153 .red = r_samples_[input.red],
154 .alpha = input.alpha,
155 };
156 }
157 break;
158 }
159 #if defined(PDF_USE_SKIA)
160 case FXDIB_Format::kBgraPremul: {
161 // TODO(crbug.com/355676038): Consider adding support for
162 // `FXDIB_Format::kBgraPremul`
163 NOTREACHED_NORETURN();
164 }
165 #endif
166 }
167 }
168
GetScanline(int line) const169 pdfium::span<const uint8_t> CPDF_TransferFuncDIB::GetScanline(int line) const {
170 TranslateScanline(src_->GetScanline(line));
171 return scanline_;
172 }
173