xref: /aosp_15_r20/external/pdfium/core/fxge/dib/cfx_dibitmap.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fxge/dib/cfx_dibitmap.h"
8 
9 #include <stdint.h>
10 #include <string.h>
11 
12 #include <limits>
13 #include <memory>
14 #include <utility>
15 
16 #include "build/build_config.h"
17 #include "core/fxcrt/data_vector.h"
18 #include "core/fxcrt/fx_coordinates.h"
19 #include "core/fxcrt/fx_safe_types.h"
20 #include "core/fxcrt/span_util.h"
21 #include "core/fxge/calculate_pitch.h"
22 #include "core/fxge/cfx_cliprgn.h"
23 #include "core/fxge/cfx_defaultrenderdevice.h"
24 #include "core/fxge/dib/cfx_scanlinecompositor.h"
25 #include "third_party/base/check.h"
26 #include "third_party/base/check_op.h"
27 #include "third_party/base/notreached.h"
28 #include "third_party/base/numerics/safe_conversions.h"
29 
30 CFX_DIBitmap::CFX_DIBitmap() = default;
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_Format = format;
43   m_Width = 0;
44   m_Height = 0;
45   m_Pitch = 0;
46 
47   absl::optional<PitchAndSize> pitch_size =
48       CalculatePitchAndSize(width, height, format, pitch);
49   if (!pitch_size.has_value())
50     return false;
51 
52   if (pBuffer) {
53     m_pBuffer.Reset(pBuffer);
54   } else {
55     FX_SAFE_SIZE_T safe_buffer_size = pitch_size.value().size;
56     safe_buffer_size += 4;
57     if (!safe_buffer_size.IsValid())
58       return false;
59 
60     m_pBuffer = std::unique_ptr<uint8_t, FxFreeDeleter>(
61         FX_TryAlloc(uint8_t, safe_buffer_size.ValueOrDie()));
62     if (!m_pBuffer)
63       return false;
64   }
65   m_Width = width;
66   m_Height = height;
67   m_Pitch = pitch_size.value().pitch;
68   return true;
69 }
70 
Copy(const RetainPtr<CFX_DIBBase> & pSrc)71 bool CFX_DIBitmap::Copy(const RetainPtr<CFX_DIBBase>& pSrc) {
72   if (m_pBuffer)
73     return false;
74 
75   if (!Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat()))
76     return false;
77 
78   SetPalette(pSrc->GetPaletteSpan());
79   for (int row = 0; row < pSrc->GetHeight(); row++) {
80     memcpy(m_pBuffer.Get() + row * m_Pitch, pSrc->GetScanline(row).data(),
81            m_Pitch);
82   }
83   return true;
84 }
85 
86 CFX_DIBitmap::~CFX_DIBitmap() = default;
87 
GetBuffer() const88 pdfium::span<const uint8_t> CFX_DIBitmap::GetBuffer() const {
89   if (!m_pBuffer)
90     return pdfium::span<const uint8_t>();
91 
92   return {m_pBuffer.Get(), m_Height * m_Pitch};
93 }
94 
GetScanline(int line) const95 pdfium::span<const uint8_t> CFX_DIBitmap::GetScanline(int line) const {
96   auto buffer_span = GetBuffer();
97   if (buffer_span.empty())
98     return pdfium::span<const uint8_t>();
99 
100   return buffer_span.subspan(line * m_Pitch, m_Pitch);
101 }
102 
GetEstimatedImageMemoryBurden() const103 size_t CFX_DIBitmap::GetEstimatedImageMemoryBurden() const {
104   size_t result = CFX_DIBBase::GetEstimatedImageMemoryBurden();
105   if (!GetBuffer().empty()) {
106     int height = GetHeight();
107     CHECK(pdfium::base::IsValueInRangeForNumericType<size_t>(height));
108     result += static_cast<size_t>(height) * GetPitch();
109   }
110   return result;
111 }
112 
TakeOver(RetainPtr<CFX_DIBitmap> && pSrcBitmap)113 void CFX_DIBitmap::TakeOver(RetainPtr<CFX_DIBitmap>&& pSrcBitmap) {
114   m_pBuffer = std::move(pSrcBitmap->m_pBuffer);
115   m_palette = std::move(pSrcBitmap->m_palette);
116   pSrcBitmap->m_pBuffer = nullptr;
117   m_Format = pSrcBitmap->m_Format;
118   m_Width = pSrcBitmap->m_Width;
119   m_Height = pSrcBitmap->m_Height;
120   m_Pitch = pSrcBitmap->m_Pitch;
121 }
122 
Clear(uint32_t color)123 void CFX_DIBitmap::Clear(uint32_t color) {
124   if (!m_pBuffer)
125     return;
126 
127   uint8_t* pBuffer = m_pBuffer.Get();
128   switch (GetFormat()) {
129     case FXDIB_Format::k1bppMask:
130       memset(pBuffer, (color & 0xff000000) ? 0xff : 0, m_Pitch * m_Height);
131       break;
132     case FXDIB_Format::k1bppRgb: {
133       int index = FindPalette(color);
134       memset(pBuffer, index ? 0xff : 0, m_Pitch * m_Height);
135       break;
136     }
137     case FXDIB_Format::k8bppMask:
138       memset(pBuffer, color >> 24, m_Pitch * m_Height);
139       break;
140     case FXDIB_Format::k8bppRgb: {
141       int index = FindPalette(color);
142       memset(pBuffer, index, m_Pitch * m_Height);
143       break;
144     }
145     case FXDIB_Format::kRgb: {
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_Format::kRgb32:
167     case FXDIB_Format::kArgb: {
168       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer() &&
169           FXDIB_Format::kRgb32 == GetFormat()) {
170         // TODO(crbug.com/pdfium/2016): This is not reliable because alpha may
171         // be modified outside of this operation.
172         color |= 0xFF000000;
173       }
174       for (int i = 0; i < m_Width; i++)
175         reinterpret_cast<uint32_t*>(pBuffer)[i] = color;
176       for (int row = 1; row < m_Height; row++)
177         memcpy(pBuffer + row * m_Pitch, pBuffer, m_Pitch);
178       break;
179     }
180     default:
181       break;
182   }
183 }
184 
TransferBitmap(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)185 bool CFX_DIBitmap::TransferBitmap(int dest_left,
186                                   int dest_top,
187                                   int width,
188                                   int height,
189                                   const RetainPtr<CFX_DIBBase>& pSrcBitmap,
190                                   int src_left,
191                                   int src_top) {
192   if (!m_pBuffer)
193     return false;
194 
195   if (!GetOverlapRect(dest_left, dest_top, width, height,
196                       pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left,
197                       src_top, nullptr)) {
198     return true;
199   }
200 
201   FXDIB_Format dest_format = GetFormat();
202   FXDIB_Format src_format = pSrcBitmap->GetFormat();
203   if (dest_format != src_format) {
204     return TransferWithUnequalFormats(dest_format, dest_left, dest_top, width,
205                                       height, pSrcBitmap, src_left, src_top);
206   }
207 
208   if (GetBPP() != 1) {
209     TransferWithMultipleBPP(dest_left, dest_top, width, height, pSrcBitmap,
210                             src_left, src_top);
211     return true;
212   }
213 
214   TransferEqualFormatsOneBPP(dest_left, dest_top, width, height, pSrcBitmap,
215                              src_left, src_top);
216   return true;
217 }
218 
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)219 bool CFX_DIBitmap::TransferWithUnequalFormats(
220     FXDIB_Format dest_format,
221     int dest_left,
222     int dest_top,
223     int width,
224     int height,
225     const RetainPtr<CFX_DIBBase>& pSrcBitmap,
226     int src_left,
227     int src_top) {
228   if (HasPalette())
229     return false;
230 
231   if (GetBppFromFormat(m_Format) == 8)
232     dest_format = FXDIB_Format::k8bppMask;
233 
234   FX_SAFE_UINT32 offset = dest_left;
235   offset *= GetBPP();
236   offset /= 8;
237   if (!offset.IsValid())
238     return false;
239 
240   pdfium::span<uint8_t> dest_buf = GetWritableBuffer().subspan(
241       dest_top * m_Pitch + static_cast<uint32_t>(offset.ValueOrDie()));
242   DataVector<uint32_t> d_plt;
243   return ConvertBuffer(dest_format, dest_buf, m_Pitch, width, height,
244                        pSrcBitmap, src_left, src_top, &d_plt);
245 }
246 
TransferWithMultipleBPP(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)247 void CFX_DIBitmap::TransferWithMultipleBPP(
248     int dest_left,
249     int dest_top,
250     int width,
251     int height,
252     const RetainPtr<CFX_DIBBase>& pSrcBitmap,
253     int src_left,
254     int src_top) {
255   int Bpp = GetBPP() / 8;
256   for (int row = 0; row < height; ++row) {
257     uint8_t* dest_scan =
258         m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * Bpp;
259     const uint8_t* src_scan =
260         pSrcBitmap->GetScanline(src_top + row).subspan(src_left * Bpp).data();
261     memcpy(dest_scan, src_scan, width * Bpp);
262   }
263 }
264 
TransferEqualFormatsOneBPP(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)265 void CFX_DIBitmap::TransferEqualFormatsOneBPP(
266     int dest_left,
267     int dest_top,
268     int width,
269     int height,
270     const RetainPtr<CFX_DIBBase>& pSrcBitmap,
271     int src_left,
272     int src_top) {
273   for (int row = 0; row < height; ++row) {
274     uint8_t* dest_scan = m_pBuffer.Get() + (dest_top + row) * m_Pitch;
275     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
276     for (int col = 0; col < width; ++col) {
277       int src_idx = src_left + col;
278       int dest_idx = dest_left + col;
279       if (src_scan[(src_idx) / 8] & (1 << (7 - (src_idx) % 8)))
280         dest_scan[(dest_idx) / 8] |= 1 << (7 - (dest_idx) % 8);
281       else
282         dest_scan[(dest_idx) / 8] &= ~(1 << (7 - (dest_idx) % 8));
283     }
284   }
285 }
286 
SetChannelFromBitmap(Channel destChannel,const RetainPtr<CFX_DIBBase> & pSrcBitmap)287 bool CFX_DIBitmap::SetChannelFromBitmap(
288     Channel destChannel,
289     const RetainPtr<CFX_DIBBase>& pSrcBitmap) {
290   if (!m_pBuffer)
291     return false;
292 
293   RetainPtr<CFX_DIBBase> pSrcClone = pSrcBitmap;
294   if (!pSrcBitmap->IsAlphaFormat() && !pSrcBitmap->IsMaskFormat())
295     return false;
296 
297   if (pSrcBitmap->GetBPP() == 1) {
298     pSrcClone = pSrcBitmap->ConvertTo(FXDIB_Format::k8bppMask);
299     if (!pSrcClone)
300       return false;
301   }
302   const int srcOffset = pSrcBitmap->GetFormat() == FXDIB_Format::kArgb ? 3 : 0;
303   int destOffset = 0;
304   if (destChannel == Channel::kAlpha) {
305     if (IsMaskFormat()) {
306       if (!ConvertFormat(FXDIB_Format::k8bppMask))
307         return false;
308     } else {
309       if (!ConvertFormat(FXDIB_Format::kArgb))
310         return false;
311 
312       destOffset = 3;
313     }
314   } else {
315     DCHECK_EQ(destChannel, Channel::kRed);
316     if (IsMaskFormat())
317       return false;
318 
319     if (GetBPP() < 24) {
320       if (IsAlphaFormat()) {
321         if (!ConvertFormat(FXDIB_Format::kArgb))
322           return false;
323       } else {
324         if (!ConvertFormat(kPlatformRGBFormat))
325           return false;
326       }
327     }
328     destOffset = 2;
329   }
330   if (pSrcClone->GetWidth() != m_Width || pSrcClone->GetHeight() != m_Height) {
331     RetainPtr<CFX_DIBitmap> pSrcMatched = pSrcClone->StretchTo(
332         m_Width, m_Height, FXDIB_ResampleOptions(), nullptr);
333     if (!pSrcMatched)
334       return false;
335 
336     pSrcClone = pSrcMatched;
337   }
338   RetainPtr<CFX_DIBitmap> pDst(this);
339   int srcBytes = pSrcClone->GetBPP() / 8;
340   int destBytes = pDst->GetBPP() / 8;
341   for (int row = 0; row < m_Height; row++) {
342     uint8_t* dest_pos =
343         pDst->GetWritableScanline(row).subspan(destOffset).data();
344     const uint8_t* src_pos =
345         pSrcClone->GetScanline(row).subspan(srcOffset).data();
346     for (int col = 0; col < m_Width; col++) {
347       *dest_pos = *src_pos;
348       dest_pos += destBytes;
349       src_pos += srcBytes;
350     }
351   }
352   return true;
353 }
354 
SetAlphaFromBitmap(const RetainPtr<CFX_DIBBase> & pSrcBitmap)355 bool CFX_DIBitmap::SetAlphaFromBitmap(
356     const RetainPtr<CFX_DIBBase>& pSrcBitmap) {
357   return SetChannelFromBitmap(Channel::kAlpha, pSrcBitmap);
358 }
359 
SetRedFromBitmap(const RetainPtr<CFX_DIBBase> & pSrcBitmap)360 bool CFX_DIBitmap::SetRedFromBitmap(const RetainPtr<CFX_DIBBase>& pSrcBitmap) {
361   return SetChannelFromBitmap(Channel::kRed, pSrcBitmap);
362 }
363 
SetUniformOpaqueAlpha()364 bool CFX_DIBitmap::SetUniformOpaqueAlpha() {
365   if (!m_pBuffer)
366     return false;
367 
368   if (IsMaskFormat()) {
369     if (!ConvertFormat(FXDIB_Format::k8bppMask))
370       return false;
371   } else {
372     if (!ConvertFormat(FXDIB_Format::kArgb))
373       return false;
374   }
375   const int Bpp = GetBPP() / 8;
376   if (Bpp == 1) {
377     memset(m_pBuffer.Get(), 0xff, m_Height * m_Pitch);
378     return true;
379   }
380   const int destOffset = GetFormat() == FXDIB_Format::kArgb ? 3 : 0;
381   for (int row = 0; row < m_Height; row++) {
382     uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + destOffset;
383     for (int col = 0; col < m_Width; col++) {
384       *scan_line = 0xff;
385       scan_line += Bpp;
386     }
387   }
388   return true;
389 }
390 
MultiplyAlpha(const RetainPtr<CFX_DIBBase> & pSrcBitmap)391 bool CFX_DIBitmap::MultiplyAlpha(const RetainPtr<CFX_DIBBase>& pSrcBitmap) {
392   CHECK(pSrcBitmap->IsMaskFormat());
393 
394   if (!m_pBuffer) {
395     return false;
396   }
397 
398   if (IsOpaqueImage())
399     return SetAlphaFromBitmap(pSrcBitmap);
400 
401   RetainPtr<CFX_DIBitmap> pSrcClone = pSrcBitmap.As<CFX_DIBitmap>();
402   if (pSrcBitmap->GetWidth() != m_Width ||
403       pSrcBitmap->GetHeight() != m_Height) {
404     pSrcClone = pSrcBitmap->StretchTo(m_Width, m_Height,
405                                       FXDIB_ResampleOptions(), nullptr);
406     if (!pSrcClone)
407       return false;
408   }
409   if (IsMaskFormat()) {
410     if (!ConvertFormat(FXDIB_Format::k8bppMask))
411       return false;
412 
413     for (int row = 0; row < m_Height; row++) {
414       uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row;
415       uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
416       if (pSrcClone->GetBPP() == 1) {
417         for (int col = 0; col < m_Width; col++) {
418           if (!((1 << (7 - col % 8)) & src_scan[col / 8]))
419             dest_scan[col] = 0;
420         }
421       } else {
422         for (int col = 0; col < m_Width; col++) {
423           *dest_scan = (*dest_scan) * src_scan[col] / 255;
424           dest_scan++;
425         }
426       }
427     }
428     return true;
429   }
430 
431   DCHECK_EQ(GetFormat(), FXDIB_Format::kArgb);
432   if (pSrcClone->GetBPP() == 1)
433     return false;
434 
435   for (int row = 0; row < m_Height; row++) {
436     uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row + 3;
437     uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
438     for (int col = 0; col < m_Width; col++) {
439       *dest_scan = (*dest_scan) * src_scan[col] / 255;
440       dest_scan += 4;
441     }
442   }
443   return true;
444 }
445 
MultiplyAlpha(int alpha)446 bool CFX_DIBitmap::MultiplyAlpha(int alpha) {
447   if (!m_pBuffer)
448     return false;
449 
450   switch (GetFormat()) {
451     case FXDIB_Format::k1bppMask:
452       if (!ConvertFormat(FXDIB_Format::k8bppMask)) {
453         return false;
454       }
455       MultiplyAlpha(alpha);
456       break;
457     case FXDIB_Format::k8bppMask: {
458       for (int row = 0; row < m_Height; row++) {
459         uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch;
460         for (int col = 0; col < m_Width; col++) {
461           scan_line[col] = scan_line[col] * alpha / 255;
462         }
463       }
464       break;
465     }
466     case FXDIB_Format::kArgb: {
467       for (int row = 0; row < m_Height; row++) {
468         uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + 3;
469         for (int col = 0; col < m_Width; col++) {
470           *scan_line = (*scan_line) * alpha / 255;
471           scan_line += 4;
472         }
473       }
474       break;
475     }
476     default:
477       DCHECK(!IsAlphaFormat());
478       if (!ConvertFormat(FXDIB_Format::kArgb)) {
479         return false;
480       }
481       MultiplyAlpha(alpha);
482       break;
483   }
484   return true;
485 }
486 
487 #if defined(_SKIA_SUPPORT_)
GetPixel(int x,int y) const488 uint32_t CFX_DIBitmap::GetPixel(int x, int y) const {
489   if (!m_pBuffer)
490     return 0;
491 
492   FX_SAFE_UINT32 offset = x;
493   offset *= GetBPP();
494   offset /= 8;
495   if (!offset.IsValid())
496     return 0;
497 
498   uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + offset.ValueOrDie();
499   switch (GetFormat()) {
500     case FXDIB_Format::k1bppMask: {
501       if ((*pos) & (1 << (7 - x % 8))) {
502         return 0xff000000;
503       }
504       return 0;
505     }
506     case FXDIB_Format::k1bppRgb: {
507       if ((*pos) & (1 << (7 - x % 8))) {
508         return HasPalette() ? GetPaletteSpan()[1] : 0xffffffff;
509       }
510       return HasPalette() ? GetPaletteSpan()[0] : 0xff000000;
511     }
512     case FXDIB_Format::k8bppMask:
513       return (*pos) << 24;
514     case FXDIB_Format::k8bppRgb:
515       return HasPalette() ? GetPaletteSpan()[*pos]
516                           : ArgbEncode(0xff, *pos, *pos, *pos);
517     case FXDIB_Format::kRgb:
518     case FXDIB_Format::kRgb32:
519       return FXARGB_GETDIB(pos) | 0xff000000;
520     case FXDIB_Format::kArgb:
521       return FXARGB_GETDIB(pos);
522     default:
523       break;
524   }
525   return 0;
526 }
527 
SetPixel(int x,int y,uint32_t color)528 void CFX_DIBitmap::SetPixel(int x, int y, uint32_t color) {
529   if (!m_pBuffer)
530     return;
531 
532   if (x < 0 || x >= m_Width || y < 0 || y >= m_Height)
533     return;
534 
535   FX_SAFE_UINT32 offset = x;
536   offset *= GetBPP();
537   offset /= 8;
538   if (!offset.IsValid())
539     return;
540 
541   uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + offset.ValueOrDie();
542   switch (GetFormat()) {
543     case FXDIB_Format::k1bppMask:
544       if (color >> 24) {
545         *pos |= 1 << (7 - x % 8);
546       } else {
547         *pos &= ~(1 << (7 - x % 8));
548       }
549       break;
550     case FXDIB_Format::k1bppRgb:
551       if (HasPalette()) {
552         if (color == GetPaletteSpan()[1]) {
553           *pos |= 1 << (7 - x % 8);
554         } else {
555           *pos &= ~(1 << (7 - x % 8));
556         }
557       } else {
558         if (color == 0xffffffff) {
559           *pos |= 1 << (7 - x % 8);
560         } else {
561           *pos &= ~(1 << (7 - x % 8));
562         }
563       }
564       break;
565     case FXDIB_Format::k8bppMask:
566       *pos = (uint8_t)(color >> 24);
567       break;
568     case FXDIB_Format::k8bppRgb: {
569       if (HasPalette()) {
570         pdfium::span<const uint32_t> palette = GetPaletteSpan();
571         for (int i = 0; i < 256; i++) {
572           if (palette[i] == color) {
573             *pos = (uint8_t)i;
574             return;
575           }
576         }
577         *pos = 0;
578       } else {
579         *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
580       }
581       break;
582     }
583     case FXDIB_Format::kRgb:
584     case FXDIB_Format::kRgb32: {
585       int alpha = FXARGB_A(color);
586       pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255;
587       pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255;
588       pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255;
589       break;
590     }
591     case FXDIB_Format::kArgb:
592       FXARGB_SETDIB(pos, color);
593       break;
594     default:
595       break;
596   }
597 }
598 #endif  // defined(_SKIA_SUPPORT_)
599 
ConvertBGRColorScale(uint32_t forecolor,uint32_t backcolor)600 void CFX_DIBitmap::ConvertBGRColorScale(uint32_t forecolor,
601                                         uint32_t backcolor) {
602   int fr = FXSYS_GetRValue(forecolor);
603   int fg = FXSYS_GetGValue(forecolor);
604   int fb = FXSYS_GetBValue(forecolor);
605   int br = FXSYS_GetRValue(backcolor);
606   int bg = FXSYS_GetGValue(backcolor);
607   int bb = FXSYS_GetBValue(backcolor);
608   if (GetBppFromFormat(m_Format) <= 8) {
609     if (forecolor == 0 && backcolor == 0xffffff && !HasPalette())
610       return;
611 
612     BuildPalette();
613     int size = 1 << GetBppFromFormat(m_Format);
614     for (int i = 0; i < size; ++i) {
615       int gray = FXRGB2GRAY(FXARGB_R(m_palette[i]), FXARGB_G(m_palette[i]),
616                             FXARGB_B(m_palette[i]));
617       m_palette[i] =
618           ArgbEncode(0xff, br + (fr - br) * gray / 255,
619                      bg + (fg - bg) * gray / 255, bb + (fb - bb) * gray / 255);
620     }
621     return;
622   }
623   if (forecolor == 0 && backcolor == 0xffffff) {
624     for (int row = 0; row < m_Height; ++row) {
625       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
626       int gap = GetBppFromFormat(m_Format) / 8 - 2;
627       for (int col = 0; col < m_Width; ++col) {
628         int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
629         *scanline++ = gray;
630         *scanline++ = gray;
631         *scanline = gray;
632         scanline += gap;
633       }
634     }
635     return;
636   }
637   for (int row = 0; row < m_Height; ++row) {
638     uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
639     int gap = GetBppFromFormat(m_Format) / 8 - 2;
640     for (int col = 0; col < m_Width; ++col) {
641       int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
642       *scanline++ = bb + (fb - bb) * gray / 255;
643       *scanline++ = bg + (fg - bg) * gray / 255;
644       *scanline = br + (fr - br) * gray / 255;
645       scanline += gap;
646     }
647   }
648 }
649 
ConvertColorScale(uint32_t forecolor,uint32_t backcolor)650 bool CFX_DIBitmap::ConvertColorScale(uint32_t forecolor, uint32_t backcolor) {
651   if (!m_pBuffer || IsMaskFormat())
652     return false;
653 
654   ConvertBGRColorScale(forecolor, backcolor);
655   return true;
656 }
657 
658 // static
CalculatePitchAndSize(int width,int height,FXDIB_Format format,uint32_t pitch)659 absl::optional<CFX_DIBitmap::PitchAndSize> CFX_DIBitmap::CalculatePitchAndSize(
660     int width,
661     int height,
662     FXDIB_Format format,
663     uint32_t pitch) {
664   if (width <= 0 || height <= 0)
665     return absl::nullopt;
666 
667   int bpp = GetBppFromFormat(format);
668   if (!bpp)
669     return absl::nullopt;
670 
671   uint32_t actual_pitch = pitch;
672   if (actual_pitch == 0) {
673     absl::optional<uint32_t> pitch32 = fxge::CalculatePitch32(bpp, width);
674     if (!pitch32.has_value()) {
675       return absl::nullopt;
676     }
677 
678     actual_pitch = pitch32.value();
679   }
680 
681   FX_SAFE_UINT32 safe_size = actual_pitch;
682   safe_size *= height;
683   if (!safe_size.IsValid())
684     return absl::nullopt;
685 
686   return PitchAndSize{actual_pitch, safe_size.ValueOrDie()};
687 }
688 
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)689 bool CFX_DIBitmap::CompositeBitmap(int dest_left,
690                                    int dest_top,
691                                    int width,
692                                    int height,
693                                    const RetainPtr<CFX_DIBBase>& pSrcBitmap,
694                                    int src_left,
695                                    int src_top,
696                                    BlendMode blend_type,
697                                    const CFX_ClipRgn* pClipRgn,
698                                    bool bRgbByteOrder) {
699   // Should have called CompositeMask().
700   CHECK(!pSrcBitmap->IsMaskFormat());
701 
702   if (!m_pBuffer)
703     return false;
704 
705   if (GetBppFromFormat(m_Format) < 8)
706     return false;
707 
708   if (!GetOverlapRect(dest_left, dest_top, width, height,
709                       pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left,
710                       src_top, pClipRgn)) {
711     return true;
712   }
713 
714   RetainPtr<CFX_DIBitmap> pClipMask;
715   FX_RECT clip_box;
716   if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::kRectI) {
717     pClipMask = pClipRgn->GetMask();
718     clip_box = pClipRgn->GetBox();
719   }
720   CFX_ScanlineCompositor compositor;
721   if (!compositor.Init(GetFormat(), pSrcBitmap->GetFormat(),
722                        pSrcBitmap->GetPaletteSpan(), 0, blend_type,
723                        pClipMask != nullptr, bRgbByteOrder)) {
724     return false;
725   }
726   const int dest_Bpp = GetBppFromFormat(m_Format) / 8;
727   const int src_Bpp = pSrcBitmap->GetBPP() / 8;
728   const bool bRgb = src_Bpp > 1;
729   if (!bRgb && !pSrcBitmap->HasPalette())
730     return false;
731 
732   for (int row = 0; row < height; row++) {
733     pdfium::span<uint8_t> dest_scan =
734         GetWritableScanline(dest_top + row).subspan(dest_left * dest_Bpp);
735     pdfium::span<const uint8_t> src_scan =
736         pSrcBitmap->GetScanline(src_top + row).subspan(src_left * src_Bpp);
737     pdfium::span<const uint8_t> clip_scan;
738     if (pClipMask) {
739       clip_scan = pClipMask->GetWritableScanline(dest_top + row - clip_box.top)
740                       .subspan(dest_left - clip_box.left);
741     }
742     if (bRgb) {
743       compositor.CompositeRgbBitmapLine(dest_scan, src_scan, width, clip_scan);
744     } else {
745       compositor.CompositePalBitmapLine(dest_scan, src_scan, src_left, width,
746                                         clip_scan);
747     }
748   }
749   return true;
750 }
751 
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)752 bool CFX_DIBitmap::CompositeMask(int dest_left,
753                                  int dest_top,
754                                  int width,
755                                  int height,
756                                  const RetainPtr<CFX_DIBBase>& pMask,
757                                  uint32_t color,
758                                  int src_left,
759                                  int src_top,
760                                  BlendMode blend_type,
761                                  const CFX_ClipRgn* pClipRgn,
762                                  bool bRgbByteOrder) {
763   // Should have called CompositeBitmap().
764   CHECK(pMask->IsMaskFormat());
765 
766   if (!m_pBuffer)
767     return false;
768 
769   if (GetBppFromFormat(m_Format) < 8)
770     return false;
771 
772   if (!GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(),
773                       pMask->GetHeight(), src_left, src_top, pClipRgn)) {
774     return true;
775   }
776 
777   int src_alpha = FXARGB_A(color);
778   if (src_alpha == 0)
779     return true;
780 
781   RetainPtr<CFX_DIBitmap> pClipMask;
782   FX_RECT clip_box;
783   if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::kRectI) {
784     pClipMask = pClipRgn->GetMask();
785     clip_box = pClipRgn->GetBox();
786   }
787   int src_bpp = pMask->GetBPP();
788   int Bpp = GetBPP() / 8;
789   CFX_ScanlineCompositor compositor;
790   if (!compositor.Init(GetFormat(), pMask->GetFormat(), {}, color, blend_type,
791                        pClipMask != nullptr, bRgbByteOrder)) {
792     return false;
793   }
794   for (int row = 0; row < height; row++) {
795     pdfium::span<uint8_t> dest_scan =
796         GetWritableScanline(dest_top + row).subspan(dest_left * Bpp);
797     pdfium::span<const uint8_t> src_scan = pMask->GetScanline(src_top + row);
798     pdfium::span<const uint8_t> clip_scan;
799     if (pClipMask) {
800       clip_scan = pClipMask->GetScanline(dest_top + row - clip_box.top)
801                       .subspan(dest_left - clip_box.left);
802     }
803     if (src_bpp == 1) {
804       compositor.CompositeBitMaskLine(dest_scan, src_scan, src_left, width,
805                                       clip_scan);
806     } else {
807       compositor.CompositeByteMaskLine(dest_scan, src_scan.subspan(src_left),
808                                        width, clip_scan);
809     }
810   }
811   return true;
812 }
813 
CompositeOneBPPMask(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)814 void CFX_DIBitmap::CompositeOneBPPMask(int dest_left,
815                                        int dest_top,
816                                        int width,
817                                        int height,
818                                        const RetainPtr<CFX_DIBBase>& pSrcBitmap,
819                                        int src_left,
820                                        int src_top) {
821   if (GetBPP() != 1) {
822     return;
823   }
824 
825   if (!GetOverlapRect(dest_left, dest_top, width, height,
826                       pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left,
827                       src_top, nullptr)) {
828     return;
829   }
830 
831   for (int row = 0; row < height; ++row) {
832     uint8_t* dest_scan = m_pBuffer.Get() + (dest_top + row) * m_Pitch;
833     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
834     for (int col = 0; col < width; ++col) {
835       int src_idx = src_left + col;
836       int dest_idx = dest_left + col;
837       if (src_scan[src_idx / 8] & (1 << (7 - src_idx % 8))) {
838         dest_scan[dest_idx / 8] |= 1 << (7 - dest_idx % 8);
839       }
840     }
841   }
842 }
843 
CompositeRect(int left,int top,int width,int height,uint32_t color)844 bool CFX_DIBitmap::CompositeRect(int left,
845                                  int top,
846                                  int width,
847                                  int height,
848                                  uint32_t color) {
849   if (!m_pBuffer)
850     return false;
851 
852   int src_alpha = FXARGB_A(color);
853   if (src_alpha == 0)
854     return true;
855 
856   FX_RECT rect(left, top, left + width, top + height);
857   rect.Intersect(0, 0, m_Width, m_Height);
858   if (rect.IsEmpty())
859     return true;
860 
861   width = rect.Width();
862   uint32_t dst_color = color;
863   uint8_t* color_p = reinterpret_cast<uint8_t*>(&dst_color);
864   if (GetBppFromFormat(m_Format) == 8) {
865     uint8_t gray = IsMaskFormat() ? 255
866                                   : (uint8_t)FXRGB2GRAY((int)color_p[2],
867                                                         color_p[1], color_p[0]);
868     for (int row = rect.top; row < rect.bottom; row++) {
869       uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left;
870       if (src_alpha == 255) {
871         memset(dest_scan, gray, width);
872       } else {
873         for (int col = 0; col < width; col++) {
874           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
875           dest_scan++;
876         }
877       }
878     }
879     return true;
880   }
881   if (GetBppFromFormat(m_Format) == 1) {
882     int left_shift = rect.left % 8;
883     int right_shift = rect.right % 8;
884     int new_width = rect.right / 8 - rect.left / 8;
885     int index = 0;
886     if (HasPalette()) {
887       for (int i = 0; i < 2; i++) {
888         if (GetPaletteSpan()[i] == color)
889           index = i;
890       }
891     } else {
892       index = (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
893     }
894     for (int row = rect.top; row < rect.bottom; row++) {
895       uint8_t* dest_scan_top =
896           GetWritableScanline(row).subspan(rect.left / 8).data();
897       uint8_t* dest_scan_top_r =
898           GetWritableScanline(row).subspan(rect.right / 8).data();
899       uint8_t left_flag = *dest_scan_top & (255 << (8 - left_shift));
900       uint8_t right_flag = *dest_scan_top_r & (255 >> right_shift);
901       if (new_width) {
902         memset(dest_scan_top + 1, index ? 255 : 0, new_width - 1);
903         if (!index) {
904           *dest_scan_top &= left_flag;
905           *dest_scan_top_r &= right_flag;
906         } else {
907           *dest_scan_top |= ~left_flag;
908           *dest_scan_top_r |= ~right_flag;
909         }
910       } else {
911         if (!index) {
912           *dest_scan_top &= left_flag | right_flag;
913         } else {
914           *dest_scan_top |= ~(left_flag | right_flag);
915         }
916       }
917     }
918     return true;
919   }
920 
921   CHECK_GE(GetBppFromFormat(m_Format), 24);
922   color_p[3] = static_cast<uint8_t>(src_alpha);
923   int Bpp = GetBppFromFormat(m_Format) / 8;
924   const bool bAlpha = IsAlphaFormat();
925   if (bAlpha) {
926     // Other formats with alpha have already been handled above.
927     DCHECK_EQ(GetFormat(), FXDIB_Format::kArgb);
928   }
929   if (src_alpha == 255) {
930     for (int row = rect.top; row < rect.bottom; row++) {
931       uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
932       if (Bpp == 4) {
933         uint32_t* scan = reinterpret_cast<uint32_t*>(dest_scan);
934         for (int col = 0; col < width; col++)
935           *scan++ = dst_color;
936       } else {
937         for (int col = 0; col < width; col++) {
938           *dest_scan++ = color_p[0];
939           *dest_scan++ = color_p[1];
940           *dest_scan++ = color_p[2];
941         }
942       }
943     }
944     return true;
945   }
946   for (int row = rect.top; row < rect.bottom; row++) {
947     uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
948     if (bAlpha) {
949       for (int col = 0; col < width; col++) {
950         uint8_t back_alpha = dest_scan[3];
951         if (back_alpha == 0) {
952           FXARGB_SETDIB(dest_scan, ArgbEncode(src_alpha, color_p[2], color_p[1],
953                                               color_p[0]));
954           dest_scan += 4;
955           continue;
956         }
957         uint8_t dest_alpha =
958             back_alpha + src_alpha - back_alpha * src_alpha / 255;
959         int alpha_ratio = src_alpha * 255 / dest_alpha;
960         *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[0], alpha_ratio);
961         dest_scan++;
962         *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[1], alpha_ratio);
963         dest_scan++;
964         *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[2], alpha_ratio);
965         dest_scan++;
966         *dest_scan++ = dest_alpha;
967       }
968     } else {
969       for (int col = 0; col < width; col++) {
970         for (int comps = 0; comps < Bpp; comps++) {
971           if (comps == 3) {
972             *dest_scan++ = 255;
973             continue;
974           }
975           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], src_alpha);
976           dest_scan++;
977         }
978       }
979     }
980   }
981   return true;
982 }
983 
ConvertFormat(FXDIB_Format dest_format)984 bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
985   DCHECK(dest_format == FXDIB_Format::k8bppMask ||
986          dest_format == FXDIB_Format::kArgb ||
987          dest_format == FXDIB_Format::kRgb32 ||
988          dest_format == FXDIB_Format::kRgb);
989 
990   if (dest_format == m_Format)
991     return true;
992 
993   if (dest_format == FXDIB_Format::k8bppMask &&
994       m_Format == FXDIB_Format::k8bppRgb && !HasPalette()) {
995     m_Format = FXDIB_Format::k8bppMask;
996     return true;
997   }
998   if (dest_format == FXDIB_Format::kArgb && m_Format == FXDIB_Format::kRgb32) {
999     m_Format = FXDIB_Format::kArgb;
1000     for (int row = 0; row < m_Height; row++) {
1001       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch + 3;
1002       for (int col = 0; col < m_Width; col++) {
1003         *scanline = 0xff;
1004         scanline += 4;
1005       }
1006     }
1007     return true;
1008   }
1009   int dest_bpp = GetBppFromFormat(dest_format);
1010   int dest_pitch = fxge::CalculatePitch32OrDie(dest_bpp, m_Width);
1011   const size_t dest_buf_size = dest_pitch * m_Height + 4;
1012   std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
1013       FX_TryAlloc(uint8_t, dest_buf_size));
1014   if (!dest_buf)
1015     return false;
1016 
1017   if (dest_format == FXDIB_Format::kArgb) {
1018     memset(dest_buf.get(), 0xff, dest_buf_size);
1019   }
1020   RetainPtr<CFX_DIBBase> holder(this);
1021   DataVector<uint32_t> pal_8bpp;
1022   if (!ConvertBuffer(dest_format, {dest_buf.get(), dest_buf_size}, dest_pitch,
1023                      m_Width, m_Height, holder, 0, 0, &pal_8bpp)) {
1024     return false;
1025   }
1026 
1027   m_palette = std::move(pal_8bpp);
1028   m_pBuffer = std::move(dest_buf);
1029   m_Format = dest_format;
1030   m_Pitch = dest_pitch;
1031   return true;
1032 }
1033