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_dibbase.h"
8
9 #include <stdint.h>
10 #include <string.h>
11
12 #include <algorithm>
13 #include <utility>
14 #include <vector>
15
16 #include "core/fxcrt/data_vector.h"
17 #include "core/fxcrt/fx_2d_size.h"
18 #include "core/fxcrt/fx_coordinates.h"
19 #include "core/fxcrt/fx_memory.h"
20 #include "core/fxcrt/fx_safe_types.h"
21 #include "core/fxcrt/span_util.h"
22 #include "core/fxge/cfx_cliprgn.h"
23 #include "core/fxge/dib/cfx_bitmapstorer.h"
24 #include "core/fxge/dib/cfx_dibitmap.h"
25 #include "core/fxge/dib/cfx_imagestretcher.h"
26 #include "core/fxge/dib/cfx_imagetransformer.h"
27 #include "third_party/base/check.h"
28 #include "third_party/base/check_op.h"
29 #include "third_party/base/notreached.h"
30 #include "third_party/base/span.h"
31
32 namespace {
33
ColorDecode(uint32_t pal_v,uint8_t * r,uint8_t * g,uint8_t * b)34 void ColorDecode(uint32_t pal_v, uint8_t* r, uint8_t* g, uint8_t* b) {
35 *r = static_cast<uint8_t>((pal_v & 0xf00) >> 4);
36 *g = static_cast<uint8_t>(pal_v & 0x0f0);
37 *b = static_cast<uint8_t>((pal_v & 0x00f) << 4);
38 }
39
Obtain_Pal(std::pair<uint32_t,uint32_t> * luts,uint32_t * dest_pal,uint32_t lut)40 void Obtain_Pal(std::pair<uint32_t, uint32_t>* luts,
41 uint32_t* dest_pal,
42 uint32_t lut) {
43 uint32_t lut_1 = lut - 1;
44 for (int row = 0; row < 256; ++row) {
45 int lut_offset = lut_1 - row;
46 if (lut_offset < 0)
47 lut_offset += 256;
48 uint32_t color = luts[lut_offset].second;
49 uint8_t r;
50 uint8_t g;
51 uint8_t b;
52 ColorDecode(color, &r, &g, &b);
53 dest_pal[row] = (static_cast<uint32_t>(r) << 16) |
54 (static_cast<uint32_t>(g) << 8) | b | 0xff000000;
55 luts[lut_offset].first = row;
56 }
57 }
58
59 class CFX_Palette {
60 public:
61 explicit CFX_Palette(const RetainPtr<const CFX_DIBBase>& pBitmap);
62 ~CFX_Palette();
63
GetPalette()64 const uint32_t* GetPalette() { return m_Palette.data(); }
GetLuts() const65 const std::pair<uint32_t, uint32_t>* GetLuts() const { return m_Luts.data(); }
GetLutCount() const66 int32_t GetLutCount() const { return m_lut; }
SetAmountLut(int row,uint32_t value)67 void SetAmountLut(int row, uint32_t value) { m_Luts[row].first = value; }
68
69 private:
70 std::vector<uint32_t> m_Palette;
71 // (Amount, Color) pairs
72 std::vector<std::pair<uint32_t, uint32_t>> m_Luts;
73 int m_lut = 0;
74 };
75
CFX_Palette(const RetainPtr<const CFX_DIBBase> & pBitmap)76 CFX_Palette::CFX_Palette(const RetainPtr<const CFX_DIBBase>& pBitmap)
77 : m_Palette(256), m_Luts(4096) {
78 int bpp = pBitmap->GetBPP() / 8;
79 int width = pBitmap->GetWidth();
80 int height = pBitmap->GetHeight();
81 for (int row = 0; row < height; ++row) {
82 pdfium::span<const uint8_t> scan_line = pBitmap->GetScanline(row);
83 for (int col = 0; col < width; ++col) {
84 const uint8_t* src_port =
85 scan_line.subspan(Fx2DSizeOrDie(col, bpp)).data();
86 uint32_t b = src_port[0] & 0xf0;
87 uint32_t g = src_port[1] & 0xf0;
88 uint32_t r = src_port[2] & 0xf0;
89 uint32_t index = (r << 4) + g + (b >> 4);
90 ++m_Luts[index].first;
91 }
92 }
93 // Move non-zeros to the front and count them
94 for (int row = 0; row < 4096; ++row) {
95 if (m_Luts[row].first != 0) {
96 m_Luts[m_lut].first = m_Luts[row].first;
97 m_Luts[m_lut].second = row;
98 ++m_lut;
99 }
100 }
101 std::sort(m_Luts.begin(), m_Luts.begin() + m_lut,
102 [](const std::pair<uint32_t, uint32_t>& arg1,
103 const std::pair<uint32_t, uint32_t>& arg2) {
104 return arg1.first < arg2.first;
105 });
106 Obtain_Pal(m_Luts.data(), m_Palette.data(), m_lut);
107 }
108
109 CFX_Palette::~CFX_Palette() = default;
110
ConvertBuffer_1bppMask2Gray(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)111 void ConvertBuffer_1bppMask2Gray(pdfium::span<uint8_t> dest_buf,
112 int dest_pitch,
113 int width,
114 int height,
115 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
116 int src_left,
117 int src_top) {
118 static constexpr uint8_t kSetGray = 0xff;
119 static constexpr uint8_t kResetGray = 0x00;
120 for (int row = 0; row < height; ++row) {
121 pdfium::span<uint8_t> dest_span =
122 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch));
123 pdfium::span<const uint8_t> src_span =
124 pSrcBitmap->GetScanline(src_top + row);
125 fxcrt::spanset(dest_span.first(width), kResetGray);
126 uint8_t* dest_scan = dest_span.data();
127 const uint8_t* src_scan = src_span.data();
128 for (int col = src_left; col < src_left + width; ++col) {
129 if (src_scan[col / 8] & (1 << (7 - col % 8)))
130 *dest_scan = kSetGray;
131 ++dest_scan;
132 }
133 }
134 }
135
ConvertBuffer_8bppMask2Gray(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)136 void ConvertBuffer_8bppMask2Gray(pdfium::span<uint8_t> dest_buf,
137 int dest_pitch,
138 int width,
139 int height,
140 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
141 int src_left,
142 int src_top) {
143 for (int row = 0; row < height; ++row) {
144 fxcrt::spancpy(
145 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)),
146 pSrcBitmap->GetScanline(src_top + row).subspan(src_left, width));
147 }
148 }
149
ConvertBuffer_1bppPlt2Gray(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)150 void ConvertBuffer_1bppPlt2Gray(pdfium::span<uint8_t> dest_buf,
151 int dest_pitch,
152 int width,
153 int height,
154 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
155 int src_left,
156 int src_top) {
157 pdfium::span<const uint32_t> src_palette = pSrcBitmap->GetPaletteSpan();
158 const uint8_t reset_r = FXARGB_R(src_palette[0]);
159 const uint8_t reset_g = FXARGB_G(src_palette[0]);
160 const uint8_t reset_b = FXARGB_B(src_palette[0]);
161 const uint8_t set_r = FXARGB_R(src_palette[1]);
162 const uint8_t set_g = FXARGB_G(src_palette[1]);
163 const uint8_t set_b = FXARGB_B(src_palette[1]);
164 const uint8_t gray0 = FXRGB2GRAY(reset_r, reset_g, reset_b);
165 const uint8_t gray1 = FXRGB2GRAY(set_r, set_g, set_b);
166
167 for (int row = 0; row < height; ++row) {
168 pdfium::span<uint8_t> dest_span =
169 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch));
170 fxcrt::spanset(dest_span.first(width), gray0);
171 uint8_t* dest_scan = dest_span.data();
172 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
173 for (int col = src_left; col < src_left + width; ++col) {
174 if (src_scan[col / 8] & (1 << (7 - col % 8)))
175 *dest_scan = gray1;
176 ++dest_scan;
177 }
178 }
179 }
180
ConvertBuffer_8bppPlt2Gray(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)181 void ConvertBuffer_8bppPlt2Gray(pdfium::span<uint8_t> dest_buf,
182 int dest_pitch,
183 int width,
184 int height,
185 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
186 int src_left,
187 int src_top) {
188 pdfium::span<const uint32_t> src_palette = pSrcBitmap->GetPaletteSpan();
189 uint8_t gray[256];
190 for (size_t i = 0; i < std::size(gray); ++i) {
191 gray[i] = FXRGB2GRAY(FXARGB_R(src_palette[i]), FXARGB_G(src_palette[i]),
192 FXARGB_B(src_palette[i]));
193 }
194
195 for (int row = 0; row < height; ++row) {
196 uint8_t* dest_scan =
197 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
198 const uint8_t* src_scan =
199 pSrcBitmap->GetScanline(src_top + row).subspan(src_left).data();
200 for (int col = 0; col < width; ++col)
201 *dest_scan++ = gray[*src_scan++];
202 }
203 }
204
ConvertBuffer_Rgb2Gray(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)205 void ConvertBuffer_Rgb2Gray(pdfium::span<uint8_t> dest_buf,
206 int dest_pitch,
207 int width,
208 int height,
209 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
210 int src_left,
211 int src_top) {
212 const int Bpp = pSrcBitmap->GetBPP() / 8;
213 const size_t x_offset = Fx2DSizeOrDie(src_left, Bpp);
214 for (int row = 0; row < height; ++row) {
215 uint8_t* dest_scan =
216 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
217 const uint8_t* src_scan =
218 pSrcBitmap->GetScanline(src_top + row).subspan(x_offset).data();
219 for (int col = 0; col < width; ++col) {
220 *dest_scan++ = FXRGB2GRAY(src_scan[2], src_scan[1], src_scan[0]);
221 src_scan += Bpp;
222 }
223 }
224 }
225
ConvertBuffer_IndexCopy(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)226 void ConvertBuffer_IndexCopy(pdfium::span<uint8_t> dest_buf,
227 int dest_pitch,
228 int width,
229 int height,
230 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
231 int src_left,
232 int src_top) {
233 if (pSrcBitmap->GetBPP() == 1) {
234 for (int row = 0; row < height; ++row) {
235 pdfium::span<uint8_t> dest_span =
236 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch));
237 // Set all destination pixels to be white initially.
238 fxcrt::spanset(dest_span.first(width), 255);
239 uint8_t* dest_scan = dest_span.data();
240 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
241 for (int col = src_left; col < src_left + width; ++col) {
242 // If the source bit is set, then set the destination pixel to be black.
243 if (src_scan[col / 8] & (1 << (7 - col % 8)))
244 *dest_scan = 0;
245
246 ++dest_scan;
247 }
248 }
249 } else {
250 for (int row = 0; row < height; ++row) {
251 fxcrt::spancpy(
252 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)),
253 pSrcBitmap->GetScanline(src_top + row).subspan(src_left, width));
254 }
255 }
256 }
257
ConvertBuffer_Plt2PltRgb8(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top,pdfium::span<uint32_t> dst_plt)258 void ConvertBuffer_Plt2PltRgb8(pdfium::span<uint8_t> dest_buf,
259 int dest_pitch,
260 int width,
261 int height,
262 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
263 int src_left,
264 int src_top,
265 pdfium::span<uint32_t> dst_plt) {
266 ConvertBuffer_IndexCopy(dest_buf, dest_pitch, width, height, pSrcBitmap,
267 src_left, src_top);
268 const size_t plt_size = pSrcBitmap->GetRequiredPaletteSize();
269 pdfium::span<const uint32_t> src_span = pSrcBitmap->GetPaletteSpan();
270 CHECK_LE(plt_size, src_span.size());
271
272 const uint32_t* src_plt = src_span.data();
273 for (size_t i = 0; i < plt_size; ++i)
274 dst_plt[i] = src_plt[i];
275 }
276
ConvertBuffer_Rgb2PltRgb8(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top,pdfium::span<uint32_t> dst_plt)277 void ConvertBuffer_Rgb2PltRgb8(pdfium::span<uint8_t> dest_buf,
278 int dest_pitch,
279 int width,
280 int height,
281 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
282 int src_left,
283 int src_top,
284 pdfium::span<uint32_t> dst_plt) {
285 int bpp = pSrcBitmap->GetBPP() / 8;
286 CFX_Palette palette(pSrcBitmap);
287 const std::pair<uint32_t, uint32_t>* Luts = palette.GetLuts();
288 int lut = palette.GetLutCount();
289 const uint32_t* pal = palette.GetPalette();
290 if (lut > 256) {
291 int err;
292 int min_err;
293 int lut_256 = lut - 256;
294 for (int row = 0; row < lut_256; ++row) {
295 min_err = 1000000;
296 uint8_t r;
297 uint8_t g;
298 uint8_t b;
299 ColorDecode(Luts[row].second, &r, &g, &b);
300 uint32_t clrindex = 0;
301 for (int col = 0; col < 256; ++col) {
302 uint32_t p_color = pal[col];
303 int d_r = r - static_cast<uint8_t>(p_color >> 16);
304 int d_g = g - static_cast<uint8_t>(p_color >> 8);
305 int d_b = b - static_cast<uint8_t>(p_color);
306 err = d_r * d_r + d_g * d_g + d_b * d_b;
307 if (err < min_err) {
308 min_err = err;
309 clrindex = col;
310 }
311 }
312 palette.SetAmountLut(row, clrindex);
313 }
314 }
315 int32_t lut_1 = lut - 1;
316 for (int row = 0; row < height; ++row) {
317 pdfium::span<const uint8_t> src_span =
318 pSrcBitmap->GetScanline(src_top + row).subspan(src_left);
319 uint8_t* dest_scan =
320 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
321 for (int col = 0; col < width; ++col) {
322 const uint8_t* src_port =
323 src_span.subspan(Fx2DSizeOrDie(col, bpp)).data();
324 int r = src_port[2] & 0xf0;
325 int g = src_port[1] & 0xf0;
326 int b = src_port[0] & 0xf0;
327 uint32_t clrindex = (r << 4) + g + (b >> 4);
328 for (int i = lut_1; i >= 0; --i)
329 if (clrindex == Luts[i].second) {
330 *(dest_scan + col) = static_cast<uint8_t>(Luts[i].first);
331 break;
332 }
333 }
334 }
335 for (size_t i = 0; i < 256; ++i)
336 dst_plt[i] = pal[i];
337 }
338
ConvertBuffer_1bppMask2Rgb(FXDIB_Format dest_format,pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)339 void ConvertBuffer_1bppMask2Rgb(FXDIB_Format dest_format,
340 pdfium::span<uint8_t> dest_buf,
341 int dest_pitch,
342 int width,
343 int height,
344 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
345 int src_left,
346 int src_top) {
347 int comps = GetCompsFromFormat(dest_format);
348 static constexpr uint8_t kSetGray = 0xff;
349 static constexpr uint8_t kResetGray = 0x00;
350 for (int row = 0; row < height; ++row) {
351 uint8_t* dest_scan =
352 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
353 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
354 for (int col = src_left; col < src_left + width; ++col) {
355 uint8_t value =
356 (src_scan[col / 8] & (1 << (7 - col % 8))) ? kSetGray : kResetGray;
357 memset(dest_scan, value, 3);
358 dest_scan += comps;
359 }
360 }
361 }
362
ConvertBuffer_8bppMask2Rgb(FXDIB_Format dest_format,pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)363 void ConvertBuffer_8bppMask2Rgb(FXDIB_Format dest_format,
364 pdfium::span<uint8_t> dest_buf,
365 int dest_pitch,
366 int width,
367 int height,
368 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
369 int src_left,
370 int src_top) {
371 int comps = GetCompsFromFormat(dest_format);
372 for (int row = 0; row < height; ++row) {
373 uint8_t* dest_scan =
374 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
375 const uint8_t* src_scan =
376 pSrcBitmap->GetScanline(src_top + row).subspan(src_left).data();
377 for (int col = 0; col < width; ++col) {
378 memset(dest_scan, *src_scan, 3);
379 dest_scan += comps;
380 ++src_scan;
381 }
382 }
383 }
384
ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dest_format,pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)385 void ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dest_format,
386 pdfium::span<uint8_t> dest_buf,
387 int dest_pitch,
388 int width,
389 int height,
390 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
391 int src_left,
392 int src_top) {
393 pdfium::span<const uint32_t> src_palette = pSrcBitmap->GetPaletteSpan();
394 const uint8_t dst_palette[6] = {
395 FXARGB_B(src_palette[0]), FXARGB_G(src_palette[0]),
396 FXARGB_R(src_palette[0]), FXARGB_B(src_palette[1]),
397 FXARGB_G(src_palette[1]), FXARGB_R(src_palette[1])};
398 int comps = GetCompsFromFormat(dest_format);
399 for (int row = 0; row < height; ++row) {
400 uint8_t* dest_scan =
401 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
402 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
403 for (int col = src_left; col < src_left + width; ++col) {
404 size_t offset = (src_scan[col / 8] & (1 << (7 - col % 8))) ? 3 : 0;
405 memcpy(dest_scan, dst_palette + offset, 3);
406 dest_scan += comps;
407 }
408 }
409 }
410
ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dest_format,pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)411 void ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dest_format,
412 pdfium::span<uint8_t> dest_buf,
413 int dest_pitch,
414 int width,
415 int height,
416 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
417 int src_left,
418 int src_top) {
419 pdfium::span<const uint32_t> src_palette = pSrcBitmap->GetPaletteSpan();
420 uint8_t dst_palette[768];
421 for (int i = 0; i < 256; ++i) {
422 dst_palette[3 * i] = FXARGB_B(src_palette[i]);
423 dst_palette[3 * i + 1] = FXARGB_G(src_palette[i]);
424 dst_palette[3 * i + 2] = FXARGB_R(src_palette[i]);
425 }
426 int comps = GetCompsFromFormat(dest_format);
427 for (int row = 0; row < height; ++row) {
428 uint8_t* dest_scan =
429 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
430 const uint8_t* src_scan =
431 pSrcBitmap->GetScanline(src_top + row).subspan(src_left).data();
432 for (int col = 0; col < width; ++col) {
433 uint8_t* src_pixel = dst_palette + 3 * (*src_scan++);
434 memcpy(dest_scan, src_pixel, 3);
435 dest_scan += comps;
436 }
437 }
438 }
439
ConvertBuffer_24bppRgb2Rgb24(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)440 void ConvertBuffer_24bppRgb2Rgb24(
441 pdfium::span<uint8_t> dest_buf,
442 int dest_pitch,
443 int width,
444 int height,
445 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
446 int src_left,
447 int src_top) {
448 const size_t x_offset = Fx2DSizeOrDie(src_left, 3);
449 const size_t byte_count = Fx2DSizeOrDie(width, 3);
450 for (int row = 0; row < height; ++row) {
451 fxcrt::spancpy(
452 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)),
453 pSrcBitmap->GetScanline(src_top + row).subspan(x_offset, byte_count));
454 }
455 }
456
ConvertBuffer_32bppRgb2Rgb24(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)457 void ConvertBuffer_32bppRgb2Rgb24(
458 pdfium::span<uint8_t> dest_buf,
459 int dest_pitch,
460 int width,
461 int height,
462 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
463 int src_left,
464 int src_top) {
465 const size_t x_offset = Fx2DSizeOrDie(src_left, 4);
466 for (int row = 0; row < height; ++row) {
467 uint8_t* dest_scan =
468 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
469 const uint8_t* src_scan =
470 pSrcBitmap->GetScanline(src_top + row).subspan(x_offset).data();
471 for (int col = 0; col < width; ++col) {
472 memcpy(dest_scan, src_scan, 3);
473 dest_scan += 3;
474 src_scan += 4;
475 }
476 }
477 }
478
ConvertBuffer_Rgb2Rgb32(pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)479 void ConvertBuffer_Rgb2Rgb32(pdfium::span<uint8_t> dest_buf,
480 int dest_pitch,
481 int width,
482 int height,
483 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
484 int src_left,
485 int src_top) {
486 const int comps = pSrcBitmap->GetBPP() / 8;
487 const size_t x_offset = Fx2DSizeOrDie(src_left, comps);
488 for (int row = 0; row < height; ++row) {
489 uint8_t* dest_scan =
490 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
491 const uint8_t* src_scan =
492 pSrcBitmap->GetScanline(src_top + row).subspan(x_offset).data();
493 for (int col = 0; col < width; ++col) {
494 memcpy(dest_scan, src_scan, 3);
495 dest_scan += 4;
496 src_scan += comps;
497 }
498 }
499 }
500
ConvertBuffer_8bppMask(int bpp,pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)501 bool ConvertBuffer_8bppMask(int bpp,
502 pdfium::span<uint8_t> dest_buf,
503 int dest_pitch,
504 int width,
505 int height,
506 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
507 int src_left,
508 int src_top) {
509 switch (bpp) {
510 case 1:
511 if (pSrcBitmap->HasPalette()) {
512 ConvertBuffer_1bppPlt2Gray(dest_buf, dest_pitch, width, height,
513 pSrcBitmap, src_left, src_top);
514 } else {
515 ConvertBuffer_1bppMask2Gray(dest_buf, dest_pitch, width, height,
516 pSrcBitmap, src_left, src_top);
517 }
518 return true;
519 case 8:
520 if (pSrcBitmap->HasPalette()) {
521 ConvertBuffer_8bppPlt2Gray(dest_buf, dest_pitch, width, height,
522 pSrcBitmap, src_left, src_top);
523 } else {
524 ConvertBuffer_8bppMask2Gray(dest_buf, dest_pitch, width, height,
525 pSrcBitmap, src_left, src_top);
526 }
527 return true;
528 case 24:
529 case 32:
530 ConvertBuffer_Rgb2Gray(dest_buf, dest_pitch, width, height, pSrcBitmap,
531 src_left, src_top);
532 return true;
533 default:
534 return false;
535 }
536 }
537
ConvertBuffer_Rgb(int bpp,FXDIB_Format dest_format,pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)538 bool ConvertBuffer_Rgb(int bpp,
539 FXDIB_Format dest_format,
540 pdfium::span<uint8_t> dest_buf,
541 int dest_pitch,
542 int width,
543 int height,
544 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
545 int src_left,
546 int src_top) {
547 switch (bpp) {
548 case 1:
549 if (pSrcBitmap->HasPalette()) {
550 ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
551 height, pSrcBitmap, src_left, src_top);
552 } else {
553 ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
554 height, pSrcBitmap, src_left, src_top);
555 }
556 return true;
557 case 8:
558 if (pSrcBitmap->HasPalette()) {
559 ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
560 height, pSrcBitmap, src_left, src_top);
561 } else {
562 ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
563 height, pSrcBitmap, src_left, src_top);
564 }
565 return true;
566 case 24:
567 ConvertBuffer_24bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
568 pSrcBitmap, src_left, src_top);
569 return true;
570 case 32:
571 ConvertBuffer_32bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
572 pSrcBitmap, src_left, src_top);
573 return true;
574 default:
575 return false;
576 }
577 }
578
ConvertBuffer_Argb(int bpp,FXDIB_Format dest_format,pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)579 bool ConvertBuffer_Argb(int bpp,
580 FXDIB_Format dest_format,
581 pdfium::span<uint8_t> dest_buf,
582 int dest_pitch,
583 int width,
584 int height,
585 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
586 int src_left,
587 int src_top) {
588 switch (bpp) {
589 case 1:
590 if (pSrcBitmap->HasPalette()) {
591 ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
592 height, pSrcBitmap, src_left, src_top);
593 } else {
594 ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
595 height, pSrcBitmap, src_left, src_top);
596 }
597 return true;
598 case 8:
599 if (pSrcBitmap->HasPalette()) {
600 ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
601 height, pSrcBitmap, src_left, src_top);
602 } else {
603 ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
604 height, pSrcBitmap, src_left, src_top);
605 }
606 return true;
607 case 24:
608 case 32:
609 ConvertBuffer_Rgb2Rgb32(dest_buf, dest_pitch, width, height, pSrcBitmap,
610 src_left, src_top);
611 return true;
612 default:
613 return false;
614 }
615 }
616
617 } // namespace
618
619 CFX_DIBBase::CFX_DIBBase() = default;
620
621 CFX_DIBBase::~CFX_DIBBase() = default;
622
GetBuffer() const623 pdfium::span<uint8_t> CFX_DIBBase::GetBuffer() const {
624 return pdfium::span<uint8_t>();
625 }
626
SkipToScanline(int line,PauseIndicatorIface * pPause) const627 bool CFX_DIBBase::SkipToScanline(int line, PauseIndicatorIface* pPause) const {
628 return false;
629 }
630
GetEstimatedImageMemoryBurden() const631 size_t CFX_DIBBase::GetEstimatedImageMemoryBurden() const {
632 return GetRequiredPaletteSize() * sizeof(uint32_t);
633 }
634
Realize() const635 RetainPtr<CFX_DIBitmap> CFX_DIBBase::Realize() const {
636 return ClipToInternal(nullptr);
637 }
638
ClipTo(const FX_RECT & rect) const639 RetainPtr<CFX_DIBitmap> CFX_DIBBase::ClipTo(const FX_RECT& rect) const {
640 return ClipToInternal(&rect);
641 }
642
ClipToInternal(const FX_RECT * pClip) const643 RetainPtr<CFX_DIBitmap> CFX_DIBBase::ClipToInternal(
644 const FX_RECT* pClip) const {
645 FX_RECT rect(0, 0, m_Width, m_Height);
646 if (pClip) {
647 rect.Intersect(*pClip);
648 if (rect.IsEmpty())
649 return nullptr;
650 }
651 auto pNewBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
652 if (!pNewBitmap->Create(rect.Width(), rect.Height(), GetFormat()))
653 return nullptr;
654
655 pNewBitmap->SetPalette(GetPaletteSpan());
656 if (GetBPP() == 1 && rect.left % 8 != 0) {
657 int left_shift = rect.left % 32;
658 int right_shift = 32 - left_shift;
659 int dword_count = pNewBitmap->m_Pitch / 4;
660 for (int row = rect.top; row < rect.bottom; ++row) {
661 const uint32_t* src_scan =
662 reinterpret_cast<const uint32_t*>(GetScanline(row).data()) +
663 rect.left / 32;
664 uint32_t* dest_scan = reinterpret_cast<uint32_t*>(
665 pNewBitmap->GetWritableScanline(row - rect.top).data());
666 for (int i = 0; i < dword_count; ++i) {
667 dest_scan[i] =
668 (src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift);
669 }
670 }
671 } else {
672 FX_SAFE_UINT32 copy_len = pNewBitmap->GetWidth();
673 copy_len *= pNewBitmap->GetBPP();
674 copy_len += 7;
675 copy_len /= 8;
676 if (!copy_len.IsValid())
677 return nullptr;
678
679 copy_len = std::min<uint32_t>(m_Pitch, copy_len.ValueOrDie());
680
681 FX_SAFE_UINT32 offset = rect.left;
682 offset *= GetBppFromFormat(m_Format);
683 offset /= 8;
684 if (!offset.IsValid())
685 return nullptr;
686
687 for (int row = rect.top; row < rect.bottom; ++row) {
688 const uint8_t* src_scan =
689 GetScanline(row).subspan(offset.ValueOrDie()).data();
690 uint8_t* dest_scan =
691 pNewBitmap->GetWritableScanline(row - rect.top).data();
692 memcpy(dest_scan, src_scan, copy_len.ValueOrDie());
693 }
694 }
695 return pNewBitmap;
696 }
697
BuildPalette()698 void CFX_DIBBase::BuildPalette() {
699 if (HasPalette())
700 return;
701
702 if (GetBPP() == 1) {
703 m_palette = {0xff000000, 0xffffffff};
704 } else if (GetBPP() == 8) {
705 m_palette.resize(256);
706 for (int i = 0; i < 256; ++i)
707 m_palette[i] = ArgbEncode(0xff, i, i, i);
708 }
709 }
710
GetRequiredPaletteSize() const711 size_t CFX_DIBBase::GetRequiredPaletteSize() const {
712 if (IsMaskFormat())
713 return 0;
714
715 switch (GetBppFromFormat(m_Format)) {
716 case 1:
717 return 2;
718 case 8:
719 return 256;
720 default:
721 return 0;
722 }
723 }
724
GetPaletteArgb(int index) const725 uint32_t CFX_DIBBase::GetPaletteArgb(int index) const {
726 DCHECK((GetBPP() == 1 || GetBPP() == 8) && !IsMaskFormat());
727 if (HasPalette())
728 return GetPaletteSpan()[index];
729
730 if (GetBPP() == 1)
731 return index ? 0xffffffff : 0xff000000;
732
733 return ArgbEncode(0xff, index, index, index);
734 }
735
SetPaletteArgb(int index,uint32_t color)736 void CFX_DIBBase::SetPaletteArgb(int index, uint32_t color) {
737 DCHECK((GetBPP() == 1 || GetBPP() == 8) && !IsMaskFormat());
738 BuildPalette();
739 m_palette[index] = color;
740 }
741
FindPalette(uint32_t color) const742 int CFX_DIBBase::FindPalette(uint32_t color) const {
743 DCHECK((GetBPP() == 1 || GetBPP() == 8) && !IsMaskFormat());
744 if (HasPalette()) {
745 int palsize = (1 << GetBPP());
746 pdfium::span<const uint32_t> palette = GetPaletteSpan();
747 for (int i = 0; i < palsize; ++i) {
748 if (palette[i] == color)
749 return i;
750 }
751 return -1;
752 }
753
754 if (GetBPP() == 1)
755 return (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
756 return static_cast<uint8_t>(color);
757 }
758
GetOverlapRect(int & dest_left,int & dest_top,int & width,int & height,int src_width,int src_height,int & src_left,int & src_top,const CFX_ClipRgn * pClipRgn) const759 bool CFX_DIBBase::GetOverlapRect(int& dest_left,
760 int& dest_top,
761 int& width,
762 int& height,
763 int src_width,
764 int src_height,
765 int& src_left,
766 int& src_top,
767 const CFX_ClipRgn* pClipRgn) const {
768 if (width == 0 || height == 0)
769 return false;
770
771 DCHECK_GT(width, 0);
772 DCHECK_GT(height, 0);
773
774 if (dest_left > m_Width || dest_top > m_Height)
775 return false;
776
777 FX_SAFE_INT32 safe_src_width = src_left;
778 safe_src_width += width;
779 if (!safe_src_width.IsValid())
780 return false;
781
782 FX_SAFE_INT32 safe_src_height = src_top;
783 safe_src_height += height;
784 if (!safe_src_height.IsValid())
785 return false;
786
787 FX_RECT src_rect(src_left, src_top, safe_src_width.ValueOrDie(),
788 safe_src_height.ValueOrDie());
789 FX_RECT src_bound(0, 0, src_width, src_height);
790 src_rect.Intersect(src_bound);
791
792 FX_SAFE_INT32 safe_x_offset = dest_left;
793 safe_x_offset -= src_left;
794 if (!safe_x_offset.IsValid())
795 return false;
796
797 FX_SAFE_INT32 safe_y_offset = dest_top;
798 safe_y_offset -= src_top;
799 if (!safe_y_offset.IsValid())
800 return false;
801
802 FX_SAFE_INT32 safe_dest_left = safe_x_offset;
803 safe_dest_left += src_rect.left;
804 if (!safe_dest_left.IsValid())
805 return false;
806
807 FX_SAFE_INT32 safe_dest_top = safe_y_offset;
808 safe_dest_top += src_rect.top;
809 if (!safe_dest_top.IsValid())
810 return false;
811
812 FX_SAFE_INT32 safe_dest_right = safe_x_offset;
813 safe_dest_right += src_rect.right;
814 if (!safe_dest_right.IsValid())
815 return false;
816
817 FX_SAFE_INT32 safe_dest_bottom = safe_y_offset;
818 safe_dest_bottom += src_rect.bottom;
819 if (!safe_dest_bottom.IsValid())
820 return false;
821
822 FX_RECT dest_rect(safe_dest_left.ValueOrDie(), safe_dest_top.ValueOrDie(),
823 safe_dest_right.ValueOrDie(),
824 safe_dest_bottom.ValueOrDie());
825 FX_RECT dest_bound(0, 0, m_Width, m_Height);
826 dest_rect.Intersect(dest_bound);
827
828 if (pClipRgn)
829 dest_rect.Intersect(pClipRgn->GetBox());
830 dest_left = dest_rect.left;
831 dest_top = dest_rect.top;
832
833 FX_SAFE_INT32 safe_new_src_left = dest_left;
834 safe_new_src_left -= safe_x_offset;
835 if (!safe_new_src_left.IsValid())
836 return false;
837 src_left = safe_new_src_left.ValueOrDie();
838
839 FX_SAFE_INT32 safe_new_src_top = dest_top;
840 safe_new_src_top -= safe_y_offset;
841 if (!safe_new_src_top.IsValid())
842 return false;
843 src_top = safe_new_src_top.ValueOrDie();
844
845 if (dest_rect.IsEmpty())
846 return false;
847
848 width = dest_rect.Width();
849 height = dest_rect.Height();
850 return true;
851 }
852
SetPalette(pdfium::span<const uint32_t> src_palette)853 void CFX_DIBBase::SetPalette(pdfium::span<const uint32_t> src_palette) {
854 if (src_palette.empty() || GetBPP() > 8) {
855 m_palette.clear();
856 return;
857 }
858 uint32_t pal_size = 1 << GetBPP();
859 if (m_palette.empty())
860 m_palette.resize(pal_size);
861 pal_size = std::min(pal_size, kPaletteSize);
862 for (size_t i = 0; i < pal_size; ++i)
863 m_palette[i] = src_palette[i];
864 }
865
CloneAlphaMask() const866 RetainPtr<CFX_DIBitmap> CFX_DIBBase::CloneAlphaMask() const {
867 DCHECK_EQ(GetFormat(), FXDIB_Format::kArgb);
868 auto pMask = pdfium::MakeRetain<CFX_DIBitmap>();
869 if (!pMask->Create(m_Width, m_Height, FXDIB_Format::k8bppMask))
870 return nullptr;
871
872 for (int row = 0; row < m_Height; ++row) {
873 const uint8_t* src_scan = GetScanline(row).subspan(3).data();
874 uint8_t* dest_scan = pMask->GetWritableScanline(row).data();
875 for (int col = 0; col < m_Width; ++col) {
876 *dest_scan++ = *src_scan;
877 src_scan += 4;
878 }
879 }
880 return pMask;
881 }
882
FlipImage(bool bXFlip,bool bYFlip) const883 RetainPtr<CFX_DIBitmap> CFX_DIBBase::FlipImage(bool bXFlip, bool bYFlip) const {
884 auto pFlipped = pdfium::MakeRetain<CFX_DIBitmap>();
885 if (!pFlipped->Create(m_Width, m_Height, GetFormat()))
886 return nullptr;
887
888 pFlipped->SetPalette(GetPaletteSpan());
889 int Bpp = GetBppFromFormat(m_Format) / 8;
890 for (int row = 0; row < m_Height; ++row) {
891 const uint8_t* src_scan = GetScanline(row).data();
892 uint8_t* dest_scan =
893 pFlipped->GetWritableScanline(bYFlip ? m_Height - row - 1 : row).data();
894 if (!bXFlip) {
895 memcpy(dest_scan, src_scan, m_Pitch);
896 continue;
897 }
898 if (GetBppFromFormat(m_Format) == 1) {
899 memset(dest_scan, 0, m_Pitch);
900 for (int col = 0; col < m_Width; ++col) {
901 if (src_scan[col / 8] & (1 << (7 - col % 8))) {
902 int dest_col = m_Width - col - 1;
903 dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8));
904 }
905 }
906 continue;
907 }
908
909 dest_scan += (m_Width - 1) * Bpp;
910 if (Bpp == 1) {
911 for (int col = 0; col < m_Width; ++col) {
912 *dest_scan = *src_scan;
913 --dest_scan;
914 ++src_scan;
915 }
916 } else if (Bpp == 3) {
917 for (int col = 0; col < m_Width; ++col) {
918 memcpy(dest_scan, src_scan, 3);
919 dest_scan -= 3;
920 src_scan += 3;
921 }
922 } else {
923 DCHECK_EQ(Bpp, 4);
924 for (int col = 0; col < m_Width; ++col) {
925 const auto* src_scan32 = reinterpret_cast<const uint32_t*>(src_scan);
926 uint32_t* dest_scan32 = reinterpret_cast<uint32_t*>(dest_scan);
927 *dest_scan32 = *src_scan32;
928 dest_scan -= 4;
929 src_scan += 4;
930 }
931 }
932 }
933 return pFlipped;
934 }
935
ConvertTo(FXDIB_Format dest_format) const936 RetainPtr<CFX_DIBitmap> CFX_DIBBase::ConvertTo(FXDIB_Format dest_format) const {
937 if (dest_format == GetFormat())
938 return Realize();
939
940 auto pClone = pdfium::MakeRetain<CFX_DIBitmap>();
941 if (!pClone->Create(m_Width, m_Height, dest_format))
942 return nullptr;
943
944 RetainPtr<CFX_DIBitmap> pSrcAlpha;
945 if (IsAlphaFormat()) {
946 pSrcAlpha = CloneAlphaMask();
947 if (!pSrcAlpha)
948 return nullptr;
949 }
950 if (dest_format == FXDIB_Format::kArgb) {
951 bool ret = pSrcAlpha ? pClone->SetAlphaFromBitmap(pSrcAlpha)
952 : pClone->SetUniformOpaqueAlpha();
953 if (!ret)
954 return nullptr;
955 }
956
957 RetainPtr<const CFX_DIBBase> holder(this);
958 DataVector<uint32_t> pal_8bpp;
959 if (!ConvertBuffer(dest_format, pClone->GetBuffer(), pClone->GetPitch(),
960 m_Width, m_Height, holder, 0, 0, &pal_8bpp)) {
961 return nullptr;
962 }
963 if (!pal_8bpp.empty())
964 pClone->SetPalette(pal_8bpp);
965
966 return pClone;
967 }
968
SwapXY(bool bXFlip,bool bYFlip) const969 RetainPtr<CFX_DIBitmap> CFX_DIBBase::SwapXY(bool bXFlip, bool bYFlip) const {
970 FX_RECT dest_clip(0, 0, m_Height, m_Width);
971 if (dest_clip.IsEmpty())
972 return nullptr;
973
974 auto pTransBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
975 const int result_height = dest_clip.Height();
976 const int result_width = dest_clip.Width();
977 if (!pTransBitmap->Create(result_width, result_height, GetFormat()))
978 return nullptr;
979
980 pTransBitmap->SetPalette(GetPaletteSpan());
981 const int dest_pitch = pTransBitmap->GetPitch();
982 pdfium::span<uint8_t> dest_span =
983 pTransBitmap->GetBuffer().first(Fx2DSizeOrDie(dest_pitch, result_height));
984 const size_t dest_last_row_offset =
985 Fx2DSizeOrDie(dest_pitch, result_height - 1);
986 const int row_start = bXFlip ? m_Height - dest_clip.right : dest_clip.left;
987 const int row_end = bXFlip ? m_Height - dest_clip.left : dest_clip.right;
988 const int col_start = bYFlip ? m_Width - dest_clip.bottom : dest_clip.top;
989 const int col_end = bYFlip ? m_Width - dest_clip.top : dest_clip.bottom;
990 if (GetBPP() == 1) {
991 fxcrt::spanset(dest_span, 0xff);
992 if (bYFlip)
993 dest_span = dest_span.subspan(dest_last_row_offset);
994 const int dest_step = bYFlip ? -dest_pitch : dest_pitch;
995 for (int row = row_start; row < row_end; ++row) {
996 const uint8_t* src_scan = GetScanline(row).data();
997 int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
998 dest_clip.left;
999 uint8_t* dest_scan = dest_span.data();
1000 for (int col = col_start; col < col_end; ++col) {
1001 if (!(src_scan[col / 8] & (1 << (7 - col % 8))))
1002 dest_scan[dest_col / 8] &= ~(1 << (7 - dest_col % 8));
1003 dest_scan += dest_step;
1004 }
1005 }
1006 } else {
1007 int nBytes = GetBPP() / 8;
1008 int dest_step = bYFlip ? -dest_pitch : dest_pitch;
1009 if (nBytes == 3)
1010 dest_step -= 2;
1011 if (bYFlip)
1012 dest_span = dest_span.subspan(dest_last_row_offset);
1013 for (int row = row_start; row < row_end; ++row) {
1014 int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
1015 dest_clip.left;
1016 size_t dest_offset = Fx2DSizeOrDie(dest_col, nBytes);
1017 uint8_t* dest_scan = dest_span.subspan(dest_offset).data();
1018 if (nBytes == 4) {
1019 const uint32_t* src_scan =
1020 reinterpret_cast<const uint32_t*>(GetScanline(row).data()) +
1021 col_start;
1022 for (int col = col_start; col < col_end; ++col) {
1023 uint32_t* dest_scan32 = reinterpret_cast<uint32_t*>(dest_scan);
1024 *dest_scan32 = *src_scan++;
1025 dest_scan += dest_step;
1026 }
1027 } else {
1028 const uint8_t* src_scan =
1029 GetScanline(row).subspan(col_start * nBytes).data();
1030 if (nBytes == 1) {
1031 for (int col = col_start; col < col_end; ++col) {
1032 *dest_scan = *src_scan++;
1033 dest_scan += dest_step;
1034 }
1035 } else {
1036 for (int col = col_start; col < col_end; ++col) {
1037 memcpy(dest_scan, src_scan, 3);
1038 dest_scan += 2 + dest_step;
1039 src_scan += 3;
1040 }
1041 }
1042 }
1043 }
1044 }
1045 return pTransBitmap;
1046 }
1047
TransformTo(const CFX_Matrix & mtDest,int * result_left,int * result_top) const1048 RetainPtr<CFX_DIBitmap> CFX_DIBBase::TransformTo(const CFX_Matrix& mtDest,
1049 int* result_left,
1050 int* result_top) const {
1051 RetainPtr<const CFX_DIBBase> holder(this);
1052 CFX_ImageTransformer transformer(holder, mtDest, FXDIB_ResampleOptions(),
1053 nullptr);
1054 transformer.Continue(nullptr);
1055 *result_left = transformer.result().left;
1056 *result_top = transformer.result().top;
1057 return transformer.DetachBitmap();
1058 }
1059
StretchTo(int dest_width,int dest_height,const FXDIB_ResampleOptions & options,const FX_RECT * pClip) const1060 RetainPtr<CFX_DIBitmap> CFX_DIBBase::StretchTo(
1061 int dest_width,
1062 int dest_height,
1063 const FXDIB_ResampleOptions& options,
1064 const FX_RECT* pClip) const {
1065 RetainPtr<const CFX_DIBBase> holder(this);
1066 FX_RECT clip_rect(0, 0, abs(dest_width), abs(dest_height));
1067 if (pClip)
1068 clip_rect.Intersect(*pClip);
1069
1070 if (clip_rect.IsEmpty())
1071 return nullptr;
1072
1073 if (dest_width == m_Width && dest_height == m_Height)
1074 return ClipTo(clip_rect);
1075
1076 CFX_BitmapStorer storer;
1077 CFX_ImageStretcher stretcher(&storer, holder, dest_width, dest_height,
1078 clip_rect, options);
1079 if (stretcher.Start())
1080 stretcher.Continue(nullptr);
1081
1082 return storer.Detach();
1083 }
1084
1085 // static
ConvertBuffer(FXDIB_Format dest_format,pdfium::span<uint8_t> dest_buf,int dest_pitch,int width,int height,const RetainPtr<const CFX_DIBBase> & pSrcBitmap,int src_left,int src_top,DataVector<uint32_t> * pal)1086 bool CFX_DIBBase::ConvertBuffer(FXDIB_Format dest_format,
1087 pdfium::span<uint8_t> dest_buf,
1088 int dest_pitch,
1089 int width,
1090 int height,
1091 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
1092 int src_left,
1093 int src_top,
1094 DataVector<uint32_t>* pal) {
1095 FXDIB_Format src_format = pSrcBitmap->GetFormat();
1096 const int bpp = GetBppFromFormat(src_format);
1097 switch (dest_format) {
1098 case FXDIB_Format::k8bppMask: {
1099 return ConvertBuffer_8bppMask(bpp, dest_buf, dest_pitch, width, height,
1100 pSrcBitmap, src_left, src_top);
1101 }
1102 case FXDIB_Format::k8bppRgb: {
1103 const bool bpp_1_or_8 = (bpp == 1 || bpp == 8);
1104 if (bpp_1_or_8 && !pSrcBitmap->HasPalette()) {
1105 return ConvertBuffer(FXDIB_Format::k8bppMask, dest_buf, dest_pitch,
1106 width, height, pSrcBitmap, src_left, src_top, pal);
1107 }
1108 pal->resize(256);
1109 if (bpp_1_or_8 && pSrcBitmap->HasPalette()) {
1110 ConvertBuffer_Plt2PltRgb8(dest_buf, dest_pitch, width, height,
1111 pSrcBitmap, src_left, src_top, *pal);
1112 return true;
1113 }
1114 if (bpp >= 24) {
1115 ConvertBuffer_Rgb2PltRgb8(dest_buf, dest_pitch, width, height,
1116 pSrcBitmap, src_left, src_top, *pal);
1117 return true;
1118 }
1119 return false;
1120 }
1121 case FXDIB_Format::kRgb: {
1122 return ConvertBuffer_Rgb(bpp, dest_format, dest_buf, dest_pitch, width,
1123 height, pSrcBitmap, src_left, src_top);
1124 }
1125 case FXDIB_Format::kArgb:
1126 case FXDIB_Format::kRgb32: {
1127 return ConvertBuffer_Argb(bpp, dest_format, dest_buf, dest_pitch, width,
1128 height, pSrcBitmap, src_left, src_top);
1129 }
1130 default:
1131 NOTREACHED();
1132 return false;
1133 }
1134 }
1135