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