• 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 <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