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