• 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_dibitmap.h"
8 
9 #include <limits>
10 #include <memory>
11 #include <utility>
12 
13 #include "core/fxcodec/fx_codec.h"
14 #include "core/fxge/cfx_cliprgn.h"
15 #include "core/fxge/dib/cfx_scanlinecompositor.h"
16 #include "third_party/base/ptr_util.h"
17 
18 #define MAX_OOM_LIMIT 12000000
19 
20 namespace {
21 
22 const int8_t g_ChannelOffset[] = {0, 2, 1, 0, 0, 1, 2, 3, 3};
23 
24 }  // namespace
25 
CFX_DIBitmap()26 CFX_DIBitmap::CFX_DIBitmap() {
27   m_pPalette = nullptr;
28 #ifdef _SKIA_SUPPORT_PATHS_
29   m_nFormat = Format::kCleared;
30 #endif
31 }
32 
Create(int width,int height,FXDIB_Format format,uint8_t * pBuffer,uint32_t pitch)33 bool CFX_DIBitmap::Create(int width,
34                           int height,
35                           FXDIB_Format format,
36                           uint8_t* pBuffer,
37                           uint32_t pitch) {
38   m_pBuffer = nullptr;
39   m_bpp = static_cast<uint8_t>(format);
40   m_AlphaFlag = static_cast<uint8_t>(format >> 8);
41   m_Width = 0;
42   m_Height = 0;
43   m_Pitch = 0;
44 
45   uint32_t calculatedSize;
46   if (!CFX_DIBitmap::CalculatePitchAndSize(height, width, format, &pitch,
47                                            &calculatedSize))
48     return false;
49 
50   if (pBuffer) {
51     m_pBuffer.Reset(pBuffer);
52   } else {
53     size_t bufferSize = calculatedSize + 4;
54     size_t oomlimit = MAX_OOM_LIMIT;
55     if (bufferSize >= oomlimit) {
56       m_pBuffer = std::unique_ptr<uint8_t, FxFreeDeleter>(
57           FX_TryAlloc(uint8_t, bufferSize));
58       if (!m_pBuffer)
59         return false;
60     } else {
61       m_pBuffer = std::unique_ptr<uint8_t, FxFreeDeleter>(
62           FX_Alloc(uint8_t, bufferSize));
63     }
64   }
65   m_Width = width;
66   m_Height = height;
67   m_Pitch = pitch;
68   if (!HasAlpha() || format == FXDIB_Argb)
69     return true;
70 
71   if (BuildAlphaMask())
72     return true;
73 
74   if (pBuffer)
75     return true;
76 
77   m_pBuffer = nullptr;
78   m_Width = 0;
79   m_Height = 0;
80   m_Pitch = 0;
81   return false;
82 }
83 
Copy(const RetainPtr<CFX_DIBSource> & pSrc)84 bool CFX_DIBitmap::Copy(const RetainPtr<CFX_DIBSource>& pSrc) {
85   if (m_pBuffer)
86     return false;
87 
88   if (!Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat()))
89     return false;
90 
91   SetPalette(pSrc->GetPalette());
92   SetAlphaMask(pSrc->m_pAlphaMask, nullptr);
93   for (int row = 0; row < pSrc->GetHeight(); row++)
94     memcpy(m_pBuffer.Get() + row * m_Pitch, pSrc->GetScanline(row), m_Pitch);
95   return true;
96 }
97 
~CFX_DIBitmap()98 CFX_DIBitmap::~CFX_DIBitmap() {}
99 
GetBuffer() const100 uint8_t* CFX_DIBitmap::GetBuffer() const {
101   return m_pBuffer.Get();
102 }
103 
GetScanline(int line) const104 const uint8_t* CFX_DIBitmap::GetScanline(int line) const {
105   return m_pBuffer.Get() ? m_pBuffer.Get() + line * m_Pitch : nullptr;
106 }
107 
TakeOver(RetainPtr<CFX_DIBitmap> && pSrcBitmap)108 void CFX_DIBitmap::TakeOver(RetainPtr<CFX_DIBitmap>&& pSrcBitmap) {
109   m_pBuffer = std::move(pSrcBitmap->m_pBuffer);
110   m_pPalette = std::move(pSrcBitmap->m_pPalette);
111   m_pAlphaMask = pSrcBitmap->m_pAlphaMask;
112   pSrcBitmap->m_pBuffer = nullptr;
113   pSrcBitmap->m_pAlphaMask = nullptr;
114   m_bpp = pSrcBitmap->m_bpp;
115   m_AlphaFlag = pSrcBitmap->m_AlphaFlag;
116   m_Width = pSrcBitmap->m_Width;
117   m_Height = pSrcBitmap->m_Height;
118   m_Pitch = pSrcBitmap->m_Pitch;
119 }
120 
Clear(uint32_t color)121 void CFX_DIBitmap::Clear(uint32_t color) {
122   if (!m_pBuffer)
123     return;
124 
125   uint8_t* pBuffer = m_pBuffer.Get();
126   switch (GetFormat()) {
127     case FXDIB_1bppMask:
128       memset(pBuffer, (color & 0xff000000) ? 0xff : 0, m_Pitch * m_Height);
129       break;
130     case FXDIB_1bppRgb: {
131       int index = FindPalette(color);
132       memset(pBuffer, index ? 0xff : 0, m_Pitch * m_Height);
133       break;
134     }
135     case FXDIB_8bppMask:
136       memset(pBuffer, color >> 24, m_Pitch * m_Height);
137       break;
138     case FXDIB_8bppRgb: {
139       int index = FindPalette(color);
140       memset(pBuffer, index, m_Pitch * m_Height);
141       break;
142     }
143     case FXDIB_Rgb:
144     case FXDIB_Rgba: {
145       int a;
146       int r;
147       int g;
148       int b;
149       std::tie(a, r, g, b) = ArgbDecode(color);
150       if (r == g && g == b) {
151         memset(pBuffer, r, m_Pitch * m_Height);
152       } else {
153         int byte_pos = 0;
154         for (int col = 0; col < m_Width; col++) {
155           pBuffer[byte_pos++] = b;
156           pBuffer[byte_pos++] = g;
157           pBuffer[byte_pos++] = r;
158         }
159         for (int row = 1; row < m_Height; row++) {
160           memcpy(pBuffer + row * m_Pitch, pBuffer, m_Pitch);
161         }
162       }
163       break;
164     }
165     case FXDIB_Rgb32:
166     case FXDIB_Argb: {
167       color = IsCmykImage() ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
168 #ifdef _SKIA_SUPPORT_
169       if (FXDIB_Rgb32 == GetFormat() && !IsCmykImage())
170         color |= 0xFF000000;
171 #endif
172       for (int i = 0; i < m_Width; i++)
173         reinterpret_cast<uint32_t*>(pBuffer)[i] = color;
174       for (int row = 1; row < m_Height; row++)
175         memcpy(pBuffer + row * m_Pitch, pBuffer, m_Pitch);
176       break;
177     }
178     default:
179       break;
180   }
181 }
182 
TransferBitmap(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBSource> & pSrcBitmap,int src_left,int src_top)183 bool CFX_DIBitmap::TransferBitmap(int dest_left,
184                                   int dest_top,
185                                   int width,
186                                   int height,
187                                   const RetainPtr<CFX_DIBSource>& pSrcBitmap,
188                                   int src_left,
189                                   int src_top) {
190   if (!m_pBuffer)
191     return false;
192 
193   GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(),
194                  pSrcBitmap->GetHeight(), src_left, src_top, nullptr);
195   if (width == 0 || height == 0)
196     return true;
197 
198   FXDIB_Format dest_format = GetFormat();
199   FXDIB_Format src_format = pSrcBitmap->GetFormat();
200   if (dest_format == src_format) {
201     if (GetBPP() == 1) {
202       for (int row = 0; row < height; row++) {
203         uint8_t* dest_scan = m_pBuffer.Get() + (dest_top + row) * m_Pitch;
204         const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
205         for (int col = 0; col < width; col++) {
206           if (src_scan[(src_left + col) / 8] &
207               (1 << (7 - (src_left + col) % 8))) {
208             dest_scan[(dest_left + col) / 8] |= 1
209                                                 << (7 - (dest_left + col) % 8);
210           } else {
211             dest_scan[(dest_left + col) / 8] &=
212                 ~(1 << (7 - (dest_left + col) % 8));
213           }
214         }
215       }
216     } else {
217       int Bpp = GetBPP() / 8;
218       for (int row = 0; row < height; row++) {
219         uint8_t* dest_scan =
220             m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * Bpp;
221         const uint8_t* src_scan =
222             pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
223         memcpy(dest_scan, src_scan, width * Bpp);
224       }
225     }
226   } else {
227     if (m_pPalette)
228       return false;
229 
230     if (m_bpp == 8)
231       dest_format = FXDIB_8bppMask;
232 
233     uint8_t* dest_buf =
234         m_pBuffer.Get() + dest_top * m_Pitch + dest_left * GetBPP() / 8;
235     std::unique_ptr<uint32_t, FxFreeDeleter> d_plt;
236     if (!ConvertBuffer(dest_format, dest_buf, m_Pitch, width, height,
237                        pSrcBitmap, src_left, src_top, &d_plt)) {
238       return false;
239     }
240   }
241   return true;
242 }
243 
LoadChannel(FXDIB_Channel destChannel,const RetainPtr<CFX_DIBSource> & pSrcBitmap,FXDIB_Channel srcChannel)244 bool CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel,
245                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
246                                FXDIB_Channel srcChannel) {
247   if (!m_pBuffer)
248     return false;
249 
250   RetainPtr<CFX_DIBSource> pSrcClone = pSrcBitmap;
251   int srcOffset;
252   if (srcChannel == FXDIB_Alpha) {
253     if (!pSrcBitmap->HasAlpha() && !pSrcBitmap->IsAlphaMask())
254       return false;
255 
256     if (pSrcBitmap->GetBPP() == 1) {
257       pSrcClone = pSrcBitmap->CloneConvert(FXDIB_8bppMask);
258       if (!pSrcClone)
259         return false;
260     }
261     srcOffset = pSrcBitmap->GetFormat() == FXDIB_Argb ? 3 : 0;
262   } else {
263     if (pSrcBitmap->IsAlphaMask())
264       return false;
265 
266     if (pSrcBitmap->GetBPP() < 24) {
267       if (pSrcBitmap->IsCmykImage()) {
268         pSrcClone = pSrcBitmap->CloneConvert(static_cast<FXDIB_Format>(
269             (pSrcBitmap->GetFormat() & 0xff00) | 0x20));
270       } else {
271         pSrcClone = pSrcBitmap->CloneConvert(static_cast<FXDIB_Format>(
272             (pSrcBitmap->GetFormat() & 0xff00) | 0x18));
273       }
274       if (!pSrcClone)
275         return false;
276     }
277     srcOffset = g_ChannelOffset[srcChannel];
278   }
279   int destOffset = 0;
280   if (destChannel == FXDIB_Alpha) {
281     if (IsAlphaMask()) {
282       if (!ConvertFormat(FXDIB_8bppMask))
283         return false;
284     } else {
285       if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb))
286         return false;
287 
288       if (GetFormat() == FXDIB_Argb)
289         destOffset = 3;
290     }
291   } else {
292     if (IsAlphaMask())
293       return false;
294 
295     if (GetBPP() < 24) {
296       if (HasAlpha()) {
297         if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb))
298           return false;
299 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
300       } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) {
301 #else
302       } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) {
303 #endif
304         return false;
305       }
306     }
307     destOffset = g_ChannelOffset[destChannel];
308   }
309   if (srcChannel == FXDIB_Alpha && pSrcClone->m_pAlphaMask) {
310     RetainPtr<CFX_DIBSource> pAlphaMask = pSrcClone->m_pAlphaMask;
311     if (pSrcClone->GetWidth() != m_Width ||
312         pSrcClone->GetHeight() != m_Height) {
313       if (pAlphaMask) {
314         pAlphaMask = pAlphaMask->StretchTo(m_Width, m_Height, 0, nullptr);
315         if (!pAlphaMask)
316           return false;
317       }
318     }
319     pSrcClone = std::move(pAlphaMask);
320     srcOffset = 0;
321   } else if (pSrcClone->GetWidth() != m_Width ||
322              pSrcClone->GetHeight() != m_Height) {
323     RetainPtr<CFX_DIBitmap> pSrcMatched =
324         pSrcClone->StretchTo(m_Width, m_Height, 0, nullptr);
325     if (!pSrcMatched)
326       return false;
327 
328     pSrcClone = std::move(pSrcMatched);
329   }
330   RetainPtr<CFX_DIBitmap> pDst(this);
331   if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
332     pDst = m_pAlphaMask;
333     destOffset = 0;
334   }
335   int srcBytes = pSrcClone->GetBPP() / 8;
336   int destBytes = pDst->GetBPP() / 8;
337   for (int row = 0; row < m_Height; row++) {
338     uint8_t* dest_pos = (uint8_t*)pDst->GetScanline(row) + destOffset;
339     const uint8_t* src_pos = pSrcClone->GetScanline(row) + srcOffset;
340     for (int col = 0; col < m_Width; col++) {
341       *dest_pos = *src_pos;
342       dest_pos += destBytes;
343       src_pos += srcBytes;
344     }
345   }
346   return true;
347 }
348 
LoadChannel(FXDIB_Channel destChannel,int value)349 bool CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel, int value) {
350   if (!m_pBuffer)
351     return false;
352 
353   int destOffset;
354   if (destChannel == FXDIB_Alpha) {
355     if (IsAlphaMask()) {
356       if (!ConvertFormat(FXDIB_8bppMask)) {
357         return false;
358       }
359       destOffset = 0;
360     } else {
361       destOffset = 0;
362       if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
363         return false;
364       }
365       if (GetFormat() == FXDIB_Argb) {
366         destOffset = 3;
367       }
368     }
369   } else {
370     if (IsAlphaMask()) {
371       return false;
372     }
373     if (GetBPP() < 24) {
374       if (HasAlpha()) {
375         if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
376           return false;
377         }
378 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
379       } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) {
380 #else
381       } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) {
382 #endif
383         return false;
384       }
385     }
386     destOffset = g_ChannelOffset[destChannel];
387   }
388   int Bpp = GetBPP() / 8;
389   if (Bpp == 1) {
390     memset(m_pBuffer.Get(), value, m_Height * m_Pitch);
391     return true;
392   }
393   if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
394     memset(m_pAlphaMask->GetBuffer(), value,
395            m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch());
396     return true;
397   }
398   for (int row = 0; row < m_Height; row++) {
399     uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + destOffset;
400     for (int col = 0; col < m_Width; col++) {
401       *scan_line = value;
402       scan_line += Bpp;
403     }
404   }
405   return true;
406 }
407 
MultiplyAlpha(const RetainPtr<CFX_DIBSource> & pSrcBitmap)408 bool CFX_DIBitmap::MultiplyAlpha(const RetainPtr<CFX_DIBSource>& pSrcBitmap) {
409   if (!m_pBuffer)
410     return false;
411 
412   ASSERT(pSrcBitmap->IsAlphaMask());
413   if (!pSrcBitmap->IsAlphaMask())
414     return false;
415 
416   if (!IsAlphaMask() && !HasAlpha())
417     return LoadChannel(FXDIB_Alpha, pSrcBitmap, FXDIB_Alpha);
418 
419   RetainPtr<CFX_DIBitmap> pSrcClone = pSrcBitmap.As<CFX_DIBitmap>();
420   if (pSrcBitmap->GetWidth() != m_Width ||
421       pSrcBitmap->GetHeight() != m_Height) {
422     pSrcClone = pSrcBitmap->StretchTo(m_Width, m_Height, 0, nullptr);
423     if (!pSrcClone)
424       return false;
425   }
426   if (IsAlphaMask()) {
427     if (!ConvertFormat(FXDIB_8bppMask))
428       return false;
429 
430     for (int row = 0; row < m_Height; row++) {
431       uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row;
432       uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
433       if (pSrcClone->GetBPP() == 1) {
434         for (int col = 0; col < m_Width; col++) {
435           if (!((1 << (7 - col % 8)) & src_scan[col / 8]))
436             dest_scan[col] = 0;
437         }
438       } else {
439         for (int col = 0; col < m_Width; col++) {
440           *dest_scan = (*dest_scan) * src_scan[col] / 255;
441           dest_scan++;
442         }
443       }
444     }
445   } else {
446     if (GetFormat() == FXDIB_Argb) {
447       if (pSrcClone->GetBPP() == 1)
448         return false;
449 
450       for (int row = 0; row < m_Height; row++) {
451         uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row + 3;
452         uint8_t* src_scan =
453             pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
454         for (int col = 0; col < m_Width; col++) {
455           *dest_scan = (*dest_scan) * src_scan[col] / 255;
456           dest_scan += 4;
457         }
458       }
459     } else {
460       m_pAlphaMask->MultiplyAlpha(pSrcClone);
461     }
462   }
463   return true;
464 }
465 
MultiplyAlpha(int alpha)466 bool CFX_DIBitmap::MultiplyAlpha(int alpha) {
467   if (!m_pBuffer)
468     return false;
469 
470   switch (GetFormat()) {
471     case FXDIB_1bppMask:
472       if (!ConvertFormat(FXDIB_8bppMask)) {
473         return false;
474       }
475       MultiplyAlpha(alpha);
476       break;
477     case FXDIB_8bppMask: {
478       for (int row = 0; row < m_Height; row++) {
479         uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch;
480         for (int col = 0; col < m_Width; col++) {
481           scan_line[col] = scan_line[col] * alpha / 255;
482         }
483       }
484       break;
485     }
486     case FXDIB_Argb: {
487       for (int row = 0; row < m_Height; row++) {
488         uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + 3;
489         for (int col = 0; col < m_Width; col++) {
490           *scan_line = (*scan_line) * alpha / 255;
491           scan_line += 4;
492         }
493       }
494       break;
495     }
496     default:
497       if (HasAlpha()) {
498         m_pAlphaMask->MultiplyAlpha(alpha);
499       } else if (IsCmykImage()) {
500         if (!ConvertFormat((FXDIB_Format)(GetFormat() | 0x0200))) {
501           return false;
502         }
503         m_pAlphaMask->MultiplyAlpha(alpha);
504       } else {
505         if (!ConvertFormat(FXDIB_Argb)) {
506           return false;
507         }
508         MultiplyAlpha(alpha);
509       }
510       break;
511   }
512   return true;
513 }
514 
GetPixel(int x,int y) const515 uint32_t CFX_DIBitmap::GetPixel(int x, int y) const {
516   if (!m_pBuffer)
517     return 0;
518 
519   uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + x * GetBPP() / 8;
520   switch (GetFormat()) {
521     case FXDIB_1bppMask: {
522       if ((*pos) & (1 << (7 - x % 8))) {
523         return 0xff000000;
524       }
525       return 0;
526     }
527     case FXDIB_1bppRgb: {
528       if ((*pos) & (1 << (7 - x % 8))) {
529         return m_pPalette ? m_pPalette.get()[1] : 0xffffffff;
530       }
531       return m_pPalette ? m_pPalette.get()[0] : 0xff000000;
532     }
533     case FXDIB_8bppMask:
534       return (*pos) << 24;
535     case FXDIB_8bppRgb:
536       return m_pPalette ? m_pPalette.get()[*pos]
537                         : (0xff000000 | ((*pos) * 0x10101));
538     case FXDIB_Rgb:
539     case FXDIB_Rgba:
540     case FXDIB_Rgb32:
541       return FXARGB_GETDIB(pos) | 0xff000000;
542     case FXDIB_Argb:
543       return FXARGB_GETDIB(pos);
544     default:
545       break;
546   }
547   return 0;
548 }
549 
SetPixel(int x,int y,uint32_t color)550 void CFX_DIBitmap::SetPixel(int x, int y, uint32_t color) {
551   if (!m_pBuffer)
552     return;
553 
554   if (x < 0 || x >= m_Width || y < 0 || y >= m_Height)
555     return;
556 
557   uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + x * GetBPP() / 8;
558   switch (GetFormat()) {
559     case FXDIB_1bppMask:
560       if (color >> 24) {
561         *pos |= 1 << (7 - x % 8);
562       } else {
563         *pos &= ~(1 << (7 - x % 8));
564       }
565       break;
566     case FXDIB_1bppRgb:
567       if (m_pPalette) {
568         if (color == m_pPalette.get()[1]) {
569           *pos |= 1 << (7 - x % 8);
570         } else {
571           *pos &= ~(1 << (7 - x % 8));
572         }
573       } else {
574         if (color == 0xffffffff) {
575           *pos |= 1 << (7 - x % 8);
576         } else {
577           *pos &= ~(1 << (7 - x % 8));
578         }
579       }
580       break;
581     case FXDIB_8bppMask:
582       *pos = (uint8_t)(color >> 24);
583       break;
584     case FXDIB_8bppRgb: {
585       if (m_pPalette) {
586         for (int i = 0; i < 256; i++) {
587           if (m_pPalette.get()[i] == color) {
588             *pos = (uint8_t)i;
589             return;
590           }
591         }
592         *pos = 0;
593       } else {
594         *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
595       }
596       break;
597     }
598     case FXDIB_Rgb:
599     case FXDIB_Rgb32: {
600       int alpha = FXARGB_A(color);
601       pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255;
602       pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255;
603       pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255;
604       break;
605     }
606     case FXDIB_Rgba: {
607       pos[0] = FXARGB_B(color);
608       pos[1] = FXARGB_G(color);
609       pos[2] = FXARGB_R(color);
610       break;
611     }
612     case FXDIB_Argb:
613       FXARGB_SETDIB(pos, color);
614       break;
615     default:
616       break;
617   }
618 }
619 
DownSampleScanline(int line,uint8_t * dest_scan,int dest_bpp,int dest_width,bool bFlipX,int clip_left,int clip_width) const620 void CFX_DIBitmap::DownSampleScanline(int line,
621                                       uint8_t* dest_scan,
622                                       int dest_bpp,
623                                       int dest_width,
624                                       bool bFlipX,
625                                       int clip_left,
626                                       int clip_width) const {
627   if (!m_pBuffer)
628     return;
629 
630   int src_Bpp = m_bpp / 8;
631   uint8_t* scanline = m_pBuffer.Get() + line * m_Pitch;
632   if (src_Bpp == 0) {
633     for (int i = 0; i < clip_width; i++) {
634       uint32_t dest_x = clip_left + i;
635       uint32_t src_x = dest_x * m_Width / dest_width;
636       if (bFlipX) {
637         src_x = m_Width - src_x - 1;
638       }
639       src_x %= m_Width;
640       dest_scan[i] = (scanline[src_x / 8] & (1 << (7 - src_x % 8))) ? 255 : 0;
641     }
642   } else if (src_Bpp == 1) {
643     for (int i = 0; i < clip_width; i++) {
644       uint32_t dest_x = clip_left + i;
645       uint32_t src_x = dest_x * m_Width / dest_width;
646       if (bFlipX) {
647         src_x = m_Width - src_x - 1;
648       }
649       src_x %= m_Width;
650       int dest_pos = i;
651       if (m_pPalette) {
652         if (!IsCmykImage()) {
653           dest_pos *= 3;
654           FX_ARGB argb = m_pPalette.get()[scanline[src_x]];
655           dest_scan[dest_pos] = FXARGB_B(argb);
656           dest_scan[dest_pos + 1] = FXARGB_G(argb);
657           dest_scan[dest_pos + 2] = FXARGB_R(argb);
658         } else {
659           dest_pos *= 4;
660           FX_CMYK cmyk = m_pPalette.get()[scanline[src_x]];
661           dest_scan[dest_pos] = FXSYS_GetCValue(cmyk);
662           dest_scan[dest_pos + 1] = FXSYS_GetMValue(cmyk);
663           dest_scan[dest_pos + 2] = FXSYS_GetYValue(cmyk);
664           dest_scan[dest_pos + 3] = FXSYS_GetKValue(cmyk);
665         }
666       } else {
667         dest_scan[dest_pos] = scanline[src_x];
668       }
669     }
670   } else {
671     for (int i = 0; i < clip_width; i++) {
672       uint32_t dest_x = clip_left + i;
673       uint32_t src_x =
674           bFlipX ? (m_Width - dest_x * m_Width / dest_width - 1) * src_Bpp
675                  : (dest_x * m_Width / dest_width) * src_Bpp;
676       src_x %= m_Width * src_Bpp;
677       int dest_pos = i * src_Bpp;
678       for (int b = 0; b < src_Bpp; b++) {
679         dest_scan[dest_pos + b] = scanline[src_x + b];
680       }
681     }
682   }
683 }
684 
ConvertRGBColorScale(uint32_t forecolor,uint32_t backcolor)685 void CFX_DIBitmap::ConvertRGBColorScale(uint32_t forecolor,
686                                         uint32_t backcolor) {
687   int fr = FXSYS_GetRValue(forecolor);
688   int fg = FXSYS_GetGValue(forecolor);
689   int fb = FXSYS_GetBValue(forecolor);
690   int br = FXSYS_GetRValue(backcolor);
691   int bg = FXSYS_GetGValue(backcolor);
692   int bb = FXSYS_GetBValue(backcolor);
693   if (m_bpp <= 8) {
694     if (forecolor == 0 && backcolor == 0xffffff && !m_pPalette)
695       return;
696     if (!m_pPalette)
697       BuildPalette();
698     int size = 1 << m_bpp;
699     for (int i = 0; i < size; ++i) {
700       int gray = FXRGB2GRAY(FXARGB_R(m_pPalette.get()[i]),
701                             FXARGB_G(m_pPalette.get()[i]),
702                             FXARGB_B(m_pPalette.get()[i]));
703       m_pPalette.get()[i] =
704           FXARGB_MAKE(0xff, br + (fr - br) * gray / 255,
705                       bg + (fg - bg) * gray / 255, bb + (fb - bb) * gray / 255);
706     }
707     return;
708   }
709   if (forecolor == 0 && backcolor == 0xffffff) {
710     for (int row = 0; row < m_Height; ++row) {
711       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
712       int gap = m_bpp / 8 - 2;
713       for (int col = 0; col < m_Width; ++col) {
714         int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
715         *scanline++ = gray;
716         *scanline++ = gray;
717         *scanline = gray;
718         scanline += gap;
719       }
720     }
721     return;
722   }
723   for (int row = 0; row < m_Height; ++row) {
724     uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
725     int gap = m_bpp / 8 - 2;
726     for (int col = 0; col < m_Width; ++col) {
727       int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
728       *scanline++ = bb + (fb - bb) * gray / 255;
729       *scanline++ = bg + (fg - bg) * gray / 255;
730       *scanline = br + (fr - br) * gray / 255;
731       scanline += gap;
732     }
733   }
734 }
735 
ConvertCMYKColorScale(uint32_t forecolor,uint32_t backcolor)736 void CFX_DIBitmap::ConvertCMYKColorScale(uint32_t forecolor,
737                                          uint32_t backcolor) {
738   int fc = FXSYS_GetCValue(forecolor);
739   int fm = FXSYS_GetMValue(forecolor);
740   int fy = FXSYS_GetYValue(forecolor);
741   int fk = FXSYS_GetKValue(forecolor);
742   int bc = FXSYS_GetCValue(backcolor);
743   int bm = FXSYS_GetMValue(backcolor);
744   int by = FXSYS_GetYValue(backcolor);
745   int bk = FXSYS_GetKValue(backcolor);
746   if (m_bpp <= 8) {
747     if (forecolor == 0xff && backcolor == 0 && !m_pPalette)
748       return;
749     if (!m_pPalette)
750       BuildPalette();
751     int size = 1 << m_bpp;
752     for (int i = 0; i < size; ++i) {
753       uint8_t r;
754       uint8_t g;
755       uint8_t b;
756       std::tie(r, g, b) =
757           AdobeCMYK_to_sRGB1(FXSYS_GetCValue(m_pPalette.get()[i]),
758                              FXSYS_GetMValue(m_pPalette.get()[i]),
759                              FXSYS_GetYValue(m_pPalette.get()[i]),
760                              FXSYS_GetKValue(m_pPalette.get()[i]));
761       int gray = 255 - FXRGB2GRAY(r, g, b);
762       m_pPalette.get()[i] =
763           CmykEncode(bc + (fc - bc) * gray / 255, bm + (fm - bm) * gray / 255,
764                      by + (fy - by) * gray / 255, bk + (fk - bk) * gray / 255);
765     }
766     return;
767   }
768   if (forecolor == 0xff && backcolor == 0x00) {
769     for (int row = 0; row < m_Height; ++row) {
770       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
771       for (int col = 0; col < m_Width; ++col) {
772         uint8_t r;
773         uint8_t g;
774         uint8_t b;
775         std::tie(r, g, b) = AdobeCMYK_to_sRGB1(scanline[0], scanline[1],
776                                                scanline[2], scanline[3]);
777         *scanline++ = 0;
778         *scanline++ = 0;
779         *scanline++ = 0;
780         *scanline++ = 255 - FXRGB2GRAY(r, g, b);
781       }
782     }
783     return;
784   }
785   for (int row = 0; row < m_Height; ++row) {
786     uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
787     for (int col = 0; col < m_Width; ++col) {
788       uint8_t r;
789       uint8_t g;
790       uint8_t b;
791       std::tie(r, g, b) = AdobeCMYK_to_sRGB1(scanline[0], scanline[1],
792                                              scanline[2], scanline[3]);
793       int gray = 255 - FXRGB2GRAY(r, g, b);
794       *scanline++ = bc + (fc - bc) * gray / 255;
795       *scanline++ = bm + (fm - bm) * gray / 255;
796       *scanline++ = by + (fy - by) * gray / 255;
797       *scanline++ = bk + (fk - bk) * gray / 255;
798     }
799   }
800 }
801 
ConvertColorScale(uint32_t forecolor,uint32_t backcolor)802 bool CFX_DIBitmap::ConvertColorScale(uint32_t forecolor, uint32_t backcolor) {
803   ASSERT(!IsAlphaMask());
804   if (!m_pBuffer || IsAlphaMask())
805     return false;
806 
807   if (IsCmykImage())
808     ConvertCMYKColorScale(forecolor, backcolor);
809   else
810     ConvertRGBColorScale(forecolor, backcolor);
811   return true;
812 }
813 
CalculatePitchAndSize(int height,int width,FXDIB_Format format,uint32_t * pitch,uint32_t * size)814 bool CFX_DIBitmap::CalculatePitchAndSize(int height,
815                                          int width,
816                                          FXDIB_Format format,
817                                          uint32_t* pitch,
818                                          uint32_t* size) {
819   if (width <= 0 || height <= 0)
820     return false;
821 
822   if ((INT_MAX - 31) / width < (format & 0xFF))
823     return false;
824 
825   if (!*pitch)
826     *pitch = static_cast<uint32_t>((width * (format & 0xff) + 31) / 32 * 4);
827 
828   if ((1 << 30) / *pitch < static_cast<uint32_t>(height))
829     return false;
830 
831   *size = *pitch * static_cast<uint32_t>(height);
832   return true;
833 }
834 
CompositeBitmap(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBSource> & pSrcBitmap,int src_left,int src_top,int blend_type,const CFX_ClipRgn * pClipRgn,bool bRgbByteOrder)835 bool CFX_DIBitmap::CompositeBitmap(int dest_left,
836                                    int dest_top,
837                                    int width,
838                                    int height,
839                                    const RetainPtr<CFX_DIBSource>& pSrcBitmap,
840                                    int src_left,
841                                    int src_top,
842                                    int blend_type,
843                                    const CFX_ClipRgn* pClipRgn,
844                                    bool bRgbByteOrder) {
845   if (!m_pBuffer)
846     return false;
847 
848   ASSERT(!pSrcBitmap->IsAlphaMask());
849   ASSERT(m_bpp >= 8);
850   if (pSrcBitmap->IsAlphaMask() || m_bpp < 8) {
851     return false;
852   }
853   GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(),
854                  pSrcBitmap->GetHeight(), src_left, src_top, pClipRgn);
855   if (width == 0 || height == 0) {
856     return true;
857   }
858   RetainPtr<CFX_DIBitmap> pClipMask;
859   FX_RECT clip_box;
860   if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
861     ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF);
862     pClipMask = pClipRgn->GetMask();
863     clip_box = pClipRgn->GetBox();
864   }
865   CFX_ScanlineCompositor compositor;
866   if (!compositor.Init(GetFormat(), pSrcBitmap->GetFormat(), width,
867                        pSrcBitmap->GetPalette(), 0, blend_type,
868                        pClipMask != nullptr, bRgbByteOrder, 0)) {
869     return false;
870   }
871   int dest_Bpp = m_bpp / 8;
872   int src_Bpp = pSrcBitmap->GetBPP() / 8;
873   bool bRgb = src_Bpp > 1 && !pSrcBitmap->IsCmykImage();
874   RetainPtr<CFX_DIBitmap> pSrcAlphaMask = pSrcBitmap->m_pAlphaMask;
875   for (int row = 0; row < height; row++) {
876     uint8_t* dest_scan =
877         m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * dest_Bpp;
878     const uint8_t* src_scan =
879         pSrcBitmap->GetScanline(src_top + row) + src_left * src_Bpp;
880     const uint8_t* src_scan_extra_alpha =
881         pSrcAlphaMask ? pSrcAlphaMask->GetScanline(src_top + row) + src_left
882                       : nullptr;
883     uint8_t* dst_scan_extra_alpha =
884         m_pAlphaMask
885             ? (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left
886             : nullptr;
887     const uint8_t* clip_scan = nullptr;
888     if (pClipMask) {
889       clip_scan = pClipMask->m_pBuffer.Get() +
890                   (dest_top + row - clip_box.top) * pClipMask->m_Pitch +
891                   (dest_left - clip_box.left);
892     }
893     if (bRgb) {
894       compositor.CompositeRgbBitmapLine(dest_scan, src_scan, width, clip_scan,
895                                         src_scan_extra_alpha,
896                                         dst_scan_extra_alpha);
897     } else {
898       compositor.CompositePalBitmapLine(dest_scan, src_scan, src_left, width,
899                                         clip_scan, src_scan_extra_alpha,
900                                         dst_scan_extra_alpha);
901     }
902   }
903   return true;
904 }
905 
CompositeMask(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBSource> & pMask,uint32_t color,int src_left,int src_top,int blend_type,const CFX_ClipRgn * pClipRgn,bool bRgbByteOrder,int alpha_flag)906 bool CFX_DIBitmap::CompositeMask(int dest_left,
907                                  int dest_top,
908                                  int width,
909                                  int height,
910                                  const RetainPtr<CFX_DIBSource>& pMask,
911                                  uint32_t color,
912                                  int src_left,
913                                  int src_top,
914                                  int blend_type,
915                                  const CFX_ClipRgn* pClipRgn,
916                                  bool bRgbByteOrder,
917                                  int alpha_flag) {
918   if (!m_pBuffer)
919     return false;
920 
921   ASSERT(pMask->IsAlphaMask());
922   ASSERT(m_bpp >= 8);
923   if (!pMask->IsAlphaMask() || m_bpp < 8)
924     return false;
925 
926   GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(),
927                  pMask->GetHeight(), src_left, src_top, pClipRgn);
928   if (width == 0 || height == 0)
929     return true;
930 
931   int src_alpha =
932       (uint8_t)(alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color);
933   if (src_alpha == 0)
934     return true;
935 
936   RetainPtr<CFX_DIBitmap> pClipMask;
937   FX_RECT clip_box;
938   if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
939     ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF);
940     pClipMask = pClipRgn->GetMask();
941     clip_box = pClipRgn->GetBox();
942   }
943   int src_bpp = pMask->GetBPP();
944   int Bpp = GetBPP() / 8;
945   CFX_ScanlineCompositor compositor;
946   if (!compositor.Init(GetFormat(), pMask->GetFormat(), width, nullptr, color,
947                        blend_type, pClipMask != nullptr, bRgbByteOrder,
948                        alpha_flag)) {
949     return false;
950   }
951   for (int row = 0; row < height; row++) {
952     uint8_t* dest_scan =
953         m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * Bpp;
954     const uint8_t* src_scan = pMask->GetScanline(src_top + row);
955     uint8_t* dst_scan_extra_alpha =
956         m_pAlphaMask
957             ? (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left
958             : nullptr;
959     const uint8_t* clip_scan = nullptr;
960     if (pClipMask) {
961       clip_scan = pClipMask->m_pBuffer.Get() +
962                   (dest_top + row - clip_box.top) * pClipMask->m_Pitch +
963                   (dest_left - clip_box.left);
964     }
965     if (src_bpp == 1) {
966       compositor.CompositeBitMaskLine(dest_scan, src_scan, src_left, width,
967                                       clip_scan, dst_scan_extra_alpha);
968     } else {
969       compositor.CompositeByteMaskLine(dest_scan, src_scan + src_left, width,
970                                        clip_scan, dst_scan_extra_alpha);
971     }
972   }
973   return true;
974 }
975 
CompositeRect(int left,int top,int width,int height,uint32_t color,int alpha_flag)976 bool CFX_DIBitmap::CompositeRect(int left,
977                                  int top,
978                                  int width,
979                                  int height,
980                                  uint32_t color,
981                                  int alpha_flag) {
982   if (!m_pBuffer)
983     return false;
984 
985   int src_alpha = (alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color);
986   if (src_alpha == 0)
987     return true;
988 
989   FX_RECT rect(left, top, left + width, top + height);
990   rect.Intersect(0, 0, m_Width, m_Height);
991   if (rect.IsEmpty())
992     return true;
993 
994   width = rect.Width();
995   uint32_t dst_color;
996   if (alpha_flag >> 8)
997     dst_color = FXCMYK_TODIB(color);
998   else
999     dst_color = FXARGB_TODIB(color);
1000   uint8_t* color_p = (uint8_t*)&dst_color;
1001   if (m_bpp == 8) {
1002     uint8_t gray = 255;
1003     if (!IsAlphaMask()) {
1004       if (alpha_flag >> 8) {
1005         uint8_t r;
1006         uint8_t g;
1007         uint8_t b;
1008         std::tie(r, g, b) =
1009             AdobeCMYK_to_sRGB1(color_p[0], color_p[1], color_p[2], color_p[3]);
1010         gray = FXRGB2GRAY(r, g, b);
1011       } else {
1012         gray = (uint8_t)FXRGB2GRAY((int)color_p[2], color_p[1], color_p[0]);
1013       }
1014       if (IsCmykImage()) {
1015         gray = ~gray;
1016       }
1017     }
1018     for (int row = rect.top; row < rect.bottom; row++) {
1019       uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left;
1020       if (src_alpha == 255) {
1021         memset(dest_scan, gray, width);
1022       } else {
1023         for (int col = 0; col < width; col++) {
1024           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
1025           dest_scan++;
1026         }
1027       }
1028     }
1029     return true;
1030   }
1031   if (m_bpp == 1) {
1032     ASSERT(!IsCmykImage() && static_cast<uint8_t>(alpha_flag >> 8) == 0);
1033     int left_shift = rect.left % 8;
1034     int right_shift = rect.right % 8;
1035     int new_width = rect.right / 8 - rect.left / 8;
1036     int index = 0;
1037     if (m_pPalette) {
1038       for (int i = 0; i < 2; i++) {
1039         if (m_pPalette.get()[i] == color)
1040           index = i;
1041       }
1042     } else {
1043       index = (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
1044     }
1045     for (int row = rect.top; row < rect.bottom; row++) {
1046       uint8_t* dest_scan_top =
1047           const_cast<uint8_t*>(GetScanline(row)) + rect.left / 8;
1048       uint8_t* dest_scan_top_r =
1049           const_cast<uint8_t*>(GetScanline(row)) + rect.right / 8;
1050       uint8_t left_flag = *dest_scan_top & (255 << (8 - left_shift));
1051       uint8_t right_flag = *dest_scan_top_r & (255 >> right_shift);
1052       if (new_width) {
1053         memset(dest_scan_top + 1, index ? 255 : 0, new_width - 1);
1054         if (!index) {
1055           *dest_scan_top &= left_flag;
1056           *dest_scan_top_r &= right_flag;
1057         } else {
1058           *dest_scan_top |= ~left_flag;
1059           *dest_scan_top_r |= ~right_flag;
1060         }
1061       } else {
1062         if (!index) {
1063           *dest_scan_top &= left_flag | right_flag;
1064         } else {
1065           *dest_scan_top |= ~(left_flag | right_flag);
1066         }
1067       }
1068     }
1069     return true;
1070   }
1071   ASSERT(m_bpp >= 24);
1072   if (m_bpp < 24 || (!(alpha_flag >> 8) && IsCmykImage()))
1073     return false;
1074   if (alpha_flag >> 8 && !IsCmykImage()) {
1075     std::tie(color_p[2], color_p[1], color_p[0]) =
1076         AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color),
1077                            FXSYS_GetYValue(color), FXSYS_GetKValue(color));
1078   }
1079   if (!IsCmykImage())
1080     color_p[3] = static_cast<uint8_t>(src_alpha);
1081   int Bpp = m_bpp / 8;
1082   bool bAlpha = HasAlpha();
1083   bool bArgb = GetFormat() == FXDIB_Argb;
1084   if (src_alpha == 255) {
1085     for (int row = rect.top; row < rect.bottom; row++) {
1086       uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
1087       uint8_t* dest_scan_alpha =
1088           m_pAlphaMask ? (uint8_t*)m_pAlphaMask->GetScanline(row) + rect.left
1089                        : nullptr;
1090       if (dest_scan_alpha) {
1091         memset(dest_scan_alpha, 0xff, width);
1092       }
1093       if (Bpp == 4) {
1094         uint32_t* scan = (uint32_t*)dest_scan;
1095         for (int col = 0; col < width; col++) {
1096           *scan++ = dst_color;
1097         }
1098       } else {
1099         for (int col = 0; col < width; col++) {
1100           *dest_scan++ = color_p[0];
1101           *dest_scan++ = color_p[1];
1102           *dest_scan++ = color_p[2];
1103         }
1104       }
1105     }
1106     return true;
1107   }
1108   for (int row = rect.top; row < rect.bottom; row++) {
1109     uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
1110     if (bAlpha) {
1111       if (bArgb) {
1112         for (int col = 0; col < width; col++) {
1113           uint8_t back_alpha = dest_scan[3];
1114           if (back_alpha == 0) {
1115             FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, color_p[2],
1116                                                  color_p[1], color_p[0]));
1117             dest_scan += 4;
1118             continue;
1119           }
1120           uint8_t dest_alpha =
1121               back_alpha + src_alpha - back_alpha * src_alpha / 255;
1122           int alpha_ratio = src_alpha * 255 / dest_alpha;
1123           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[0], alpha_ratio);
1124           dest_scan++;
1125           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[1], alpha_ratio);
1126           dest_scan++;
1127           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[2], alpha_ratio);
1128           dest_scan++;
1129           *dest_scan++ = dest_alpha;
1130         }
1131       } else {
1132         uint8_t* dest_scan_alpha =
1133             (uint8_t*)m_pAlphaMask->GetScanline(row) + rect.left;
1134         for (int col = 0; col < width; col++) {
1135           uint8_t back_alpha = *dest_scan_alpha;
1136           if (back_alpha == 0) {
1137             *dest_scan_alpha++ = src_alpha;
1138             memcpy(dest_scan, color_p, Bpp);
1139             dest_scan += Bpp;
1140             continue;
1141           }
1142           uint8_t dest_alpha =
1143               back_alpha + src_alpha - back_alpha * src_alpha / 255;
1144           *dest_scan_alpha++ = dest_alpha;
1145           int alpha_ratio = src_alpha * 255 / dest_alpha;
1146           for (int comps = 0; comps < Bpp; comps++) {
1147             *dest_scan =
1148                 FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], alpha_ratio);
1149             dest_scan++;
1150           }
1151         }
1152       }
1153     } else {
1154       for (int col = 0; col < width; col++) {
1155         for (int comps = 0; comps < Bpp; comps++) {
1156           if (comps == 3) {
1157             *dest_scan++ = 255;
1158             continue;
1159           }
1160           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], src_alpha);
1161           dest_scan++;
1162         }
1163       }
1164     }
1165   }
1166   return true;
1167 }
1168 
ConvertFormat(FXDIB_Format dest_format)1169 bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
1170   FXDIB_Format src_format = GetFormat();
1171   if (dest_format == src_format)
1172     return true;
1173 
1174   if (dest_format == FXDIB_8bppMask && src_format == FXDIB_8bppRgb &&
1175       !m_pPalette) {
1176     m_AlphaFlag = 1;
1177     return true;
1178   }
1179   if (dest_format == FXDIB_Argb && src_format == FXDIB_Rgb32) {
1180     m_AlphaFlag = 2;
1181     for (int row = 0; row < m_Height; row++) {
1182       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch + 3;
1183       for (int col = 0; col < m_Width; col++) {
1184         *scanline = 0xff;
1185         scanline += 4;
1186       }
1187     }
1188     return true;
1189   }
1190   int dest_bpp = dest_format & 0xff;
1191   int dest_pitch = (dest_bpp * m_Width + 31) / 32 * 4;
1192   std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
1193       FX_TryAlloc(uint8_t, dest_pitch * m_Height + 4));
1194   if (!dest_buf)
1195     return false;
1196 
1197   RetainPtr<CFX_DIBitmap> pAlphaMask;
1198   if (dest_format == FXDIB_Argb) {
1199     memset(dest_buf.get(), 0xff, dest_pitch * m_Height + 4);
1200     if (m_pAlphaMask) {
1201       for (int row = 0; row < m_Height; row++) {
1202         uint8_t* pDstScanline = dest_buf.get() + row * dest_pitch + 3;
1203         const uint8_t* pSrcScanline = m_pAlphaMask->GetScanline(row);
1204         for (int col = 0; col < m_Width; col++) {
1205           *pDstScanline = *pSrcScanline++;
1206           pDstScanline += 4;
1207         }
1208       }
1209     }
1210   } else if (dest_format & 0x0200) {
1211     if (src_format == FXDIB_Argb) {
1212       pAlphaMask = CloneAlphaMask();
1213       if (!pAlphaMask)
1214         return false;
1215     } else {
1216       if (!m_pAlphaMask) {
1217         if (!BuildAlphaMask())
1218           return false;
1219         pAlphaMask = std::move(m_pAlphaMask);
1220       } else {
1221         pAlphaMask = m_pAlphaMask;
1222       }
1223     }
1224   }
1225   bool ret = false;
1226   RetainPtr<CFX_DIBSource> holder(this);
1227   std::unique_ptr<uint32_t, FxFreeDeleter> pal_8bpp;
1228   ret = ConvertBuffer(dest_format, dest_buf.get(), dest_pitch, m_Width,
1229                       m_Height, holder, 0, 0, &pal_8bpp);
1230   if (!ret)
1231     return false;
1232 
1233   m_pAlphaMask = pAlphaMask;
1234   m_pPalette = std::move(pal_8bpp);
1235   m_pBuffer = std::move(dest_buf);
1236   m_bpp = static_cast<uint8_t>(dest_format);
1237   m_AlphaFlag = static_cast<uint8_t>(dest_format >> 8);
1238   m_Pitch = dest_pitch;
1239   return true;
1240 }
1241