• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fxge/dib/cfx_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<uint8_t> CFX_DIBitmap::GetBuffer() const {
89   if (!m_pBuffer)
90     return pdfium::span<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 = GetBuffer().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   if (!m_pBuffer)
393     return false;
394 
395   if (!pSrcBitmap->IsMaskFormat()) {
396     NOTREACHED();
397     return false;
398   }
399 
400   if (IsOpaqueImage())
401     return SetAlphaFromBitmap(pSrcBitmap);
402 
403   RetainPtr<CFX_DIBitmap> pSrcClone = pSrcBitmap.As<CFX_DIBitmap>();
404   if (pSrcBitmap->GetWidth() != m_Width ||
405       pSrcBitmap->GetHeight() != m_Height) {
406     pSrcClone = pSrcBitmap->StretchTo(m_Width, m_Height,
407                                       FXDIB_ResampleOptions(), nullptr);
408     if (!pSrcClone)
409       return false;
410   }
411   if (IsMaskFormat()) {
412     if (!ConvertFormat(FXDIB_Format::k8bppMask))
413       return false;
414 
415     for (int row = 0; row < m_Height; row++) {
416       uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row;
417       uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
418       if (pSrcClone->GetBPP() == 1) {
419         for (int col = 0; col < m_Width; col++) {
420           if (!((1 << (7 - col % 8)) & src_scan[col / 8]))
421             dest_scan[col] = 0;
422         }
423       } else {
424         for (int col = 0; col < m_Width; col++) {
425           *dest_scan = (*dest_scan) * src_scan[col] / 255;
426           dest_scan++;
427         }
428       }
429     }
430     return true;
431   }
432 
433   DCHECK_EQ(GetFormat(), FXDIB_Format::kArgb);
434   if (pSrcClone->GetBPP() == 1)
435     return false;
436 
437   for (int row = 0; row < m_Height; row++) {
438     uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row + 3;
439     uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
440     for (int col = 0; col < m_Width; col++) {
441       *dest_scan = (*dest_scan) * src_scan[col] / 255;
442       dest_scan += 4;
443     }
444   }
445   return true;
446 }
447 
MultiplyAlpha(int alpha)448 bool CFX_DIBitmap::MultiplyAlpha(int alpha) {
449   if (!m_pBuffer)
450     return false;
451 
452   switch (GetFormat()) {
453     case FXDIB_Format::k1bppMask:
454       if (!ConvertFormat(FXDIB_Format::k8bppMask)) {
455         return false;
456       }
457       MultiplyAlpha(alpha);
458       break;
459     case FXDIB_Format::k8bppMask: {
460       for (int row = 0; row < m_Height; row++) {
461         uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch;
462         for (int col = 0; col < m_Width; col++) {
463           scan_line[col] = scan_line[col] * alpha / 255;
464         }
465       }
466       break;
467     }
468     case FXDIB_Format::kArgb: {
469       for (int row = 0; row < m_Height; row++) {
470         uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + 3;
471         for (int col = 0; col < m_Width; col++) {
472           *scan_line = (*scan_line) * alpha / 255;
473           scan_line += 4;
474         }
475       }
476       break;
477     }
478     default:
479       DCHECK(!IsAlphaFormat());
480       if (!ConvertFormat(FXDIB_Format::kArgb)) {
481         return false;
482       }
483       MultiplyAlpha(alpha);
484       break;
485   }
486   return true;
487 }
488 
489 #if defined(_SKIA_SUPPORT_)
GetPixel(int x,int y) const490 uint32_t CFX_DIBitmap::GetPixel(int x, int y) const {
491   if (!m_pBuffer)
492     return 0;
493 
494   FX_SAFE_UINT32 offset = x;
495   offset *= GetBPP();
496   offset /= 8;
497   if (!offset.IsValid())
498     return 0;
499 
500   uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + offset.ValueOrDie();
501   switch (GetFormat()) {
502     case FXDIB_Format::k1bppMask: {
503       if ((*pos) & (1 << (7 - x % 8))) {
504         return 0xff000000;
505       }
506       return 0;
507     }
508     case FXDIB_Format::k1bppRgb: {
509       if ((*pos) & (1 << (7 - x % 8))) {
510         return HasPalette() ? GetPaletteSpan()[1] : 0xffffffff;
511       }
512       return HasPalette() ? GetPaletteSpan()[0] : 0xff000000;
513     }
514     case FXDIB_Format::k8bppMask:
515       return (*pos) << 24;
516     case FXDIB_Format::k8bppRgb:
517       return HasPalette() ? GetPaletteSpan()[*pos]
518                           : ArgbEncode(0xff, *pos, *pos, *pos);
519     case FXDIB_Format::kRgb:
520     case FXDIB_Format::kRgb32:
521       return FXARGB_GETDIB(pos) | 0xff000000;
522     case FXDIB_Format::kArgb:
523       return FXARGB_GETDIB(pos);
524     default:
525       break;
526   }
527   return 0;
528 }
529 
SetPixel(int x,int y,uint32_t color)530 void CFX_DIBitmap::SetPixel(int x, int y, uint32_t color) {
531   if (!m_pBuffer)
532     return;
533 
534   if (x < 0 || x >= m_Width || y < 0 || y >= m_Height)
535     return;
536 
537   FX_SAFE_UINT32 offset = x;
538   offset *= GetBPP();
539   offset /= 8;
540   if (!offset.IsValid())
541     return;
542 
543   uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + offset.ValueOrDie();
544   switch (GetFormat()) {
545     case FXDIB_Format::k1bppMask:
546       if (color >> 24) {
547         *pos |= 1 << (7 - x % 8);
548       } else {
549         *pos &= ~(1 << (7 - x % 8));
550       }
551       break;
552     case FXDIB_Format::k1bppRgb:
553       if (HasPalette()) {
554         if (color == GetPaletteSpan()[1]) {
555           *pos |= 1 << (7 - x % 8);
556         } else {
557           *pos &= ~(1 << (7 - x % 8));
558         }
559       } else {
560         if (color == 0xffffffff) {
561           *pos |= 1 << (7 - x % 8);
562         } else {
563           *pos &= ~(1 << (7 - x % 8));
564         }
565       }
566       break;
567     case FXDIB_Format::k8bppMask:
568       *pos = (uint8_t)(color >> 24);
569       break;
570     case FXDIB_Format::k8bppRgb: {
571       if (HasPalette()) {
572         pdfium::span<const uint32_t> palette = GetPaletteSpan();
573         for (int i = 0; i < 256; i++) {
574           if (palette[i] == color) {
575             *pos = (uint8_t)i;
576             return;
577           }
578         }
579         *pos = 0;
580       } else {
581         *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
582       }
583       break;
584     }
585     case FXDIB_Format::kRgb:
586     case FXDIB_Format::kRgb32: {
587       int alpha = FXARGB_A(color);
588       pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255;
589       pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255;
590       pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255;
591       break;
592     }
593     case FXDIB_Format::kArgb:
594       FXARGB_SETDIB(pos, color);
595       break;
596     default:
597       break;
598   }
599 }
600 #endif  // defined(_SKIA_SUPPORT_)
601 
ConvertBGRColorScale(uint32_t forecolor,uint32_t backcolor)602 void CFX_DIBitmap::ConvertBGRColorScale(uint32_t forecolor,
603                                         uint32_t backcolor) {
604   int fr = FXSYS_GetRValue(forecolor);
605   int fg = FXSYS_GetGValue(forecolor);
606   int fb = FXSYS_GetBValue(forecolor);
607   int br = FXSYS_GetRValue(backcolor);
608   int bg = FXSYS_GetGValue(backcolor);
609   int bb = FXSYS_GetBValue(backcolor);
610   if (GetBppFromFormat(m_Format) <= 8) {
611     if (forecolor == 0 && backcolor == 0xffffff && !HasPalette())
612       return;
613 
614     BuildPalette();
615     int size = 1 << GetBppFromFormat(m_Format);
616     for (int i = 0; i < size; ++i) {
617       int gray = FXRGB2GRAY(FXARGB_R(m_palette[i]), FXARGB_G(m_palette[i]),
618                             FXARGB_B(m_palette[i]));
619       m_palette[i] =
620           ArgbEncode(0xff, br + (fr - br) * gray / 255,
621                      bg + (fg - bg) * gray / 255, bb + (fb - bb) * gray / 255);
622     }
623     return;
624   }
625   if (forecolor == 0 && backcolor == 0xffffff) {
626     for (int row = 0; row < m_Height; ++row) {
627       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
628       int gap = GetBppFromFormat(m_Format) / 8 - 2;
629       for (int col = 0; col < m_Width; ++col) {
630         int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
631         *scanline++ = gray;
632         *scanline++ = gray;
633         *scanline = gray;
634         scanline += gap;
635       }
636     }
637     return;
638   }
639   for (int row = 0; row < m_Height; ++row) {
640     uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
641     int gap = GetBppFromFormat(m_Format) / 8 - 2;
642     for (int col = 0; col < m_Width; ++col) {
643       int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
644       *scanline++ = bb + (fb - bb) * gray / 255;
645       *scanline++ = bg + (fg - bg) * gray / 255;
646       *scanline = br + (fr - br) * gray / 255;
647       scanline += gap;
648     }
649   }
650 }
651 
ConvertColorScale(uint32_t forecolor,uint32_t backcolor)652 bool CFX_DIBitmap::ConvertColorScale(uint32_t forecolor, uint32_t backcolor) {
653   if (!m_pBuffer || IsMaskFormat())
654     return false;
655 
656   ConvertBGRColorScale(forecolor, backcolor);
657   return true;
658 }
659 
660 // static
CalculatePitchAndSize(int width,int height,FXDIB_Format format,uint32_t pitch)661 absl::optional<CFX_DIBitmap::PitchAndSize> CFX_DIBitmap::CalculatePitchAndSize(
662     int width,
663     int height,
664     FXDIB_Format format,
665     uint32_t pitch) {
666   if (width <= 0 || height <= 0)
667     return absl::nullopt;
668 
669   int bpp = GetBppFromFormat(format);
670   if (!bpp)
671     return absl::nullopt;
672 
673   uint32_t actual_pitch = pitch;
674   if (actual_pitch == 0) {
675     absl::optional<uint32_t> pitch32 = fxge::CalculatePitch32(bpp, width);
676     if (!pitch32.has_value()) {
677       return absl::nullopt;
678     }
679 
680     actual_pitch = pitch32.value();
681   }
682 
683   FX_SAFE_UINT32 safe_size = actual_pitch;
684   safe_size *= height;
685   if (!safe_size.IsValid())
686     return absl::nullopt;
687 
688   return PitchAndSize{actual_pitch, safe_size.ValueOrDie()};
689 }
690 
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)691 bool CFX_DIBitmap::CompositeBitmap(int dest_left,
692                                    int dest_top,
693                                    int width,
694                                    int height,
695                                    const RetainPtr<CFX_DIBBase>& pSrcBitmap,
696                                    int src_left,
697                                    int src_top,
698                                    BlendMode blend_type,
699                                    const CFX_ClipRgn* pClipRgn,
700                                    bool bRgbByteOrder) {
701   if (pSrcBitmap->IsMaskFormat()) {
702     // Should have called CompositeMask().
703     NOTREACHED();
704     return false;
705   }
706 
707   if (!m_pBuffer)
708     return false;
709 
710   if (GetBppFromFormat(m_Format) < 8)
711     return false;
712 
713   if (!GetOverlapRect(dest_left, dest_top, width, height,
714                       pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left,
715                       src_top, pClipRgn)) {
716     return true;
717   }
718 
719   RetainPtr<CFX_DIBitmap> pClipMask;
720   FX_RECT clip_box;
721   if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::kRectI) {
722     pClipMask = pClipRgn->GetMask();
723     clip_box = pClipRgn->GetBox();
724   }
725   CFX_ScanlineCompositor compositor;
726   if (!compositor.Init(GetFormat(), pSrcBitmap->GetFormat(),
727                        pSrcBitmap->GetPaletteSpan(), 0, blend_type,
728                        pClipMask != nullptr, bRgbByteOrder)) {
729     return false;
730   }
731   const int dest_Bpp = GetBppFromFormat(m_Format) / 8;
732   const int src_Bpp = pSrcBitmap->GetBPP() / 8;
733   const bool bRgb = src_Bpp > 1;
734   if (!bRgb && !pSrcBitmap->HasPalette())
735     return false;
736 
737   for (int row = 0; row < height; row++) {
738     pdfium::span<uint8_t> dest_scan =
739         GetWritableScanline(dest_top + row).subspan(dest_left * dest_Bpp);
740     pdfium::span<const uint8_t> src_scan =
741         pSrcBitmap->GetScanline(src_top + row).subspan(src_left * src_Bpp);
742     pdfium::span<const uint8_t> clip_scan;
743     if (pClipMask) {
744       clip_scan = pClipMask->GetWritableScanline(dest_top + row - clip_box.top)
745                       .subspan(dest_left - clip_box.left);
746     }
747     if (bRgb) {
748       compositor.CompositeRgbBitmapLine(dest_scan, src_scan, width, clip_scan);
749     } else {
750       compositor.CompositePalBitmapLine(dest_scan, src_scan, src_left, width,
751                                         clip_scan);
752     }
753   }
754   return true;
755 }
756 
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)757 bool CFX_DIBitmap::CompositeMask(int dest_left,
758                                  int dest_top,
759                                  int width,
760                                  int height,
761                                  const RetainPtr<CFX_DIBBase>& pMask,
762                                  uint32_t color,
763                                  int src_left,
764                                  int src_top,
765                                  BlendMode blend_type,
766                                  const CFX_ClipRgn* pClipRgn,
767                                  bool bRgbByteOrder) {
768   if (!pMask->IsMaskFormat()) {
769     // Should have called CompositeBitmap().
770     NOTREACHED();
771     return false;
772   }
773 
774   if (!m_pBuffer)
775     return false;
776 
777   if (GetBppFromFormat(m_Format) < 8)
778     return false;
779 
780   if (!GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(),
781                       pMask->GetHeight(), src_left, src_top, pClipRgn)) {
782     return true;
783   }
784 
785   int src_alpha = FXARGB_A(color);
786   if (src_alpha == 0)
787     return true;
788 
789   RetainPtr<CFX_DIBitmap> pClipMask;
790   FX_RECT clip_box;
791   if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::kRectI) {
792     pClipMask = pClipRgn->GetMask();
793     clip_box = pClipRgn->GetBox();
794   }
795   int src_bpp = pMask->GetBPP();
796   int Bpp = GetBPP() / 8;
797   CFX_ScanlineCompositor compositor;
798   if (!compositor.Init(GetFormat(), pMask->GetFormat(), {}, color, blend_type,
799                        pClipMask != nullptr, bRgbByteOrder)) {
800     return false;
801   }
802   for (int row = 0; row < height; row++) {
803     pdfium::span<uint8_t> dest_scan =
804         GetWritableScanline(dest_top + row).subspan(dest_left * Bpp);
805     pdfium::span<const uint8_t> src_scan = pMask->GetScanline(src_top + row);
806     pdfium::span<const uint8_t> clip_scan;
807     if (pClipMask) {
808       clip_scan = pClipMask->GetScanline(dest_top + row - clip_box.top)
809                       .subspan(dest_left - clip_box.left);
810     }
811     if (src_bpp == 1) {
812       compositor.CompositeBitMaskLine(dest_scan, src_scan, src_left, width,
813                                       clip_scan);
814     } else {
815       compositor.CompositeByteMaskLine(dest_scan, src_scan.subspan(src_left),
816                                        width, clip_scan);
817     }
818   }
819   return true;
820 }
821 
CompositeOneBPPMask(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)822 void CFX_DIBitmap::CompositeOneBPPMask(int dest_left,
823                                        int dest_top,
824                                        int width,
825                                        int height,
826                                        const RetainPtr<CFX_DIBBase>& pSrcBitmap,
827                                        int src_left,
828                                        int src_top) {
829   if (GetBPP() != 1) {
830     return;
831   }
832 
833   if (!GetOverlapRect(dest_left, dest_top, width, height,
834                       pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left,
835                       src_top, nullptr)) {
836     return;
837   }
838 
839   for (int row = 0; row < height; ++row) {
840     uint8_t* dest_scan = m_pBuffer.Get() + (dest_top + row) * m_Pitch;
841     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
842     for (int col = 0; col < width; ++col) {
843       int src_idx = src_left + col;
844       int dest_idx = dest_left + col;
845       if (src_scan[src_idx / 8] & (1 << (7 - src_idx % 8))) {
846         dest_scan[dest_idx / 8] |= 1 << (7 - dest_idx % 8);
847       }
848     }
849   }
850 }
851 
CompositeRect(int left,int top,int width,int height,uint32_t color)852 bool CFX_DIBitmap::CompositeRect(int left,
853                                  int top,
854                                  int width,
855                                  int height,
856                                  uint32_t color) {
857   if (!m_pBuffer)
858     return false;
859 
860   int src_alpha = FXARGB_A(color);
861   if (src_alpha == 0)
862     return true;
863 
864   FX_RECT rect(left, top, left + width, top + height);
865   rect.Intersect(0, 0, m_Width, m_Height);
866   if (rect.IsEmpty())
867     return true;
868 
869   width = rect.Width();
870   uint32_t dst_color = color;
871   uint8_t* color_p = reinterpret_cast<uint8_t*>(&dst_color);
872   if (GetBppFromFormat(m_Format) == 8) {
873     uint8_t gray = IsMaskFormat() ? 255
874                                   : (uint8_t)FXRGB2GRAY((int)color_p[2],
875                                                         color_p[1], color_p[0]);
876     for (int row = rect.top; row < rect.bottom; row++) {
877       uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left;
878       if (src_alpha == 255) {
879         memset(dest_scan, gray, width);
880       } else {
881         for (int col = 0; col < width; col++) {
882           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
883           dest_scan++;
884         }
885       }
886     }
887     return true;
888   }
889   if (GetBppFromFormat(m_Format) == 1) {
890     int left_shift = rect.left % 8;
891     int right_shift = rect.right % 8;
892     int new_width = rect.right / 8 - rect.left / 8;
893     int index = 0;
894     if (HasPalette()) {
895       for (int i = 0; i < 2; i++) {
896         if (GetPaletteSpan()[i] == color)
897           index = i;
898       }
899     } else {
900       index = (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
901     }
902     for (int row = rect.top; row < rect.bottom; row++) {
903       uint8_t* dest_scan_top =
904           GetWritableScanline(row).subspan(rect.left / 8).data();
905       uint8_t* dest_scan_top_r =
906           GetWritableScanline(row).subspan(rect.right / 8).data();
907       uint8_t left_flag = *dest_scan_top & (255 << (8 - left_shift));
908       uint8_t right_flag = *dest_scan_top_r & (255 >> right_shift);
909       if (new_width) {
910         memset(dest_scan_top + 1, index ? 255 : 0, new_width - 1);
911         if (!index) {
912           *dest_scan_top &= left_flag;
913           *dest_scan_top_r &= right_flag;
914         } else {
915           *dest_scan_top |= ~left_flag;
916           *dest_scan_top_r |= ~right_flag;
917         }
918       } else {
919         if (!index) {
920           *dest_scan_top &= left_flag | right_flag;
921         } else {
922           *dest_scan_top |= ~(left_flag | right_flag);
923         }
924       }
925     }
926     return true;
927   }
928 
929   if (GetBppFromFormat(m_Format) < 24) {
930     NOTREACHED();
931     return false;
932   }
933 
934   color_p[3] = static_cast<uint8_t>(src_alpha);
935   int Bpp = GetBppFromFormat(m_Format) / 8;
936   const bool bAlpha = IsAlphaFormat();
937   if (bAlpha) {
938     // Other formats with alpha have already been handled above.
939     DCHECK_EQ(GetFormat(), FXDIB_Format::kArgb);
940   }
941   if (src_alpha == 255) {
942     for (int row = rect.top; row < rect.bottom; row++) {
943       uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
944       if (Bpp == 4) {
945         uint32_t* scan = reinterpret_cast<uint32_t*>(dest_scan);
946         for (int col = 0; col < width; col++)
947           *scan++ = dst_color;
948       } else {
949         for (int col = 0; col < width; col++) {
950           *dest_scan++ = color_p[0];
951           *dest_scan++ = color_p[1];
952           *dest_scan++ = color_p[2];
953         }
954       }
955     }
956     return true;
957   }
958   for (int row = rect.top; row < rect.bottom; row++) {
959     uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
960     if (bAlpha) {
961       for (int col = 0; col < width; col++) {
962         uint8_t back_alpha = dest_scan[3];
963         if (back_alpha == 0) {
964           FXARGB_SETDIB(dest_scan, ArgbEncode(src_alpha, color_p[2], color_p[1],
965                                               color_p[0]));
966           dest_scan += 4;
967           continue;
968         }
969         uint8_t dest_alpha =
970             back_alpha + src_alpha - back_alpha * src_alpha / 255;
971         int alpha_ratio = src_alpha * 255 / dest_alpha;
972         *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[0], alpha_ratio);
973         dest_scan++;
974         *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[1], alpha_ratio);
975         dest_scan++;
976         *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[2], alpha_ratio);
977         dest_scan++;
978         *dest_scan++ = dest_alpha;
979       }
980     } else {
981       for (int col = 0; col < width; col++) {
982         for (int comps = 0; comps < Bpp; comps++) {
983           if (comps == 3) {
984             *dest_scan++ = 255;
985             continue;
986           }
987           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], src_alpha);
988           dest_scan++;
989         }
990       }
991     }
992   }
993   return true;
994 }
995 
ConvertFormat(FXDIB_Format dest_format)996 bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
997   DCHECK(dest_format == FXDIB_Format::k8bppMask ||
998          dest_format == FXDIB_Format::kArgb ||
999          dest_format == FXDIB_Format::kRgb32 ||
1000          dest_format == FXDIB_Format::kRgb);
1001 
1002   if (dest_format == m_Format)
1003     return true;
1004 
1005   if (dest_format == FXDIB_Format::k8bppMask &&
1006       m_Format == FXDIB_Format::k8bppRgb && !HasPalette()) {
1007     m_Format = FXDIB_Format::k8bppMask;
1008     return true;
1009   }
1010   if (dest_format == FXDIB_Format::kArgb && m_Format == FXDIB_Format::kRgb32) {
1011     m_Format = FXDIB_Format::kArgb;
1012     for (int row = 0; row < m_Height; row++) {
1013       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch + 3;
1014       for (int col = 0; col < m_Width; col++) {
1015         *scanline = 0xff;
1016         scanline += 4;
1017       }
1018     }
1019     return true;
1020   }
1021   int dest_bpp = GetBppFromFormat(dest_format);
1022   int dest_pitch = fxge::CalculatePitch32OrDie(dest_bpp, m_Width);
1023   const size_t dest_buf_size = dest_pitch * m_Height + 4;
1024   std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
1025       FX_TryAlloc(uint8_t, dest_buf_size));
1026   if (!dest_buf)
1027     return false;
1028 
1029   if (dest_format == FXDIB_Format::kArgb) {
1030     memset(dest_buf.get(), 0xff, dest_buf_size);
1031   }
1032   RetainPtr<CFX_DIBBase> holder(this);
1033   DataVector<uint32_t> pal_8bpp;
1034   if (!ConvertBuffer(dest_format, {dest_buf.get(), dest_buf_size}, dest_pitch,
1035                      m_Width, m_Height, holder, 0, 0, &pal_8bpp)) {
1036     return false;
1037   }
1038 
1039   m_palette = std::move(pal_8bpp);
1040   m_pBuffer = std::move(dest_buf);
1041   m_Format = dest_format;
1042   m_Pitch = dest_pitch;
1043   return true;
1044 }
1045