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