• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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