Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfx_dibitmap.cpp
Go to the documentation of this file.
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
30CFX_DIBitmap::CFX_DIBitmap() = default;
31
32bool CFX_DIBitmap::Create(int width, int height, FXDIB_Format format) {
33 return Create(width, height, format, nullptr, 0);
34}
35
36bool 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
71bool CFX_DIBitmap::Copy(RetainPtr<const CFX_DIBBase> source) {
72 if (m_pBuffer)
73 return false;
74
75 if (!Create(source->GetWidth(), source->GetHeight(), source->GetFormat())) {
76 return false;
77 }
78
79 SetPalette(source->GetPaletteSpan());
80 for (int row = 0; row < source->GetHeight(); row++) {
81 memcpy(m_pBuffer.Get() + row * m_Pitch, source->GetScanline(row).data(),
82 m_Pitch);
83 }
84 return true;
85}
86
87CFX_DIBitmap::~CFX_DIBitmap() = default;
88
89pdfium::span<const uint8_t> CFX_DIBitmap::GetBuffer() const {
90 if (!m_pBuffer)
91 return pdfium::span<const uint8_t>();
92
93 return {m_pBuffer.Get(), m_Height * m_Pitch};
94}
95
96pdfium::span<const uint8_t> CFX_DIBitmap::GetScanline(int line) const {
97 auto buffer_span = GetBuffer();
98 if (buffer_span.empty())
99 return pdfium::span<const uint8_t>();
100
101 return buffer_span.subspan(line * m_Pitch, m_Pitch);
102}
103
105 size_t result = CFX_DIBBase::GetEstimatedImageMemoryBurden();
106 if (!GetBuffer().empty()) {
107 int height = GetHeight();
108 CHECK(pdfium::base::IsValueInRangeForNumericType<size_t>(height));
109 result += static_cast<size_t>(height) * GetPitch();
110 }
111 return result;
112}
113
114#if BUILDFLAG(IS_WIN) || defined(PDF_USE_SKIA)
115RetainPtr<const CFX_DIBitmap> CFX_DIBitmap::RealizeIfNeeded() const {
116 if (GetBuffer().empty()) {
117 return Realize();
118 }
119 return pdfium::WrapRetain(this);
120}
121#endif
122
123void CFX_DIBitmap::TakeOver(RetainPtr<CFX_DIBitmap>&& pSrcBitmap) {
124 m_pBuffer = std::move(pSrcBitmap->m_pBuffer);
125 m_palette = std::move(pSrcBitmap->m_palette);
126 pSrcBitmap->m_pBuffer = nullptr;
127 m_Format = pSrcBitmap->m_Format;
128 m_Width = pSrcBitmap->m_Width;
129 m_Height = pSrcBitmap->m_Height;
130 m_Pitch = pSrcBitmap->m_Pitch;
131}
132
133void CFX_DIBitmap::Clear(uint32_t color) {
134 if (!m_pBuffer)
135 return;
136
137 uint8_t* pBuffer = m_pBuffer.Get();
138 switch (GetFormat()) {
140 memset(pBuffer, (color & 0xff000000) ? 0xff : 0, m_Pitch * m_Height);
141 break;
143 int index = FindPalette(color);
144 memset(pBuffer, index ? 0xff : 0, m_Pitch * m_Height);
145 break;
146 }
148 memset(pBuffer, color >> 24, m_Pitch * m_Height);
149 break;
151 int index = FindPalette(color);
152 memset(pBuffer, index, m_Pitch * m_Height);
153 break;
154 }
155 case FXDIB_Format::kRgb: {
156 int a;
157 int r;
158 int g;
159 int b;
160 std::tie(a, r, g, b) = ArgbDecode(color);
161 if (r == g && g == b) {
162 memset(pBuffer, r, m_Pitch * m_Height);
163 } else {
164 int byte_pos = 0;
165 for (int col = 0; col < m_Width; col++) {
166 pBuffer[byte_pos++] = b;
167 pBuffer[byte_pos++] = g;
168 pBuffer[byte_pos++] = r;
169 }
170 for (int row = 1; row < m_Height; row++) {
171 memcpy(pBuffer + row * m_Pitch, pBuffer, m_Pitch);
172 }
173 }
174 break;
175 }
177 case FXDIB_Format::kArgb: {
178 if (CFX_DefaultRenderDevice::UseSkiaRenderer() &&
180 // TODO(crbug.com/pdfium/2016): This is not reliable because alpha may
181 // be modified outside of this operation.
182 color |= 0xFF000000;
183 }
184 for (int i = 0; i < m_Width; i++)
185 reinterpret_cast<uint32_t*>(pBuffer)[i] = color;
186 for (int row = 1; row < m_Height; row++)
187 memcpy(pBuffer + row * m_Pitch, pBuffer, m_Pitch);
188 break;
189 }
190 default:
191 break;
192 }
193}
194
195bool CFX_DIBitmap::TransferBitmap(int dest_left,
196 int dest_top,
197 int width,
198 int height,
199 RetainPtr<const CFX_DIBBase> source,
200 int src_left,
201 int src_top) {
202 if (!m_pBuffer)
203 return false;
204
205 if (!GetOverlapRect(dest_left, dest_top, width, height, source->GetWidth(),
206 source->GetHeight(), src_left, src_top, nullptr)) {
207 return true;
208 }
209
210 FXDIB_Format dest_format = GetFormat();
211 FXDIB_Format src_format = source->GetFormat();
212 if (dest_format != src_format) {
213 return TransferWithUnequalFormats(dest_format, dest_left, dest_top, width,
214 height, std::move(source), src_left,
215 src_top);
216 }
217
218 if (GetBPP() != 1) {
219 TransferWithMultipleBPP(dest_left, dest_top, width, height,
220 std::move(source), src_left, src_top);
221 return true;
222 }
223
224 TransferEqualFormatsOneBPP(dest_left, dest_top, width, height,
225 std::move(source), src_left, src_top);
226 return true;
227}
228
229bool CFX_DIBitmap::TransferWithUnequalFormats(
230 FXDIB_Format dest_format,
231 int dest_left,
232 int dest_top,
233 int width,
234 int height,
235 RetainPtr<const CFX_DIBBase> source,
236 int src_left,
237 int src_top) {
238 if (HasPalette())
239 return false;
240
242 dest_format = FXDIB_Format::k8bppMask;
243
244 FX_SAFE_UINT32 offset = dest_left;
245 offset *= GetBPP();
246 offset /= 8;
247 if (!offset.IsValid())
248 return false;
249
250 pdfium::span<uint8_t> dest_buf = GetWritableBuffer().subspan(
251 dest_top * m_Pitch + static_cast<uint32_t>(offset.ValueOrDie()));
252 DataVector<uint32_t> dest_palette = ConvertBuffer(
253 dest_format, dest_buf, m_Pitch, width, height, source, src_left, src_top);
254 CHECK(dest_palette.empty());
255 return true;
256}
257
258void CFX_DIBitmap::TransferWithMultipleBPP(int dest_left,
259 int dest_top,
260 int width,
261 int height,
262 RetainPtr<const CFX_DIBBase> source,
263 int src_left,
264 int src_top) {
265 int Bpp = GetBPP() / 8;
266 for (int row = 0; row < height; ++row) {
267 uint8_t* dest_scan =
268 m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * Bpp;
269 const uint8_t* src_scan =
270 source->GetScanline(src_top + row).subspan(src_left * Bpp).data();
271 memcpy(dest_scan, src_scan, width * Bpp);
272 }
273}
274
275void CFX_DIBitmap::TransferEqualFormatsOneBPP(
276 int dest_left,
277 int dest_top,
278 int width,
279 int height,
280 RetainPtr<const CFX_DIBBase> source,
281 int src_left,
282 int src_top) {
283 for (int row = 0; row < height; ++row) {
284 uint8_t* dest_scan = m_pBuffer.Get() + (dest_top + row) * m_Pitch;
285 const uint8_t* src_scan = source->GetScanline(src_top + row).data();
286 for (int col = 0; col < width; ++col) {
287 int src_idx = src_left + col;
288 int dest_idx = dest_left + col;
289 if (src_scan[(src_idx) / 8] & (1 << (7 - (src_idx) % 8)))
290 dest_scan[(dest_idx) / 8] |= 1 << (7 - (dest_idx) % 8);
291 else
292 dest_scan[(dest_idx) / 8] &= ~(1 << (7 - (dest_idx) % 8));
293 }
294 }
295}
296
297bool CFX_DIBitmap::SetChannelFromBitmap(Channel dest_channel,
298 RetainPtr<const CFX_DIBBase> source) {
299 if (!m_pBuffer)
300 return false;
301
302 if (!source->IsAlphaFormat() && !source->IsMaskFormat()) {
303 return false;
304 }
305
306 if (source->GetBPP() == 1) {
307 source = source->ConvertTo(FXDIB_Format::k8bppMask);
308 if (!source) {
309 return false;
310 }
311 }
312 const int src_offset = source->GetFormat() == FXDIB_Format::kArgb ? 3 : 0;
313 int dest_offset = 0;
314 if (dest_channel == Channel::kAlpha) {
315 if (IsMaskFormat()) {
317 return false;
318 } else {
320 return false;
321
322 dest_offset = 3;
323 }
324 } else {
325 DCHECK_EQ(dest_channel, Channel::kRed);
326 if (IsMaskFormat())
327 return false;
328
329 if (GetBPP() < 24) {
330 if (IsAlphaFormat()) {
332 return false;
333 } else {
335 return false;
336 }
337 }
338 dest_offset = 2;
339 }
340 if (source->GetWidth() != m_Width || source->GetHeight() != m_Height) {
341 source =
342 source->StretchTo(m_Width, m_Height, FXDIB_ResampleOptions(), nullptr);
343 if (!source) {
344 return false;
345 }
346 }
347 RetainPtr<CFX_DIBitmap> dest_bitmap(this);
348 int src_bytes = source->GetBPP() / 8;
349 int dest_bytes = dest_bitmap->GetBPP() / 8;
350 for (int row = 0; row < m_Height; row++) {
351 uint8_t* dest_pos =
352 dest_bitmap->GetWritableScanline(row).subspan(dest_offset).data();
353 const uint8_t* src_pos =
354 source->GetScanline(row).subspan(src_offset).data();
355 for (int col = 0; col < m_Width; col++) {
356 *dest_pos = *src_pos;
357 dest_pos += dest_bytes;
358 src_pos += src_bytes;
359 }
360 }
361 return true;
362}
363
364bool CFX_DIBitmap::SetAlphaFromBitmap(RetainPtr<const CFX_DIBBase> source) {
365 return SetChannelFromBitmap(Channel::kAlpha, std::move(source));
366}
367
368bool CFX_DIBitmap::SetRedFromBitmap(RetainPtr<const CFX_DIBBase> source) {
369 return SetChannelFromBitmap(Channel::kRed, std::move(source));
370}
371
372bool CFX_DIBitmap::SetUniformOpaqueAlpha() {
373 if (!m_pBuffer)
374 return false;
375
376 if (IsMaskFormat()) {
378 return false;
379 } else {
381 return false;
382 }
383 const int Bpp = GetBPP() / 8;
384 if (Bpp == 1) {
385 memset(m_pBuffer.Get(), 0xff, m_Height * m_Pitch);
386 return true;
387 }
388 const int dest_offset = GetFormat() == FXDIB_Format::kArgb ? 3 : 0;
389 for (int row = 0; row < m_Height; row++) {
390 uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + dest_offset;
391 for (int col = 0; col < m_Width; col++) {
392 *scan_line = 0xff;
393 scan_line += Bpp;
394 }
395 }
396 return true;
397}
398
399bool CFX_DIBitmap::MultiplyAlphaMask(RetainPtr<const CFX_DIBBase> source) {
400 CHECK(source->IsMaskFormat());
401
402 if (!m_pBuffer) {
403 return false;
404 }
405
406 if (IsOpaqueImage()) {
407 return SetAlphaFromBitmap(std::move(source));
408 }
409
410 RetainPtr<const CFX_DIBitmap> pSrcClone = source.As<const CFX_DIBitmap>();
411 if (source->GetWidth() != m_Width || source->GetHeight() != m_Height) {
412 pSrcClone =
413 source->StretchTo(m_Width, m_Height, FXDIB_ResampleOptions(), nullptr);
414 if (!pSrcClone)
415 return false;
416 }
417 if (IsMaskFormat()) {
419 return false;
420
421 for (int row = 0; row < m_Height; row++) {
422 uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row;
423 uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
424 if (pSrcClone->GetBPP() == 1) {
425 for (int col = 0; col < m_Width; col++) {
426 if (!((1 << (7 - col % 8)) & src_scan[col / 8]))
427 dest_scan[col] = 0;
428 }
429 } else {
430 for (int col = 0; col < m_Width; col++) {
431 *dest_scan = (*dest_scan) * src_scan[col] / 255;
432 dest_scan++;
433 }
434 }
435 }
436 return true;
437 }
438
439 DCHECK_EQ(GetFormat(), FXDIB_Format::kArgb);
440 if (pSrcClone->GetBPP() == 1)
441 return false;
442
443 for (int row = 0; row < m_Height; row++) {
444 uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row + 3;
445 uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
446 for (int col = 0; col < m_Width; col++) {
447 *dest_scan = (*dest_scan) * src_scan[col] / 255;
448 dest_scan += 4;
449 }
450 }
451 return true;
452}
453
454bool CFX_DIBitmap::MultiplyAlpha(float alpha) {
455 CHECK_GE(alpha, 0.0f);
456 CHECK_LE(alpha, 1.0f);
457
458 if (alpha == 1.0f) {
459 return true;
460 }
461
462 if (!m_pBuffer) {
463 return false;
464 }
465
466 switch (GetFormat()) {
469 return false;
470 }
471 MultiplyAlpha(alpha);
472 break;
474 const int bitmap_alpha = static_cast<int>(alpha * 255);
475 for (int row = 0; row < m_Height; row++) {
476 uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch;
477 for (int col = 0; col < m_Width; col++) {
478 scan_line[col] = scan_line[col] * bitmap_alpha / 255;
479 }
480 }
481 break;
482 }
483 case FXDIB_Format::kArgb: {
484 const int bitmap_alpha = static_cast<int>(alpha * 255);
485 for (int row = 0; row < m_Height; row++) {
486 uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + 3;
487 for (int col = 0; col < m_Width; col++) {
488 *scan_line = (*scan_line) * bitmap_alpha / 255;
489 scan_line += 4;
490 }
491 }
492 break;
493 }
494 default:
495 DCHECK(!IsAlphaFormat());
497 return false;
498 }
499 MultiplyAlpha(alpha);
500 break;
501 }
502 return true;
503}
504
505#if defined(PDF_USE_SKIA)
506uint32_t CFX_DIBitmap::GetPixelForTesting(int x, int y) const {
507 if (!m_pBuffer)
508 return 0;
509
510 FX_SAFE_UINT32 offset = x;
511 offset *= GetBPP();
512 offset /= 8;
513 if (!offset.IsValid())
514 return 0;
515
516 uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + offset.ValueOrDie();
517 switch (GetFormat()) {
518 case FXDIB_Format::k1bppMask: {
519 if ((*pos) & (1 << (7 - x % 8))) {
520 return 0xff000000;
521 }
522 return 0;
523 }
524 case FXDIB_Format::k1bppRgb: {
525 if ((*pos) & (1 << (7 - x % 8))) {
526 return HasPalette() ? GetPaletteSpan()[1] : 0xffffffff;
527 }
528 return HasPalette() ? GetPaletteSpan()[0] : 0xff000000;
529 }
530 case FXDIB_Format::k8bppMask:
531 return (*pos) << 24;
532 case FXDIB_Format::k8bppRgb:
533 return HasPalette() ? GetPaletteSpan()[*pos]
534 : ArgbEncode(0xff, *pos, *pos, *pos);
535 case FXDIB_Format::kRgb:
536 case FXDIB_Format::kRgb32:
537 return FXARGB_GETDIB(pos) | 0xff000000;
538 case FXDIB_Format::kArgb:
539 return FXARGB_GETDIB(pos);
540 default:
541 break;
542 }
543 return 0;
544}
545#endif // defined(PDF_USE_SKIA)
546
547void CFX_DIBitmap::ConvertBGRColorScale(uint32_t forecolor,
548 uint32_t backcolor) {
549 int fr = FXSYS_GetRValue(forecolor);
550 int fg = FXSYS_GetGValue(forecolor);
551 int fb = FXSYS_GetBValue(forecolor);
552 int br = FXSYS_GetRValue(backcolor);
553 int bg = FXSYS_GetGValue(backcolor);
554 int bb = FXSYS_GetBValue(backcolor);
556 if (forecolor == 0 && backcolor == 0xffffff && !HasPalette())
557 return;
558
559 BuildPalette();
560 int size = 1 << GetBppFromFormat(m_Format);
561 for (int i = 0; i < size; ++i) {
562 int gray = FXRGB2GRAY(FXARGB_R(m_palette[i]), FXARGB_G(m_palette[i]),
563 FXARGB_B(m_palette[i]));
564 m_palette[i] =
565 ArgbEncode(0xff, br + (fr - br) * gray / 255,
566 bg + (fg - bg) * gray / 255, bb + (fb - bb) * gray / 255);
567 }
568 return;
569 }
570 if (forecolor == 0 && backcolor == 0xffffff) {
571 for (int row = 0; row < m_Height; ++row) {
572 uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
573 int gap = GetBppFromFormat(m_Format) / 8 - 2;
574 for (int col = 0; col < m_Width; ++col) {
575 int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
576 *scanline++ = gray;
577 *scanline++ = gray;
578 *scanline = gray;
579 scanline += gap;
580 }
581 }
582 return;
583 }
584 for (int row = 0; row < m_Height; ++row) {
585 uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
586 int gap = GetBppFromFormat(m_Format) / 8 - 2;
587 for (int col = 0; col < m_Width; ++col) {
588 int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
589 *scanline++ = bb + (fb - bb) * gray / 255;
590 *scanline++ = bg + (fg - bg) * gray / 255;
591 *scanline = br + (fr - br) * gray / 255;
592 scanline += gap;
593 }
594 }
595}
596
597bool CFX_DIBitmap::ConvertColorScale(uint32_t forecolor, uint32_t backcolor) {
598 if (!m_pBuffer || IsMaskFormat())
599 return false;
600
601 ConvertBGRColorScale(forecolor, backcolor);
602 return true;
603}
604
605// static
606absl::optional<CFX_DIBitmap::PitchAndSize> CFX_DIBitmap::CalculatePitchAndSize(
607 int width,
608 int height,
609 FXDIB_Format format,
610 uint32_t pitch) {
611 if (width <= 0 || height <= 0) {
612 return absl::nullopt;
613 }
614 int bpp = GetBppFromFormat(format);
615 if (!bpp) {
616 return absl::nullopt;
617 }
618 if (pitch == 0) {
619 absl::optional<uint32_t> pitch32 = fxge::CalculatePitch32(bpp, width);
620 if (!pitch32.has_value()) {
621 return absl::nullopt;
622 }
623 pitch = pitch32.value();
624 } else {
625 absl::optional<uint32_t> actual_pitch =
626 fxge::CalculatePitch8(bpp, /*components=*/1, width);
627 if (!actual_pitch.has_value() || pitch < actual_pitch.value()) {
628 return absl::nullopt;
629 }
630 }
631 size_t safe_size = pitch;
632 safe_size *= height;
633 // The final size of the buffer will be (*size + 4). We are trying to not exceed this.
634 if (((std::numeric_limits<std::size_t>::max() - 4) / pitch) < static_cast<uint32_t>(height))
635 return absl::nullopt;
636
637 return PitchAndSize{pitch, safe_size};
638}
639
640bool CFX_DIBitmap::CompositeBitmap(int dest_left,
641 int dest_top,
642 int width,
643 int height,
644 RetainPtr<const CFX_DIBBase> source,
645 int src_left,
646 int src_top,
647 BlendMode blend_type,
648 const CFX_ClipRgn* pClipRgn,
649 bool bRgbByteOrder) {
650 // Should have called CompositeMask().
651 CHECK(!source->IsMaskFormat());
652
653 if (!m_pBuffer)
654 return false;
655
657 return false;
658
659 if (!GetOverlapRect(dest_left, dest_top, width, height, source->GetWidth(),
660 source->GetHeight(), src_left, src_top, pClipRgn)) {
661 return true;
662 }
663
664 RetainPtr<CFX_DIBitmap> pClipMask;
665 FX_RECT clip_box;
666 if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::kRectI) {
667 pClipMask = pClipRgn->GetMask();
668 clip_box = pClipRgn->GetBox();
669 }
670 CFX_ScanlineCompositor compositor;
671 if (!compositor.Init(GetFormat(), source->GetFormat(),
672 source->GetPaletteSpan(), 0, blend_type,
673 pClipMask != nullptr, bRgbByteOrder)) {
674 return false;
675 }
676 const int dest_Bpp = GetBppFromFormat(m_Format) / 8;
677 const int src_Bpp = source->GetBPP() / 8;
678 const bool bRgb = src_Bpp > 1;
679 if (!bRgb && !source->HasPalette()) {
680 return false;
681 }
682
683 for (int row = 0; row < height; row++) {
684 pdfium::span<uint8_t> dest_scan =
685 GetWritableScanline(dest_top + row).subspan(dest_left * dest_Bpp);
686 pdfium::span<const uint8_t> src_scan =
687 source->GetScanline(src_top + row).subspan(src_left * src_Bpp);
688 pdfium::span<const uint8_t> clip_scan;
689 if (pClipMask) {
690 clip_scan = pClipMask->GetWritableScanline(dest_top + row - clip_box.top)
691 .subspan(dest_left - clip_box.left);
692 }
693 if (bRgb) {
694 compositor.CompositeRgbBitmapLine(dest_scan, src_scan, width, clip_scan);
695 } else {
696 compositor.CompositePalBitmapLine(dest_scan, src_scan, src_left, width,
697 clip_scan);
698 }
699 }
700 return true;
701}
702
703bool CFX_DIBitmap::CompositeMask(int dest_left,
704 int dest_top,
705 int width,
706 int height,
707 const RetainPtr<const CFX_DIBBase>& pMask,
708 uint32_t color,
709 int src_left,
710 int src_top,
711 BlendMode blend_type,
712 const CFX_ClipRgn* pClipRgn,
713 bool bRgbByteOrder) {
714 // Should have called CompositeBitmap().
715 CHECK(pMask->IsMaskFormat());
716
717 if (!m_pBuffer)
718 return false;
719
721 return false;
722
723 if (!GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(),
724 pMask->GetHeight(), src_left, src_top, pClipRgn)) {
725 return true;
726 }
727
728 int src_alpha = FXARGB_A(color);
729 if (src_alpha == 0)
730 return true;
731
732 RetainPtr<CFX_DIBitmap> pClipMask;
733 FX_RECT clip_box;
734 if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::kRectI) {
735 pClipMask = pClipRgn->GetMask();
736 clip_box = pClipRgn->GetBox();
737 }
738 int src_bpp = pMask->GetBPP();
739 int Bpp = GetBPP() / 8;
740 CFX_ScanlineCompositor compositor;
741 if (!compositor.Init(GetFormat(), pMask->GetFormat(), {}, color, blend_type,
742 pClipMask != nullptr, bRgbByteOrder)) {
743 return false;
744 }
745 for (int row = 0; row < height; row++) {
746 pdfium::span<uint8_t> dest_scan =
747 GetWritableScanline(dest_top + row).subspan(dest_left * Bpp);
748 pdfium::span<const uint8_t> src_scan = pMask->GetScanline(src_top + row);
749 pdfium::span<const uint8_t> clip_scan;
750 if (pClipMask) {
751 clip_scan = pClipMask->GetScanline(dest_top + row - clip_box.top)
752 .subspan(dest_left - clip_box.left);
753 }
754 if (src_bpp == 1) {
755 compositor.CompositeBitMaskLine(dest_scan, src_scan, src_left, width,
756 clip_scan);
757 } else {
758 compositor.CompositeByteMaskLine(dest_scan, src_scan.subspan(src_left),
759 width, clip_scan);
760 }
761 }
762 return true;
763}
764
765void CFX_DIBitmap::CompositeOneBPPMask(int dest_left,
766 int dest_top,
767 int width,
768 int height,
769 RetainPtr<const CFX_DIBBase> source,
770 int src_left,
771 int src_top) {
772 if (GetBPP() != 1) {
773 return;
774 }
775
776 if (!GetOverlapRect(dest_left, dest_top, width, height, source->GetWidth(),
777 source->GetHeight(), src_left, src_top, nullptr)) {
778 return;
779 }
780
781 for (int row = 0; row < height; ++row) {
782 uint8_t* dest_scan = m_pBuffer.Get() + (dest_top + row) * m_Pitch;
783 const uint8_t* src_scan = source->GetScanline(src_top + row).data();
784 for (int col = 0; col < width; ++col) {
785 int src_idx = src_left + col;
786 int dest_idx = dest_left + col;
787 if (src_scan[src_idx / 8] & (1 << (7 - src_idx % 8))) {
788 dest_scan[dest_idx / 8] |= 1 << (7 - dest_idx % 8);
789 }
790 }
791 }
792}
793
794bool CFX_DIBitmap::CompositeRect(int left,
795 int top,
796 int width,
797 int height,
798 uint32_t color) {
799 if (!m_pBuffer)
800 return false;
801
802 int src_alpha = FXARGB_A(color);
803 if (src_alpha == 0)
804 return true;
805
806 FX_RECT rect(left, top, left + width, top + height);
808 if (rect.IsEmpty())
809 return true;
810
811 width = rect.Width();
812 uint32_t dst_color = color;
813 uint8_t* color_p = reinterpret_cast<uint8_t*>(&dst_color);
815 uint8_t gray = IsMaskFormat() ? 255
816 : (uint8_t)FXRGB2GRAY((int)color_p[2],
817 color_p[1], color_p[0]);
818 for (int row = rect.top; row < rect.bottom; row++) {
819 uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left;
820 if (src_alpha == 255) {
821 memset(dest_scan, gray, width);
822 } else {
823 for (int col = 0; col < width; col++) {
824 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
825 dest_scan++;
826 }
827 }
828 }
829 return true;
830 }
832 int left_shift = rect.left % 8;
833 int right_shift = rect.right % 8;
834 int new_width = rect.right / 8 - rect.left / 8;
835 int index = 0;
836 if (HasPalette()) {
837 for (int i = 0; i < 2; i++) {
838 if (GetPaletteSpan()[i] == color)
839 index = i;
840 }
841 } else {
842 index = (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
843 }
844 for (int row = rect.top; row < rect.bottom; row++) {
845 uint8_t* dest_scan_top =
846 GetWritableScanline(row).subspan(rect.left / 8).data();
847 uint8_t* dest_scan_top_r =
848 GetWritableScanline(row).subspan(rect.right / 8).data();
849 uint8_t left_flag = *dest_scan_top & (255 << (8 - left_shift));
850 uint8_t right_flag = *dest_scan_top_r & (255 >> right_shift);
851 if (new_width) {
852 memset(dest_scan_top + 1, index ? 255 : 0, new_width - 1);
853 if (!index) {
854 *dest_scan_top &= left_flag;
855 *dest_scan_top_r &= right_flag;
856 } else {
857 *dest_scan_top |= ~left_flag;
858 *dest_scan_top_r |= ~right_flag;
859 }
860 } else {
861 if (!index) {
862 *dest_scan_top &= left_flag | right_flag;
863 } else {
864 *dest_scan_top |= ~(left_flag | right_flag);
865 }
866 }
867 }
868 return true;
869 }
870
871 CHECK_GE(GetBppFromFormat(m_Format), 24);
872 color_p[3] = static_cast<uint8_t>(src_alpha);
873 int Bpp = GetBppFromFormat(m_Format) / 8;
874 const bool bAlpha = IsAlphaFormat();
875 if (bAlpha) {
876 // Other formats with alpha have already been handled above.
877 DCHECK_EQ(GetFormat(), FXDIB_Format::kArgb);
878 }
879 if (src_alpha == 255) {
880 for (int row = rect.top; row < rect.bottom; row++) {
881 uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
882 if (Bpp == 4) {
883 uint32_t* scan = reinterpret_cast<uint32_t*>(dest_scan);
884 for (int col = 0; col < width; col++)
885 *scan++ = dst_color;
886 } else {
887 for (int col = 0; col < width; col++) {
888 *dest_scan++ = color_p[0];
889 *dest_scan++ = color_p[1];
890 *dest_scan++ = color_p[2];
891 }
892 }
893 }
894 return true;
895 }
896 for (int row = rect.top; row < rect.bottom; row++) {
897 uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
898 if (bAlpha) {
899 for (int col = 0; col < width; col++) {
900 uint8_t back_alpha = dest_scan[3];
901 if (back_alpha == 0) {
902 FXARGB_SETDIB(dest_scan, ArgbEncode(src_alpha, color_p[2], color_p[1],
903 color_p[0]));
904 dest_scan += 4;
905 continue;
906 }
907 uint8_t dest_alpha =
908 back_alpha + src_alpha - back_alpha * src_alpha / 255;
909 int alpha_ratio = src_alpha * 255 / dest_alpha;
910 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[0], alpha_ratio);
911 dest_scan++;
912 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[1], alpha_ratio);
913 dest_scan++;
914 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[2], alpha_ratio);
915 dest_scan++;
916 *dest_scan++ = dest_alpha;
917 }
918 } else {
919 for (int col = 0; col < width; col++) {
920 for (int comps = 0; comps < Bpp; comps++) {
921 if (comps == 3) {
922 *dest_scan++ = 255;
923 continue;
924 }
925 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], src_alpha);
926 dest_scan++;
927 }
928 }
929 }
930 }
931 return true;
932}
933
934bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
935 DCHECK(dest_format == FXDIB_Format::k8bppMask ||
936 dest_format == FXDIB_Format::kArgb ||
937 dest_format == FXDIB_Format::kRgb32 ||
938 dest_format == FXDIB_Format::kRgb);
939
940 if (dest_format == m_Format)
941 return true;
942
943 if (dest_format == FXDIB_Format::k8bppMask &&
946 return true;
947 }
948 if (dest_format == FXDIB_Format::kArgb && m_Format == FXDIB_Format::kRgb32) {
950 for (int row = 0; row < m_Height; row++) {
951 uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch + 3;
952 for (int col = 0; col < m_Width; col++) {
953 *scanline = 0xff;
954 scanline += 4;
955 }
956 }
957 return true;
958 }
959 int dest_bpp = GetBppFromFormat(dest_format);
960 int dest_pitch = fxge::CalculatePitch32OrDie(dest_bpp, m_Width);
961 const size_t dest_buf_size = dest_pitch * m_Height + 4;
962 std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
963 FX_TryAlloc(uint8_t, dest_buf_size));
964 if (!dest_buf)
965 return false;
966
967 if (dest_format == FXDIB_Format::kArgb) {
968 memset(dest_buf.get(), 0xff, dest_buf_size);
969 }
970 RetainPtr<CFX_DIBBase> holder(this);
971 m_palette =
972 ConvertBuffer(dest_format, {dest_buf.get(), dest_buf_size}, dest_pitch,
973 m_Width, m_Height, holder, /*src_left=*/0, /*src_top=*/0);
974 m_pBuffer = std::move(dest_buf);
975 m_Format = dest_format;
976 m_Pitch = dest_pitch;
977 return true;
978}
ClipType GetType() const
Definition cfx_cliprgn.h:23
const FX_RECT & GetBox() const
Definition cfx_cliprgn.h:24
int FindPalette(uint32_t color) const
static constexpr FXDIB_Format kPlatformRGBFormat
Definition cfx_dibbase.h:39
bool HasPalette() const
Definition cfx_dibbase.h:62
void SetPalette(pdfium::span< const uint32_t > src_palette)
uint32_t m_Pitch
FXDIB_Format GetFormat() const
Definition cfx_dibbase.h:56
int GetBPP() const
Definition cfx_dibbase.h:57
bool GetOverlapRect(int &dest_left, int &dest_top, int &width, int &height, int src_width, int src_height, int &src_left, int &src_top, const CFX_ClipRgn *pClipRgn) const
FXDIB_Format m_Format
void BuildPalette()
bool IsAlphaFormat() const
Definition cfx_dibbase.h:59
bool IsOpaqueImage() const
Definition cfx_dibbase.h:60
uint32_t GetPitch() const
Definition cfx_dibbase.h:54
int GetHeight() const
Definition cfx_dibbase.h:53
bool IsMaskFormat() const
Definition cfx_dibbase.h:58
bool TransferBitmap(int dest_left, int dest_top, int width, int height, RetainPtr< const CFX_DIBBase > source, int src_left, int src_top)
bool SetAlphaFromBitmap(RetainPtr< const CFX_DIBBase > source)
bool SetUniformOpaqueAlpha()
bool Create(int width, int height, FXDIB_Format format)
pdfium::span< const uint8_t > GetBuffer() const
bool CompositeMask(int dest_left, int dest_top, int width, int height, const RetainPtr< const CFX_DIBBase > &pMask, uint32_t color, int src_left, int src_top, BlendMode blend_type, const CFX_ClipRgn *pClipRgn, bool bRgbByteOrder)
bool SetRedFromBitmap(RetainPtr< const CFX_DIBBase > source)
bool MultiplyAlphaMask(RetainPtr< const CFX_DIBBase > source)
bool CompositeBitmap(int dest_left, int dest_top, int width, int height, RetainPtr< const CFX_DIBBase > source, int src_left, int src_top, BlendMode blend_type, const CFX_ClipRgn *pClipRgn, bool bRgbByteOrder)
bool ConvertColorScale(uint32_t forecolor, uint32_t backcolor)
bool ConvertFormat(FXDIB_Format format)
bool CompositeRect(int dest_left, int dest_top, int width, int height, uint32_t color)
pdfium::span< const uint8_t > GetScanline(int line) const override
size_t GetEstimatedImageMemoryBurden() const override
bool MultiplyAlpha(float alpha)
bool Create(int width, int height, FXDIB_Format format, uint8_t *pBuffer, uint32_t pitch)
void TakeOver(RetainPtr< CFX_DIBitmap > &&pSrcBitmap)
void Clear(uint32_t color)
bool Copy(RetainPtr< const CFX_DIBBase > source)
void CompositeOneBPPMask(int dest_left, int dest_top, int width, int height, RetainPtr< const CFX_DIBBase > source, int src_left, int src_top)
~CFX_DIBitmap() override
void CompositeByteMaskLine(pdfium::span< uint8_t > dest_scan, pdfium::span< const uint8_t > src_scan, int width, pdfium::span< const uint8_t > clip_scan) const
void CompositePalBitmapLine(pdfium::span< uint8_t > dest_scan, pdfium::span< const uint8_t > src_scan, int src_left, int width, pdfium::span< const uint8_t > clip_scan) const
bool Init(FXDIB_Format dest_format, FXDIB_Format src_format, pdfium::span< const uint32_t > src_palette, uint32_t mask_color, BlendMode blend_type, bool bClip, bool bRgbByteOrder)
void CompositeRgbBitmapLine(pdfium::span< uint8_t > dest_scan, pdfium::span< const uint8_t > src_scan, int width, pdfium::span< const uint8_t > clip_scan) const
void CompositeBitMaskLine(pdfium::span< uint8_t > dest_scan, pdfium::span< const uint8_t > src_scan, int src_left, int width, pdfium::span< const uint8_t > clip_scan) const
BlendMode
Definition fx_dib.h:49
#define FXRGB2GRAY(r, g, b)
Definition fx_dib.h:131
#define FXARGB_B(argb)
Definition fx_dib.h:127
#define FXARGB_G(argb)
Definition fx_dib.h:126
#define FXARGB_A(argb)
Definition fx_dib.h:124
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
Definition fx_dib.h:118
#define FXARGB_SETDIB(p, argb)
Definition fx_dib.h:137
int GetBppFromFormat(FXDIB_Format format)
Definition fx_dib.h:90
#define FXARGB_R(argb)
Definition fx_dib.h:125
constexpr uint8_t FXSYS_GetRValue(uint32_t bgr)
Definition fx_dib.h:73
FXDIB_Format
Definition fx_dib.h:19
constexpr uint8_t FXSYS_GetGValue(uint32_t bgr)
Definition fx_dib.h:77
#define FXDIB_ALPHA_MERGE(backdrop, source, source_alpha)
Definition fx_dib.h:132
constexpr uint8_t FXSYS_GetBValue(uint32_t bgr)
Definition fx_dib.h:81
uint32_t CalculatePitch32OrDie(int bpp, int width)
#define CHECK(cvref)
FX_RECT & operator=(const FX_RECT &that)=default
int32_t bottom
int32_t right
int Width() const
void Intersect(int l, int t, int r, int b)
int32_t top
int32_t left
bool IsEmpty() const
constexpr FX_RECT(int l, int t, int r, int b)