• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 PDFium Authors. All rights reserved.
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 <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "core/fxge/cfx_cliprgn.h"
15 #include "core/fxge/dib/cfx_bitmapstorer.h"
16 #include "core/fxge/dib/cfx_cmyk_to_srgb.h"
17 #include "core/fxge/dib/cfx_dibitmap.h"
18 #include "core/fxge/dib/cfx_imagestretcher.h"
19 #include "core/fxge/dib/cfx_imagetransformer.h"
20 #include "third_party/base/logging.h"
21 
22 namespace {
23 
ColorDecode(uint32_t pal_v,uint8_t * r,uint8_t * g,uint8_t * b)24 void ColorDecode(uint32_t pal_v, uint8_t* r, uint8_t* g, uint8_t* b) {
25   *r = static_cast<uint8_t>((pal_v & 0xf00) >> 4);
26   *g = static_cast<uint8_t>(pal_v & 0x0f0);
27   *b = static_cast<uint8_t>((pal_v & 0x00f) << 4);
28 }
29 
Obtain_Pal(std::pair<uint32_t,uint32_t> * luts,uint32_t * dest_pal,uint32_t lut)30 void Obtain_Pal(std::pair<uint32_t, uint32_t>* luts,
31                 uint32_t* dest_pal,
32                 uint32_t lut) {
33   uint32_t lut_1 = lut - 1;
34   for (int row = 0; row < 256; ++row) {
35     int lut_offset = lut_1 - row;
36     if (lut_offset < 0)
37       lut_offset += 256;
38     uint32_t color = luts[lut_offset].second;
39     uint8_t r;
40     uint8_t g;
41     uint8_t b;
42     ColorDecode(color, &r, &g, &b);
43     dest_pal[row] = (static_cast<uint32_t>(r) << 16) |
44                     (static_cast<uint32_t>(g) << 8) | b | 0xff000000;
45     luts[lut_offset].first = row;
46   }
47 }
48 
49 class CFX_Palette {
50  public:
51   explicit CFX_Palette(const RetainPtr<CFX_DIBBase>& pBitmap);
52   ~CFX_Palette();
53 
GetPalette()54   const uint32_t* GetPalette() { return m_Palette.data(); }
GetLuts() const55   const std::pair<uint32_t, uint32_t>* GetLuts() const { return m_Luts.data(); }
GetLutCount() const56   int32_t GetLutCount() const { return m_lut; }
SetAmountLut(int row,uint32_t value)57   void SetAmountLut(int row, uint32_t value) { m_Luts[row].first = value; }
58 
59  private:
60   std::vector<uint32_t> m_Palette;
61   // (Amount, Color) pairs
62   std::vector<std::pair<uint32_t, uint32_t>> m_Luts;
63   int m_lut;
64 };
65 
CFX_Palette(const RetainPtr<CFX_DIBBase> & pBitmap)66 CFX_Palette::CFX_Palette(const RetainPtr<CFX_DIBBase>& pBitmap)
67     : m_Palette(256), m_Luts(4096), m_lut(0) {
68   int bpp = pBitmap->GetBPP() / 8;
69   int width = pBitmap->GetWidth();
70   int height = pBitmap->GetHeight();
71   for (int row = 0; row < height; ++row) {
72     const uint8_t* scan_line = pBitmap->GetScanline(row);
73     for (int col = 0; col < width; ++col) {
74       const uint8_t* src_port = scan_line + col * bpp;
75       uint32_t b = src_port[0] & 0xf0;
76       uint32_t g = src_port[1] & 0xf0;
77       uint32_t r = src_port[2] & 0xf0;
78       uint32_t index = (r << 4) + g + (b >> 4);
79       ++m_Luts[index].first;
80     }
81   }
82   // Move non-zeros to the front and count them
83   for (int row = 0; row < 4096; ++row) {
84     if (m_Luts[row].first != 0) {
85       m_Luts[m_lut].first = m_Luts[row].first;
86       m_Luts[m_lut].second = row;
87       ++m_lut;
88     }
89   }
90   std::sort(m_Luts.begin(), m_Luts.begin() + m_lut,
91             [](const std::pair<uint32_t, uint32_t>& arg1,
92                const std::pair<uint32_t, uint32_t>& arg2) {
93               return arg1.first < arg2.first;
94             });
95   Obtain_Pal(m_Luts.data(), m_Palette.data(), m_lut);
96 }
97 
~CFX_Palette()98 CFX_Palette::~CFX_Palette() {}
99 
ConvertBuffer_1bppMask2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)100 void ConvertBuffer_1bppMask2Gray(uint8_t* dest_buf,
101                                  int dest_pitch,
102                                  int width,
103                                  int height,
104                                  const RetainPtr<CFX_DIBBase>& pSrcBitmap,
105                                  int src_left,
106                                  int src_top) {
107   static constexpr uint8_t kSetGray = 0xff;
108   static constexpr uint8_t kResetGray = 0x00;
109   for (int row = 0; row < height; ++row) {
110     uint8_t* dest_scan = dest_buf + row * dest_pitch;
111     memset(dest_scan, kResetGray, width);
112     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
113     for (int col = src_left; col < src_left + width; ++col) {
114       if (src_scan[col / 8] & (1 << (7 - col % 8)))
115         *dest_scan = kSetGray;
116       ++dest_scan;
117     }
118   }
119 }
120 
ConvertBuffer_8bppMask2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)121 void ConvertBuffer_8bppMask2Gray(uint8_t* dest_buf,
122                                  int dest_pitch,
123                                  int width,
124                                  int height,
125                                  const RetainPtr<CFX_DIBBase>& pSrcBitmap,
126                                  int src_left,
127                                  int src_top) {
128   for (int row = 0; row < height; ++row) {
129     uint8_t* dest_scan = dest_buf + row * dest_pitch;
130     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
131     memcpy(dest_scan, src_scan, width);
132   }
133 }
134 
ConvertBuffer_1bppPlt2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)135 void ConvertBuffer_1bppPlt2Gray(uint8_t* dest_buf,
136                                 int dest_pitch,
137                                 int width,
138                                 int height,
139                                 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
140                                 int src_left,
141                                 int src_top) {
142   uint32_t* src_plt = pSrcBitmap->GetPalette();
143   uint8_t gray[2];
144   uint8_t reset_r;
145   uint8_t reset_g;
146   uint8_t reset_b;
147   uint8_t set_r;
148   uint8_t set_g;
149   uint8_t set_b;
150   if (pSrcBitmap->IsCmykImage()) {
151     std::tie(reset_r, reset_g, reset_b) = AdobeCMYK_to_sRGB1(
152         FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]),
153         FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]));
154     std::tie(set_r, set_g, set_b) = AdobeCMYK_to_sRGB1(
155         FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]),
156         FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]));
157   } else {
158     reset_r = FXARGB_R(src_plt[0]);
159     reset_g = FXARGB_G(src_plt[0]);
160     reset_b = FXARGB_B(src_plt[0]);
161     set_r = FXARGB_R(src_plt[1]);
162     set_g = FXARGB_G(src_plt[1]);
163     set_b = FXARGB_B(src_plt[1]);
164   }
165   gray[0] = FXRGB2GRAY(reset_r, reset_g, reset_b);
166   gray[1] = FXRGB2GRAY(set_r, set_g, set_b);
167 
168   for (int row = 0; row < height; ++row) {
169     uint8_t* dest_scan = dest_buf + row * dest_pitch;
170     memset(dest_scan, gray[0], width);
171     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
172     for (int col = src_left; col < src_left + width; ++col) {
173       if (src_scan[col / 8] & (1 << (7 - col % 8)))
174         *dest_scan = gray[1];
175       ++dest_scan;
176     }
177   }
178 }
179 
ConvertBuffer_8bppPlt2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)180 void ConvertBuffer_8bppPlt2Gray(uint8_t* dest_buf,
181                                 int dest_pitch,
182                                 int width,
183                                 int height,
184                                 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
185                                 int src_left,
186                                 int src_top) {
187   uint32_t* src_plt = pSrcBitmap->GetPalette();
188   uint8_t gray[256];
189   if (pSrcBitmap->IsCmykImage()) {
190     uint8_t r;
191     uint8_t g;
192     uint8_t b;
193     for (size_t i = 0; i < FX_ArraySize(gray); ++i) {
194       std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
195           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
196           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
197       gray[i] = FXRGB2GRAY(r, g, b);
198     }
199   } else {
200     for (size_t i = 0; i < FX_ArraySize(gray); ++i) {
201       gray[i] = FXRGB2GRAY(FXARGB_R(src_plt[i]), FXARGB_G(src_plt[i]),
202                            FXARGB_B(src_plt[i]));
203     }
204   }
205 
206   for (int row = 0; row < height; ++row) {
207     uint8_t* dest_scan = dest_buf + row * dest_pitch;
208     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
209     for (int col = 0; col < width; ++col)
210       *dest_scan++ = gray[*src_scan++];
211   }
212 }
213 
ConvertBuffer_RgbOrCmyk2Gray(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)214 void ConvertBuffer_RgbOrCmyk2Gray(uint8_t* dest_buf,
215                                   int dest_pitch,
216                                   int width,
217                                   int height,
218                                   const RetainPtr<CFX_DIBBase>& pSrcBitmap,
219                                   int src_left,
220                                   int src_top) {
221   int Bpp = pSrcBitmap->GetBPP() / 8;
222   if (pSrcBitmap->IsCmykImage()) {
223     for (int row = 0; row < height; ++row) {
224       uint8_t* dest_scan = dest_buf + row * dest_pitch;
225       const uint8_t* src_scan =
226           pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
227       for (int col = 0; col < width; ++col) {
228         uint8_t r;
229         uint8_t g;
230         uint8_t b;
231         std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
232             FXSYS_GetCValue(static_cast<uint32_t>(src_scan[0])),
233             FXSYS_GetMValue(static_cast<uint32_t>(src_scan[1])),
234             FXSYS_GetYValue(static_cast<uint32_t>(src_scan[2])),
235             FXSYS_GetKValue(static_cast<uint32_t>(src_scan[3])));
236         *dest_scan++ = FXRGB2GRAY(r, g, b);
237         src_scan += 4;
238       }
239     }
240   } else {
241     for (int row = 0; row < height; ++row) {
242       uint8_t* dest_scan = dest_buf + row * dest_pitch;
243       const uint8_t* src_scan =
244           pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
245       for (int col = 0; col < width; ++col) {
246         *dest_scan++ = FXRGB2GRAY(src_scan[2], src_scan[1], src_scan[0]);
247         src_scan += Bpp;
248       }
249     }
250   }
251 }
252 
ConvertBuffer_IndexCopy(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)253 void ConvertBuffer_IndexCopy(uint8_t* dest_buf,
254                              int dest_pitch,
255                              int width,
256                              int height,
257                              const RetainPtr<CFX_DIBBase>& pSrcBitmap,
258                              int src_left,
259                              int src_top) {
260   if (pSrcBitmap->GetBPP() == 1) {
261     for (int row = 0; row < height; ++row) {
262       uint8_t* dest_scan = dest_buf + row * dest_pitch;
263       // Set all destination pixels to be white initially.
264       memset(dest_scan, 255, width);
265       const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
266       for (int col = src_left; col < src_left + width; ++col) {
267         // If the source bit is set, then set the destination pixel to be black.
268         if (src_scan[col / 8] & (1 << (7 - col % 8)))
269           *dest_scan = 0;
270 
271         ++dest_scan;
272       }
273     }
274   } else {
275     for (int row = 0; row < height; ++row) {
276       uint8_t* dest_scan = dest_buf + row * dest_pitch;
277       const uint8_t* src_scan =
278           pSrcBitmap->GetScanline(src_top + row) + src_left;
279       memcpy(dest_scan, src_scan, width);
280     }
281   }
282 }
283 
ConvertBuffer_Plt2PltRgb8(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top,uint32_t * dst_plt)284 void ConvertBuffer_Plt2PltRgb8(uint8_t* dest_buf,
285                                int dest_pitch,
286                                int width,
287                                int height,
288                                const RetainPtr<CFX_DIBBase>& pSrcBitmap,
289                                int src_left,
290                                int src_top,
291                                uint32_t* dst_plt) {
292   ConvertBuffer_IndexCopy(dest_buf, dest_pitch, width, height, pSrcBitmap,
293                           src_left, src_top);
294   uint32_t* src_plt = pSrcBitmap->GetPalette();
295   size_t plt_size = pSrcBitmap->GetPaletteSize();
296   if (pSrcBitmap->IsCmykImage()) {
297     for (size_t i = 0; i < plt_size; ++i) {
298       uint8_t r;
299       uint8_t g;
300       uint8_t b;
301       std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
302           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
303           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
304       dst_plt[i] = ArgbEncode(0xff, r, g, b);
305     }
306   } else {
307     memcpy(dst_plt, src_plt, plt_size * 4);
308   }
309 }
310 
ConvertBuffer_Rgb2PltRgb8(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top,uint32_t * dst_plt)311 void ConvertBuffer_Rgb2PltRgb8(uint8_t* dest_buf,
312                                int dest_pitch,
313                                int width,
314                                int height,
315                                const RetainPtr<CFX_DIBBase>& pSrcBitmap,
316                                int src_left,
317                                int src_top,
318                                uint32_t* dst_plt) {
319   int bpp = pSrcBitmap->GetBPP() / 8;
320   CFX_Palette palette(pSrcBitmap);
321   const std::pair<uint32_t, uint32_t>* Luts = palette.GetLuts();
322   int lut = palette.GetLutCount();
323   const uint32_t* pal = palette.GetPalette();
324   if (lut > 256) {
325     int err;
326     int min_err;
327     int lut_256 = lut - 256;
328     for (int row = 0; row < lut_256; ++row) {
329       min_err = 1000000;
330       uint8_t r;
331       uint8_t g;
332       uint8_t b;
333       ColorDecode(Luts[row].second, &r, &g, &b);
334       uint32_t clrindex = 0;
335       for (int col = 0; col < 256; ++col) {
336         uint32_t p_color = pal[col];
337         int d_r = r - static_cast<uint8_t>(p_color >> 16);
338         int d_g = g - static_cast<uint8_t>(p_color >> 8);
339         int d_b = b - static_cast<uint8_t>(p_color);
340         err = d_r * d_r + d_g * d_g + d_b * d_b;
341         if (err < min_err) {
342           min_err = err;
343           clrindex = col;
344         }
345       }
346       palette.SetAmountLut(row, clrindex);
347     }
348   }
349   int32_t lut_1 = lut - 1;
350   for (int row = 0; row < height; ++row) {
351     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
352     uint8_t* dest_scan = dest_buf + row * dest_pitch;
353     for (int col = 0; col < width; ++col) {
354       const uint8_t* src_port = src_scan + col * bpp;
355       int r = src_port[2] & 0xf0;
356       int g = src_port[1] & 0xf0;
357       int b = src_port[0] & 0xf0;
358       uint32_t clrindex = (r << 4) + g + (b >> 4);
359       for (int i = lut_1; i >= 0; --i)
360         if (clrindex == Luts[i].second) {
361           *(dest_scan + col) = static_cast<uint8_t>(Luts[i].first);
362           break;
363         }
364     }
365   }
366   memcpy(dst_plt, pal, sizeof(uint32_t) * 256);
367 }
368 
ConvertBuffer_1bppMask2Rgb(FXDIB_Format dest_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)369 void ConvertBuffer_1bppMask2Rgb(FXDIB_Format dest_format,
370                                 uint8_t* dest_buf,
371                                 int dest_pitch,
372                                 int width,
373                                 int height,
374                                 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
375                                 int src_left,
376                                 int src_top) {
377   int comps = GetCompsFromFormat(dest_format);
378   static constexpr uint8_t kSetGray = 0xff;
379   static constexpr uint8_t kResetGray = 0x00;
380   for (int row = 0; row < height; ++row) {
381     uint8_t* dest_scan = dest_buf + row * dest_pitch;
382     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
383     for (int col = src_left; col < src_left + width; ++col) {
384       if (src_scan[col / 8] & (1 << (7 - col % 8))) {
385         dest_scan[0] = kSetGray;
386         dest_scan[1] = kSetGray;
387         dest_scan[2] = kSetGray;
388       } else {
389         dest_scan[0] = kResetGray;
390         dest_scan[1] = kResetGray;
391         dest_scan[2] = kResetGray;
392       }
393       dest_scan += comps;
394     }
395   }
396 }
397 
ConvertBuffer_8bppMask2Rgb(FXDIB_Format dest_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)398 void ConvertBuffer_8bppMask2Rgb(FXDIB_Format dest_format,
399                                 uint8_t* dest_buf,
400                                 int dest_pitch,
401                                 int width,
402                                 int height,
403                                 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
404                                 int src_left,
405                                 int src_top) {
406   int comps = GetCompsFromFormat(dest_format);
407   for (int row = 0; row < height; ++row) {
408     uint8_t* dest_scan = dest_buf + row * dest_pitch;
409     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
410     uint8_t src_pixel;
411     for (int col = 0; col < width; ++col) {
412       src_pixel = *src_scan++;
413       *dest_scan++ = src_pixel;
414       *dest_scan++ = src_pixel;
415       *dest_scan = src_pixel;
416       dest_scan += comps - 2;
417     }
418   }
419 }
420 
ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dest_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)421 void ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dest_format,
422                                uint8_t* dest_buf,
423                                int dest_pitch,
424                                int width,
425                                int height,
426                                const RetainPtr<CFX_DIBBase>& pSrcBitmap,
427                                int src_left,
428                                int src_top) {
429   int comps = GetCompsFromFormat(dest_format);
430   uint32_t* src_plt = pSrcBitmap->GetPalette();
431   uint32_t plt[2];
432   uint8_t* bgr_ptr = reinterpret_cast<uint8_t*>(plt);
433   if (pSrcBitmap->IsCmykImage()) {
434     plt[0] = FXCMYK_TODIB(src_plt[0]);
435     plt[1] = FXCMYK_TODIB(src_plt[1]);
436   } else {
437     bgr_ptr[0] = FXARGB_B(src_plt[0]);
438     bgr_ptr[1] = FXARGB_G(src_plt[0]);
439     bgr_ptr[2] = FXARGB_R(src_plt[0]);
440     bgr_ptr[3] = FXARGB_B(src_plt[1]);
441     bgr_ptr[4] = FXARGB_G(src_plt[1]);
442     bgr_ptr[5] = FXARGB_R(src_plt[1]);
443   }
444 
445   if (pSrcBitmap->IsCmykImage()) {
446     std::tie(bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]) = AdobeCMYK_to_sRGB1(
447         FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]),
448         FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]));
449     std::tie(bgr_ptr[5], bgr_ptr[4], bgr_ptr[3]) = AdobeCMYK_to_sRGB1(
450         FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]),
451         FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]));
452   }
453 
454   for (int row = 0; row < height; ++row) {
455     uint8_t* dest_scan = dest_buf + row * dest_pitch;
456     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
457     for (int col = src_left; col < src_left + width; ++col) {
458       if (src_scan[col / 8] & (1 << (7 - col % 8))) {
459         *dest_scan++ = bgr_ptr[3];
460         *dest_scan++ = bgr_ptr[4];
461         *dest_scan = bgr_ptr[5];
462       } else {
463         *dest_scan++ = bgr_ptr[0];
464         *dest_scan++ = bgr_ptr[1];
465         *dest_scan = bgr_ptr[2];
466       }
467       dest_scan += comps - 2;
468     }
469   }
470 }
471 
ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dest_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)472 void ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dest_format,
473                                uint8_t* dest_buf,
474                                int dest_pitch,
475                                int width,
476                                int height,
477                                const RetainPtr<CFX_DIBBase>& pSrcBitmap,
478                                int src_left,
479                                int src_top) {
480   int comps = GetCompsFromFormat(dest_format);
481   uint32_t* src_plt = pSrcBitmap->GetPalette();
482   uint32_t plt[256];
483   uint8_t* bgr_ptr = reinterpret_cast<uint8_t*>(plt);
484   if (!pSrcBitmap->IsCmykImage()) {
485     for (int i = 0; i < 256; ++i) {
486       *bgr_ptr++ = FXARGB_B(src_plt[i]);
487       *bgr_ptr++ = FXARGB_G(src_plt[i]);
488       *bgr_ptr++ = FXARGB_R(src_plt[i]);
489     }
490     bgr_ptr = reinterpret_cast<uint8_t*>(plt);
491   }
492 
493   if (pSrcBitmap->IsCmykImage()) {
494     for (int i = 0; i < 256; ++i) {
495       std::tie(bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]) = AdobeCMYK_to_sRGB1(
496           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
497           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
498       bgr_ptr += 3;
499     }
500     bgr_ptr = reinterpret_cast<uint8_t*>(plt);
501   }
502 
503   for (int row = 0; row < height; ++row) {
504     uint8_t* dest_scan = dest_buf + row * dest_pitch;
505     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
506     for (int col = 0; col < width; ++col) {
507       uint8_t* src_pixel = bgr_ptr + 3 * (*src_scan++);
508       *dest_scan++ = *src_pixel++;
509       *dest_scan++ = *src_pixel++;
510       *dest_scan = *src_pixel++;
511       dest_scan += comps - 2;
512     }
513   }
514 }
515 
ConvertBuffer_24bppRgb2Rgb24(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)516 void ConvertBuffer_24bppRgb2Rgb24(uint8_t* dest_buf,
517                                   int dest_pitch,
518                                   int width,
519                                   int height,
520                                   const RetainPtr<CFX_DIBBase>& pSrcBitmap,
521                                   int src_left,
522                                   int src_top) {
523   for (int row = 0; row < height; ++row) {
524     uint8_t* dest_scan = dest_buf + row * dest_pitch;
525     const uint8_t* src_scan =
526         pSrcBitmap->GetScanline(src_top + row) + src_left * 3;
527     memcpy(dest_scan, src_scan, width * 3);
528   }
529 }
530 
ConvertBuffer_32bppRgb2Rgb24(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)531 void ConvertBuffer_32bppRgb2Rgb24(uint8_t* dest_buf,
532                                   int dest_pitch,
533                                   int width,
534                                   int height,
535                                   const RetainPtr<CFX_DIBBase>& pSrcBitmap,
536                                   int src_left,
537                                   int src_top) {
538   for (int row = 0; row < height; ++row) {
539     uint8_t* dest_scan = dest_buf + row * dest_pitch;
540     const uint8_t* src_scan =
541         pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
542     for (int col = 0; col < width; ++col) {
543       *dest_scan++ = *src_scan++;
544       *dest_scan++ = *src_scan++;
545       *dest_scan++ = *src_scan++;
546       ++src_scan;
547     }
548   }
549 }
550 
ConvertBuffer_Rgb2Rgb32(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)551 void ConvertBuffer_Rgb2Rgb32(uint8_t* dest_buf,
552                              int dest_pitch,
553                              int width,
554                              int height,
555                              const RetainPtr<CFX_DIBBase>& pSrcBitmap,
556                              int src_left,
557                              int src_top) {
558   int comps = pSrcBitmap->GetBPP() / 8;
559   for (int row = 0; row < height; ++row) {
560     uint8_t* dest_scan = dest_buf + row * dest_pitch;
561     const uint8_t* src_scan =
562         pSrcBitmap->GetScanline(src_top + row) + src_left * comps;
563     for (int col = 0; col < width; ++col) {
564       *dest_scan++ = *src_scan++;
565       *dest_scan++ = *src_scan++;
566       *dest_scan++ = *src_scan++;
567       ++dest_scan;
568       src_scan += comps - 3;
569     }
570   }
571 }
572 
ConvertBuffer_32bppCmyk2Rgb32(uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)573 void ConvertBuffer_32bppCmyk2Rgb32(uint8_t* dest_buf,
574                                    int dest_pitch,
575                                    int width,
576                                    int height,
577                                    const RetainPtr<CFX_DIBBase>& pSrcBitmap,
578                                    int src_left,
579                                    int src_top) {
580   for (int row = 0; row < height; ++row) {
581     uint8_t* dest_scan = dest_buf + row * dest_pitch;
582     const uint8_t* src_scan =
583         pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
584     for (int col = 0; col < width; ++col) {
585       std::tie(dest_scan[2], dest_scan[1], dest_scan[0]) = AdobeCMYK_to_sRGB1(
586           src_scan[0], src_scan[1], src_scan[2], src_scan[3]);
587       dest_scan += 4;
588       src_scan += 4;
589     }
590   }
591 }
592 
ConvertBuffer_8bppMask(int bpp,uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)593 bool ConvertBuffer_8bppMask(int bpp,
594                             uint8_t* dest_buf,
595                             int dest_pitch,
596                             int width,
597                             int height,
598                             const RetainPtr<CFX_DIBBase>& pSrcBitmap,
599                             int src_left,
600                             int src_top) {
601   switch (bpp) {
602     case 1:
603       if (pSrcBitmap->GetPalette()) {
604         ConvertBuffer_1bppPlt2Gray(dest_buf, dest_pitch, width, height,
605                                    pSrcBitmap, src_left, src_top);
606       } else {
607         ConvertBuffer_1bppMask2Gray(dest_buf, dest_pitch, width, height,
608                                     pSrcBitmap, src_left, src_top);
609       }
610       return true;
611     case 8:
612       if (pSrcBitmap->GetPalette()) {
613         ConvertBuffer_8bppPlt2Gray(dest_buf, dest_pitch, width, height,
614                                    pSrcBitmap, src_left, src_top);
615       } else {
616         ConvertBuffer_8bppMask2Gray(dest_buf, dest_pitch, width, height,
617                                     pSrcBitmap, src_left, src_top);
618       }
619       return true;
620     case 24:
621     case 32:
622       ConvertBuffer_RgbOrCmyk2Gray(dest_buf, dest_pitch, width, height,
623                                    pSrcBitmap, src_left, src_top);
624       return true;
625     default:
626       return false;
627   }
628 }
629 
ConvertBuffer_Rgb(int bpp,FXDIB_Format dest_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)630 bool ConvertBuffer_Rgb(int bpp,
631                        FXDIB_Format dest_format,
632                        uint8_t* dest_buf,
633                        int dest_pitch,
634                        int width,
635                        int height,
636                        const RetainPtr<CFX_DIBBase>& pSrcBitmap,
637                        int src_left,
638                        int src_top) {
639   switch (bpp) {
640     case 1:
641       if (pSrcBitmap->GetPalette()) {
642         ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
643                                   height, pSrcBitmap, src_left, src_top);
644       } else {
645         ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
646                                    height, pSrcBitmap, src_left, src_top);
647       }
648       return true;
649     case 8:
650       if (pSrcBitmap->GetPalette()) {
651         ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
652                                   height, pSrcBitmap, src_left, src_top);
653       } else {
654         ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
655                                    height, pSrcBitmap, src_left, src_top);
656       }
657       return true;
658     case 24:
659       ConvertBuffer_24bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
660                                    pSrcBitmap, src_left, src_top);
661       return true;
662     case 32:
663       ConvertBuffer_32bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
664                                    pSrcBitmap, src_left, src_top);
665       return true;
666     default:
667       return false;
668   }
669 }
670 
ConvertBuffer_Argb(int bpp,bool cmyk,FXDIB_Format dest_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)671 bool ConvertBuffer_Argb(int bpp,
672                         bool cmyk,
673                         FXDIB_Format dest_format,
674                         uint8_t* dest_buf,
675                         int dest_pitch,
676                         int width,
677                         int height,
678                         const RetainPtr<CFX_DIBBase>& pSrcBitmap,
679                         int src_left,
680                         int src_top) {
681   switch (bpp) {
682     case 1:
683       if (pSrcBitmap->GetPalette()) {
684         ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
685                                   height, pSrcBitmap, src_left, src_top);
686       } else {
687         ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
688                                    height, pSrcBitmap, src_left, src_top);
689       }
690       return true;
691     case 8:
692       if (pSrcBitmap->GetPalette()) {
693         ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
694                                   height, pSrcBitmap, src_left, src_top);
695       } else {
696         ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
697                                    height, pSrcBitmap, src_left, src_top);
698       }
699       return true;
700     case 24:
701     case 32:
702       if (cmyk) {
703         ConvertBuffer_32bppCmyk2Rgb32(dest_buf, dest_pitch, width, height,
704                                       pSrcBitmap, src_left, src_top);
705       } else {
706         ConvertBuffer_Rgb2Rgb32(dest_buf, dest_pitch, width, height, pSrcBitmap,
707                                 src_left, src_top);
708       }
709       return true;
710     default:
711       return false;
712   }
713 }
714 
715 }  // namespace
716 
CFX_DIBBase()717 CFX_DIBBase::CFX_DIBBase()
718     : m_Width(0), m_Height(0), m_bpp(0), m_AlphaFlag(0), m_Pitch(0) {}
719 
~CFX_DIBBase()720 CFX_DIBBase::~CFX_DIBBase() {}
721 
GetBuffer() const722 uint8_t* CFX_DIBBase::GetBuffer() const {
723   return nullptr;
724 }
725 
SkipToScanline(int line,PauseIndicatorIface * pPause) const726 bool CFX_DIBBase::SkipToScanline(int line, PauseIndicatorIface* pPause) const {
727   return false;
728 }
729 
Clone(const FX_RECT * pClip) const730 RetainPtr<CFX_DIBitmap> CFX_DIBBase::Clone(const FX_RECT* pClip) const {
731   FX_RECT rect(0, 0, m_Width, m_Height);
732   if (pClip) {
733     rect.Intersect(*pClip);
734     if (rect.IsEmpty())
735       return nullptr;
736   }
737   auto pNewBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
738   if (!pNewBitmap->Create(rect.Width(), rect.Height(), GetFormat()))
739     return nullptr;
740 
741   pNewBitmap->SetPalette(m_pPalette.get());
742   pNewBitmap->SetAlphaMask(m_pAlphaMask, pClip);
743   if (GetBPP() == 1 && rect.left % 8 != 0) {
744     int left_shift = rect.left % 32;
745     int right_shift = 32 - left_shift;
746     int dword_count = pNewBitmap->m_Pitch / 4;
747     for (int row = rect.top; row < rect.bottom; ++row) {
748       const uint32_t* src_scan =
749           reinterpret_cast<const uint32_t*>(GetScanline(row)) + rect.left / 32;
750       uint32_t* dest_scan = reinterpret_cast<uint32_t*>(
751           pNewBitmap->GetWritableScanline(row - rect.top));
752       for (int i = 0; i < dword_count; ++i) {
753         dest_scan[i] =
754             (src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift);
755       }
756     }
757   } else {
758     int copy_len = (pNewBitmap->GetWidth() * pNewBitmap->GetBPP() + 7) / 8;
759     if (m_Pitch < static_cast<uint32_t>(copy_len))
760       copy_len = m_Pitch;
761 
762     for (int row = rect.top; row < rect.bottom; ++row) {
763       const uint8_t* src_scan = GetScanline(row) + rect.left * m_bpp / 8;
764       uint8_t* dest_scan = pNewBitmap->GetWritableScanline(row - rect.top);
765       memcpy(dest_scan, src_scan, copy_len);
766     }
767   }
768   return pNewBitmap;
769 }
770 
BuildPalette()771 void CFX_DIBBase::BuildPalette() {
772   if (m_pPalette)
773     return;
774 
775   if (GetBPP() == 1) {
776     m_pPalette.reset(FX_Alloc(uint32_t, 2));
777     if (IsCmykImage()) {
778       m_pPalette.get()[0] = 0xff;
779       m_pPalette.get()[1] = 0;
780     } else {
781       m_pPalette.get()[0] = 0xff000000;
782       m_pPalette.get()[1] = 0xffffffff;
783     }
784   } else if (GetBPP() == 8) {
785     m_pPalette.reset(FX_Alloc(uint32_t, 256));
786     if (IsCmykImage()) {
787       for (int i = 0; i < 256; ++i)
788         m_pPalette.get()[i] = 0xff - i;
789     } else {
790       for (int i = 0; i < 256; ++i)
791         m_pPalette.get()[i] = 0xff000000 | (i * 0x10101);
792     }
793   }
794 }
795 
BuildAlphaMask()796 bool CFX_DIBBase::BuildAlphaMask() {
797   if (m_pAlphaMask)
798     return true;
799 
800   m_pAlphaMask = pdfium::MakeRetain<CFX_DIBitmap>();
801   if (!m_pAlphaMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
802     m_pAlphaMask = nullptr;
803     return false;
804   }
805   memset(m_pAlphaMask->GetBuffer(), 0xff,
806          m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch());
807   return true;
808 }
809 
GetPaletteSize() const810 size_t CFX_DIBBase::GetPaletteSize() const {
811   if (IsAlphaMask())
812     return 0;
813 
814   switch (m_bpp) {
815     case 1:
816       return 2;
817     case 8:
818       return 256;
819     default:
820       return 0;
821   }
822 }
823 
GetPaletteArgb(int index) const824 uint32_t CFX_DIBBase::GetPaletteArgb(int index) const {
825   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
826   if (m_pPalette)
827     return m_pPalette.get()[index];
828 
829   if (IsCmykImage()) {
830     if (GetBPP() == 1)
831       return index ? 0 : 0xff;
832 
833     return 0xff - index;
834   }
835   if (GetBPP() == 1)
836     return index ? 0xffffffff : 0xff000000;
837 
838   return index * 0x10101 | 0xff000000;
839 }
840 
SetPaletteArgb(int index,uint32_t color)841 void CFX_DIBBase::SetPaletteArgb(int index, uint32_t color) {
842   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
843   if (!m_pPalette) {
844     BuildPalette();
845   }
846   m_pPalette.get()[index] = color;
847 }
848 
FindPalette(uint32_t color) const849 int CFX_DIBBase::FindPalette(uint32_t color) const {
850   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
851   if (!m_pPalette) {
852     if (IsCmykImage()) {
853       if (GetBPP() == 1)
854         return (static_cast<uint8_t>(color) == 0xff) ? 0 : 1;
855 
856       return 0xff - static_cast<uint8_t>(color);
857     }
858     if (GetBPP() == 1)
859       return (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
860 
861     return static_cast<uint8_t>(color);
862   }
863   int palsize = (1 << GetBPP());
864   for (int i = 0; i < palsize; ++i) {
865     if (m_pPalette.get()[i] == color)
866       return i;
867   }
868   return -1;
869 }
870 
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)871 bool CFX_DIBBase::GetOverlapRect(int& dest_left,
872                                  int& dest_top,
873                                  int& width,
874                                  int& height,
875                                  int src_width,
876                                  int src_height,
877                                  int& src_left,
878                                  int& src_top,
879                                  const CFX_ClipRgn* pClipRgn) {
880   if (width == 0 || height == 0)
881     return false;
882 
883   ASSERT(width > 0);
884   ASSERT(height > 0);
885 
886   if (dest_left > m_Width || dest_top > m_Height) {
887     width = 0;
888     height = 0;
889     return false;
890   }
891   int x_offset = dest_left - src_left;
892   int y_offset = dest_top - src_top;
893   FX_RECT src_rect(src_left, src_top, src_left + width, src_top + height);
894   FX_RECT src_bound(0, 0, src_width, src_height);
895   src_rect.Intersect(src_bound);
896   FX_RECT dest_rect(src_rect.left + x_offset, src_rect.top + y_offset,
897                     src_rect.right + x_offset, src_rect.bottom + y_offset);
898   FX_RECT dest_bound(0, 0, m_Width, m_Height);
899   dest_rect.Intersect(dest_bound);
900   if (pClipRgn)
901     dest_rect.Intersect(pClipRgn->GetBox());
902   dest_left = dest_rect.left;
903   dest_top = dest_rect.top;
904 
905   pdfium::base::CheckedNumeric<int> safe_src_left = dest_left;
906   safe_src_left -= x_offset;
907   if (!safe_src_left.IsValid())
908     return false;
909   src_left = safe_src_left.ValueOrDie();
910 
911   pdfium::base::CheckedNumeric<int> safe_src_top = dest_top;
912   safe_src_top -= y_offset;
913   if (!safe_src_top.IsValid())
914     return false;
915   src_top = safe_src_top.ValueOrDie();
916 
917   width = dest_rect.right - dest_rect.left;
918   height = dest_rect.bottom - dest_rect.top;
919   return width != 0 && height != 0;
920 }
921 
SetPalette(const uint32_t * pSrc)922 void CFX_DIBBase::SetPalette(const uint32_t* pSrc) {
923   static const uint32_t kPaletteSize = 256;
924   if (!pSrc || GetBPP() > 8) {
925     m_pPalette.reset();
926     return;
927   }
928   uint32_t pal_size = 1 << GetBPP();
929   if (!m_pPalette)
930     m_pPalette.reset(FX_Alloc(uint32_t, pal_size));
931   pal_size = std::min(pal_size, kPaletteSize);
932   memcpy(m_pPalette.get(), pSrc, pal_size * sizeof(uint32_t));
933 }
934 
GetPalette(uint32_t * pal,int alpha) const935 void CFX_DIBBase::GetPalette(uint32_t* pal, int alpha) const {
936   ASSERT(GetBPP() <= 8);
937   ASSERT(!IsCmykImage());
938 
939   if (GetBPP() == 1) {
940     pal[0] = ((m_pPalette ? m_pPalette.get()[0] : 0xff000000) & 0xffffff) |
941              (alpha << 24);
942     pal[1] = ((m_pPalette ? m_pPalette.get()[1] : 0xffffffff) & 0xffffff) |
943              (alpha << 24);
944     return;
945   }
946   if (m_pPalette) {
947     for (int i = 0; i < 256; ++i)
948       pal[i] = (m_pPalette.get()[i] & 0x00ffffff) | (alpha << 24);
949   } else {
950     for (int i = 0; i < 256; ++i)
951       pal[i] = (i * 0x10101) | (alpha << 24);
952   }
953 }
954 
CloneAlphaMask() const955 RetainPtr<CFX_DIBitmap> CFX_DIBBase::CloneAlphaMask() const {
956   ASSERT(GetFormat() == FXDIB_Argb);
957   FX_RECT rect(0, 0, m_Width, m_Height);
958   auto pMask = pdfium::MakeRetain<CFX_DIBitmap>();
959   if (!pMask->Create(rect.Width(), rect.Height(), FXDIB_8bppMask))
960     return nullptr;
961 
962   for (int row = rect.top; row < rect.bottom; ++row) {
963     const uint8_t* src_scan = GetScanline(row) + rect.left * 4 + 3;
964     uint8_t* dest_scan = pMask->GetWritableScanline(row - rect.top);
965     for (int col = rect.left; col < rect.right; ++col) {
966       *dest_scan++ = *src_scan;
967       src_scan += 4;
968     }
969   }
970   return pMask;
971 }
972 
SetAlphaMask(const RetainPtr<CFX_DIBBase> & pAlphaMask,const FX_RECT * pClip)973 bool CFX_DIBBase::SetAlphaMask(const RetainPtr<CFX_DIBBase>& pAlphaMask,
974                                const FX_RECT* pClip) {
975   if (!HasAlpha() || GetFormat() == FXDIB_Argb)
976     return false;
977 
978   if (!pAlphaMask) {
979     m_pAlphaMask->Clear(0xff000000);
980     return true;
981   }
982   FX_RECT rect(0, 0, pAlphaMask->m_Width, pAlphaMask->m_Height);
983   if (pClip) {
984     rect.Intersect(*pClip);
985     if (rect.IsEmpty() || rect.Width() != m_Width ||
986         rect.Height() != m_Height) {
987       return false;
988     }
989   } else {
990     if (pAlphaMask->m_Width != m_Width || pAlphaMask->m_Height != m_Height)
991       return false;
992   }
993   for (int row = 0; row < m_Height; ++row) {
994     memcpy(m_pAlphaMask->GetWritableScanline(row),
995            pAlphaMask->GetScanline(row + rect.top) + rect.left,
996            m_pAlphaMask->m_Pitch);
997   }
998   return true;
999 }
1000 
FlipImage(bool bXFlip,bool bYFlip) const1001 RetainPtr<CFX_DIBitmap> CFX_DIBBase::FlipImage(bool bXFlip, bool bYFlip) const {
1002   auto pFlipped = pdfium::MakeRetain<CFX_DIBitmap>();
1003   if (!pFlipped->Create(m_Width, m_Height, GetFormat()))
1004     return nullptr;
1005 
1006   pFlipped->SetPalette(m_pPalette.get());
1007   uint8_t* pDestBuffer = pFlipped->GetBuffer();
1008   int Bpp = m_bpp / 8;
1009   for (int row = 0; row < m_Height; ++row) {
1010     const uint8_t* src_scan = GetScanline(row);
1011     uint8_t* dest_scan =
1012         pDestBuffer + m_Pitch * (bYFlip ? (m_Height - row - 1) : row);
1013     if (!bXFlip) {
1014       memcpy(dest_scan, src_scan, m_Pitch);
1015       continue;
1016     }
1017     if (m_bpp == 1) {
1018       memset(dest_scan, 0, m_Pitch);
1019       for (int col = 0; col < m_Width; ++col) {
1020         if (src_scan[col / 8] & (1 << (7 - col % 8))) {
1021           int dest_col = m_Width - col - 1;
1022           dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8));
1023         }
1024       }
1025       continue;
1026     }
1027 
1028     dest_scan += (m_Width - 1) * Bpp;
1029     if (Bpp == 1) {
1030       for (int col = 0; col < m_Width; ++col) {
1031         *dest_scan = *src_scan;
1032         --dest_scan;
1033         ++src_scan;
1034       }
1035     } else if (Bpp == 3) {
1036       for (int col = 0; col < m_Width; ++col) {
1037         dest_scan[0] = src_scan[0];
1038         dest_scan[1] = src_scan[1];
1039         dest_scan[2] = src_scan[2];
1040         dest_scan -= 3;
1041         src_scan += 3;
1042       }
1043     } else {
1044       ASSERT(Bpp == 4);
1045       for (int col = 0; col < m_Width; ++col) {
1046         const auto* src_scan32 = reinterpret_cast<const uint32_t*>(src_scan);
1047         uint32_t* dest_scan32 = reinterpret_cast<uint32_t*>(dest_scan);
1048         *dest_scan32 = *src_scan32;
1049         dest_scan -= 4;
1050         src_scan += 4;
1051       }
1052     }
1053   }
1054   if (m_pAlphaMask) {
1055     pDestBuffer = pFlipped->m_pAlphaMask->GetBuffer();
1056     uint32_t dest_pitch = pFlipped->m_pAlphaMask->GetPitch();
1057     for (int row = 0; row < m_Height; ++row) {
1058       const uint8_t* src_scan = m_pAlphaMask->GetScanline(row);
1059       uint8_t* dest_scan =
1060           pDestBuffer + dest_pitch * (bYFlip ? (m_Height - row - 1) : row);
1061       if (!bXFlip) {
1062         memcpy(dest_scan, src_scan, dest_pitch);
1063         continue;
1064       }
1065       dest_scan += (m_Width - 1);
1066       for (int col = 0; col < m_Width; ++col) {
1067         *dest_scan = *src_scan;
1068         --dest_scan;
1069         ++src_scan;
1070       }
1071     }
1072   }
1073   return pFlipped;
1074 }
1075 
CloneConvert(FXDIB_Format dest_format)1076 RetainPtr<CFX_DIBitmap> CFX_DIBBase::CloneConvert(FXDIB_Format dest_format) {
1077   if (dest_format == GetFormat())
1078     return Clone(nullptr);
1079 
1080   auto pClone = pdfium::MakeRetain<CFX_DIBitmap>();
1081   if (!pClone->Create(m_Width, m_Height, dest_format))
1082     return nullptr;
1083 
1084   RetainPtr<CFX_DIBitmap> pSrcAlpha;
1085   if (HasAlpha()) {
1086     pSrcAlpha = (GetFormat() == FXDIB_Argb) ? CloneAlphaMask() : m_pAlphaMask;
1087     if (!pSrcAlpha)
1088       return nullptr;
1089   }
1090   if (GetIsAlphaFromFormat(dest_format)) {
1091     bool ret;
1092     if (dest_format == FXDIB_Argb) {
1093       ret = pSrcAlpha ? pClone->LoadChannelFromAlpha(FXDIB_Alpha, pSrcAlpha)
1094                       : pClone->LoadChannel(FXDIB_Alpha, 0xff);
1095     } else {
1096       ret = pClone->SetAlphaMask(pSrcAlpha, nullptr);
1097     }
1098     if (!ret)
1099       return nullptr;
1100   }
1101 
1102   RetainPtr<CFX_DIBBase> holder(this);
1103   std::unique_ptr<uint32_t, FxFreeDeleter> pal_8bpp;
1104   if (!ConvertBuffer(dest_format, pClone->GetBuffer(), pClone->GetPitch(),
1105                      m_Width, m_Height, holder, 0, 0, &pal_8bpp)) {
1106     return nullptr;
1107   }
1108   if (pal_8bpp)
1109     pClone->SetPalette(pal_8bpp.get());
1110 
1111   return pClone;
1112 }
1113 
SwapXY(bool bXFlip,bool bYFlip) const1114 RetainPtr<CFX_DIBitmap> CFX_DIBBase::SwapXY(bool bXFlip, bool bYFlip) const {
1115   FX_RECT dest_clip(0, 0, m_Height, m_Width);
1116   if (dest_clip.IsEmpty())
1117     return nullptr;
1118 
1119   auto pTransBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
1120   int result_height = dest_clip.Height();
1121   int result_width = dest_clip.Width();
1122   if (!pTransBitmap->Create(result_width, result_height, GetFormat()))
1123     return nullptr;
1124 
1125   pTransBitmap->SetPalette(m_pPalette.get());
1126   int dest_pitch = pTransBitmap->GetPitch();
1127   uint8_t* dest_buf = pTransBitmap->GetBuffer();
1128   int row_start = bXFlip ? m_Height - dest_clip.right : dest_clip.left;
1129   int row_end = bXFlip ? m_Height - dest_clip.left : dest_clip.right;
1130   int col_start = bYFlip ? m_Width - dest_clip.bottom : dest_clip.top;
1131   int col_end = bYFlip ? m_Width - dest_clip.top : dest_clip.bottom;
1132   if (GetBPP() == 1) {
1133     memset(dest_buf, 0xff, dest_pitch * result_height);
1134     for (int row = row_start; row < row_end; ++row) {
1135       const uint8_t* src_scan = GetScanline(row);
1136       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
1137                      dest_clip.left;
1138       uint8_t* dest_scan = dest_buf;
1139       if (bYFlip)
1140         dest_scan += (result_height - 1) * dest_pitch;
1141       int dest_step = bYFlip ? -dest_pitch : dest_pitch;
1142       for (int col = col_start; col < col_end; ++col) {
1143         if (!(src_scan[col / 8] & (1 << (7 - col % 8))))
1144           dest_scan[dest_col / 8] &= ~(1 << (7 - dest_col % 8));
1145         dest_scan += dest_step;
1146       }
1147     }
1148   } else {
1149     int nBytes = GetBPP() / 8;
1150     int dest_step = bYFlip ? -dest_pitch : dest_pitch;
1151     if (nBytes == 3)
1152       dest_step -= 2;
1153     for (int row = row_start; row < row_end; ++row) {
1154       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
1155                      dest_clip.left;
1156       uint8_t* dest_scan = dest_buf + dest_col * nBytes;
1157       if (bYFlip)
1158         dest_scan += (result_height - 1) * dest_pitch;
1159       if (nBytes == 4) {
1160         const uint32_t* src_scan =
1161             reinterpret_cast<const uint32_t*>(GetScanline(row)) + col_start;
1162         for (int col = col_start; col < col_end; ++col) {
1163           uint32_t* dest_scan32 = reinterpret_cast<uint32_t*>(dest_scan);
1164           *dest_scan32 = *src_scan++;
1165           dest_scan += dest_step;
1166         }
1167       } else {
1168         const uint8_t* src_scan = GetScanline(row) + col_start * nBytes;
1169         if (nBytes == 1) {
1170           for (int col = col_start; col < col_end; ++col) {
1171             *dest_scan = *src_scan++;
1172             dest_scan += dest_step;
1173           }
1174         } else {
1175           for (int col = col_start; col < col_end; ++col) {
1176             *dest_scan++ = *src_scan++;
1177             *dest_scan++ = *src_scan++;
1178             *dest_scan = *src_scan++;
1179             dest_scan += dest_step;
1180           }
1181         }
1182       }
1183     }
1184   }
1185   if (m_pAlphaMask) {
1186     dest_pitch = pTransBitmap->m_pAlphaMask->GetPitch();
1187     dest_buf = pTransBitmap->m_pAlphaMask->GetBuffer();
1188     int dest_step = bYFlip ? -dest_pitch : dest_pitch;
1189     for (int row = row_start; row < row_end; ++row) {
1190       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
1191                      dest_clip.left;
1192       uint8_t* dest_scan = dest_buf + dest_col;
1193       if (bYFlip)
1194         dest_scan += (result_height - 1) * dest_pitch;
1195       const uint8_t* src_scan = m_pAlphaMask->GetScanline(row) + col_start;
1196       for (int col = col_start; col < col_end; ++col) {
1197         *dest_scan = *src_scan++;
1198         dest_scan += dest_step;
1199       }
1200     }
1201   }
1202   return pTransBitmap;
1203 }
1204 
TransformTo(const CFX_Matrix & mtDest,int * result_left,int * result_top)1205 RetainPtr<CFX_DIBitmap> CFX_DIBBase::TransformTo(const CFX_Matrix& mtDest,
1206                                                  int* result_left,
1207                                                  int* result_top) {
1208   RetainPtr<CFX_DIBBase> holder(this);
1209   CFX_ImageTransformer transformer(holder, mtDest, FXDIB_ResampleOptions(),
1210                                    nullptr);
1211   transformer.Continue(nullptr);
1212   *result_left = transformer.result().left;
1213   *result_top = transformer.result().top;
1214   return transformer.DetachBitmap();
1215 }
1216 
StretchTo(int dest_width,int dest_height,const FXDIB_ResampleOptions & options,const FX_RECT * pClip)1217 RetainPtr<CFX_DIBitmap> CFX_DIBBase::StretchTo(
1218     int dest_width,
1219     int dest_height,
1220     const FXDIB_ResampleOptions& options,
1221     const FX_RECT* pClip) {
1222   RetainPtr<CFX_DIBBase> holder(this);
1223   FX_RECT clip_rect(0, 0, abs(dest_width), abs(dest_height));
1224   if (pClip)
1225     clip_rect.Intersect(*pClip);
1226 
1227   if (clip_rect.IsEmpty())
1228     return nullptr;
1229 
1230   if (dest_width == m_Width && dest_height == m_Height)
1231     return Clone(&clip_rect);
1232 
1233   CFX_BitmapStorer storer;
1234   CFX_ImageStretcher stretcher(&storer, holder, dest_width, dest_height,
1235                                clip_rect, options);
1236   if (stretcher.Start())
1237     stretcher.Continue(nullptr);
1238 
1239   return storer.Detach();
1240 }
1241 
1242 // static
ConvertBuffer(FXDIB_Format dest_format,uint8_t * dest_buf,int dest_pitch,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top,std::unique_ptr<uint32_t,FxFreeDeleter> * p_pal)1243 bool CFX_DIBBase::ConvertBuffer(
1244     FXDIB_Format dest_format,
1245     uint8_t* dest_buf,
1246     int dest_pitch,
1247     int width,
1248     int height,
1249     const RetainPtr<CFX_DIBBase>& pSrcBitmap,
1250     int src_left,
1251     int src_top,
1252     std::unique_ptr<uint32_t, FxFreeDeleter>* p_pal) {
1253   FXDIB_Format src_format = pSrcBitmap->GetFormat();
1254   const int bpp = GetBppFromFormat(src_format);
1255   switch (dest_format) {
1256     case FXDIB_8bppMask: {
1257       return ConvertBuffer_8bppMask(bpp, dest_buf, dest_pitch, width, height,
1258                                     pSrcBitmap, src_left, src_top);
1259     }
1260     case FXDIB_8bppRgb:
1261     case FXDIB_8bppRgba: {
1262       const bool bpp_1_or_8 = (bpp == 1 || bpp == 8);
1263       if (bpp_1_or_8 && !pSrcBitmap->GetPalette()) {
1264         return ConvertBuffer(FXDIB_8bppMask, dest_buf, dest_pitch, width,
1265                              height, pSrcBitmap, src_left, src_top, p_pal);
1266       }
1267       p_pal->reset(FX_Alloc(uint32_t, 256));
1268       if (bpp_1_or_8 && pSrcBitmap->GetPalette()) {
1269         ConvertBuffer_Plt2PltRgb8(dest_buf, dest_pitch, width, height,
1270                                   pSrcBitmap, src_left, src_top, p_pal->get());
1271         return true;
1272       }
1273       if (bpp >= 24) {
1274         ConvertBuffer_Rgb2PltRgb8(dest_buf, dest_pitch, width, height,
1275                                   pSrcBitmap, src_left, src_top, p_pal->get());
1276         return true;
1277       }
1278       return false;
1279     }
1280     case FXDIB_Rgb:
1281     case FXDIB_Rgba: {
1282       return ConvertBuffer_Rgb(bpp, dest_format, dest_buf, dest_pitch, width,
1283                                height, pSrcBitmap, src_left, src_top);
1284     }
1285     case FXDIB_Argb:
1286     case FXDIB_Rgb32: {
1287       return ConvertBuffer_Argb(bpp, GetIsCmykFromFormat(src_format),
1288                                 dest_format, dest_buf, dest_pitch, width,
1289                                 height, pSrcBitmap, src_left, src_top);
1290     }
1291     default:
1292       NOTREACHED();
1293       return false;
1294   }
1295 }
1296