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