1 // Copyright 2017 PDFium Authors. All rights reserved.
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 <limits>
10 #include <memory>
11 #include <utility>
12
13 #include "build/build_config.h"
14 #include "core/fxge/cfx_cliprgn.h"
15 #include "core/fxge/dib/cfx_cmyk_to_srgb.h"
16 #include "core/fxge/dib/cfx_scanlinecompositor.h"
17
18 namespace {
19
20 constexpr size_t kMaxOOMLimit = 12000000;
21 constexpr int8_t kChannelOffset[] = {0, 2, 1, 0, 0, 1, 2, 3, 3};
22
23 } // namespace
24
CFX_DIBitmap()25 CFX_DIBitmap::CFX_DIBitmap() {
26 m_pPalette = nullptr;
27 #ifdef _SKIA_SUPPORT_PATHS_
28 m_nFormat = Format::kCleared;
29 #endif
30 }
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_bpp = GetBppFromFormat(format);
43 m_AlphaFlag = GetAlphaFlagFromFormat(format);
44 m_Width = 0;
45 m_Height = 0;
46 m_Pitch = 0;
47
48 uint32_t calculatedSize;
49 if (!CalculatePitchAndSize(height, width, format, &pitch, &calculatedSize))
50 return false;
51
52 if (pBuffer) {
53 m_pBuffer.Reset(pBuffer);
54 } else {
55 size_t bufferSize = calculatedSize + 4;
56 if (bufferSize >= kMaxOOMLimit) {
57 m_pBuffer = std::unique_ptr<uint8_t, FxFreeDeleter>(
58 FX_TryAlloc(uint8_t, bufferSize));
59 if (!m_pBuffer)
60 return false;
61 } else {
62 m_pBuffer = std::unique_ptr<uint8_t, FxFreeDeleter>(
63 FX_Alloc(uint8_t, bufferSize));
64 }
65 }
66 m_Width = width;
67 m_Height = height;
68 m_Pitch = pitch;
69 if (!HasAlpha() || format == FXDIB_Argb)
70 return true;
71
72 if (BuildAlphaMask())
73 return true;
74
75 if (pBuffer)
76 return true;
77
78 m_pBuffer = nullptr;
79 m_Width = 0;
80 m_Height = 0;
81 m_Pitch = 0;
82 return false;
83 }
84
Copy(const RetainPtr<CFX_DIBBase> & pSrc)85 bool CFX_DIBitmap::Copy(const RetainPtr<CFX_DIBBase>& pSrc) {
86 if (m_pBuffer)
87 return false;
88
89 if (!Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat()))
90 return false;
91
92 SetPalette(pSrc->GetPalette());
93 SetAlphaMask(pSrc->m_pAlphaMask, nullptr);
94 for (int row = 0; row < pSrc->GetHeight(); row++)
95 memcpy(m_pBuffer.Get() + row * m_Pitch, pSrc->GetScanline(row), m_Pitch);
96 return true;
97 }
98
~CFX_DIBitmap()99 CFX_DIBitmap::~CFX_DIBitmap() {}
100
GetBuffer() const101 uint8_t* CFX_DIBitmap::GetBuffer() const {
102 return m_pBuffer.Get();
103 }
104
GetScanline(int line) const105 const uint8_t* CFX_DIBitmap::GetScanline(int line) const {
106 return m_pBuffer.Get() ? m_pBuffer.Get() + line * m_Pitch : nullptr;
107 }
108
TakeOver(RetainPtr<CFX_DIBitmap> && pSrcBitmap)109 void CFX_DIBitmap::TakeOver(RetainPtr<CFX_DIBitmap>&& pSrcBitmap) {
110 m_pBuffer = std::move(pSrcBitmap->m_pBuffer);
111 m_pPalette = std::move(pSrcBitmap->m_pPalette);
112 m_pAlphaMask = pSrcBitmap->m_pAlphaMask;
113 pSrcBitmap->m_pBuffer = nullptr;
114 pSrcBitmap->m_pAlphaMask = nullptr;
115 m_bpp = pSrcBitmap->m_bpp;
116 m_AlphaFlag = pSrcBitmap->m_AlphaFlag;
117 m_Width = pSrcBitmap->m_Width;
118 m_Height = pSrcBitmap->m_Height;
119 m_Pitch = pSrcBitmap->m_Pitch;
120 }
121
Clear(uint32_t color)122 void CFX_DIBitmap::Clear(uint32_t color) {
123 if (!m_pBuffer)
124 return;
125
126 uint8_t* pBuffer = m_pBuffer.Get();
127 switch (GetFormat()) {
128 case FXDIB_1bppMask:
129 memset(pBuffer, (color & 0xff000000) ? 0xff : 0, m_Pitch * m_Height);
130 break;
131 case FXDIB_1bppRgb: {
132 int index = FindPalette(color);
133 memset(pBuffer, index ? 0xff : 0, m_Pitch * m_Height);
134 break;
135 }
136 case FXDIB_8bppMask:
137 memset(pBuffer, color >> 24, m_Pitch * m_Height);
138 break;
139 case FXDIB_8bppRgb: {
140 int index = FindPalette(color);
141 memset(pBuffer, index, m_Pitch * m_Height);
142 break;
143 }
144 case FXDIB_Rgb:
145 case FXDIB_Rgba: {
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_Rgb32:
167 case FXDIB_Argb: {
168 color = IsCmykImage() ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
169 #ifdef _SKIA_SUPPORT_
170 if (FXDIB_Rgb32 == GetFormat() && !IsCmykImage())
171 color |= 0xFF000000;
172 #endif
173 for (int i = 0; i < m_Width; i++)
174 reinterpret_cast<uint32_t*>(pBuffer)[i] = color;
175 for (int row = 1; row < m_Height; row++)
176 memcpy(pBuffer + row * m_Pitch, pBuffer, m_Pitch);
177 break;
178 }
179 default:
180 break;
181 }
182 }
183
TransferBitmap(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)184 bool CFX_DIBitmap::TransferBitmap(int dest_left,
185 int dest_top,
186 int width,
187 int height,
188 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
189 int src_left,
190 int src_top) {
191 if (!m_pBuffer)
192 return false;
193
194 if (!GetOverlapRect(dest_left, dest_top, width, height,
195 pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left,
196 src_top, nullptr)) {
197 return true;
198 }
199
200 FXDIB_Format dest_format = GetFormat();
201 FXDIB_Format src_format = pSrcBitmap->GetFormat();
202 if (dest_format != src_format) {
203 return TransferWithUnequalFormats(dest_format, dest_left, dest_top, width,
204 height, pSrcBitmap, src_left, src_top);
205 }
206
207 if (GetBPP() != 1) {
208 TransferWithMultipleBPP(dest_left, dest_top, width, height, pSrcBitmap,
209 src_left, src_top);
210 return true;
211 }
212
213 TransferEqualFormatsOneBPP(dest_left, dest_top, width, height, pSrcBitmap,
214 src_left, src_top);
215 return true;
216 }
217
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)218 bool CFX_DIBitmap::TransferWithUnequalFormats(
219 FXDIB_Format dest_format,
220 int dest_left,
221 int dest_top,
222 int width,
223 int height,
224 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
225 int src_left,
226 int src_top) {
227 if (m_pPalette)
228 return false;
229
230 if (m_bpp == 8)
231 dest_format = FXDIB_8bppMask;
232
233 uint8_t* dest_buf =
234 m_pBuffer.Get() + dest_top * m_Pitch + dest_left * GetBPP() / 8;
235 std::unique_ptr<uint32_t, FxFreeDeleter> d_plt;
236 if (!ConvertBuffer(dest_format, dest_buf, m_Pitch, width, height, pSrcBitmap,
237 src_left, src_top, &d_plt)) {
238 return false;
239 }
240 return true;
241 }
242
TransferWithMultipleBPP(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)243 void CFX_DIBitmap::TransferWithMultipleBPP(
244 int dest_left,
245 int dest_top,
246 int width,
247 int height,
248 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
249 int src_left,
250 int src_top) {
251 int Bpp = GetBPP() / 8;
252 for (int row = 0; row < height; ++row) {
253 uint8_t* dest_scan =
254 m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * Bpp;
255 const uint8_t* src_scan =
256 pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
257 memcpy(dest_scan, src_scan, width * Bpp);
258 }
259 }
260
TransferEqualFormatsOneBPP(int dest_left,int dest_top,int width,int height,const RetainPtr<CFX_DIBBase> & pSrcBitmap,int src_left,int src_top)261 void CFX_DIBitmap::TransferEqualFormatsOneBPP(
262 int dest_left,
263 int dest_top,
264 int width,
265 int height,
266 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
267 int src_left,
268 int src_top) {
269 for (int row = 0; row < height; ++row) {
270 uint8_t* dest_scan = m_pBuffer.Get() + (dest_top + row) * m_Pitch;
271 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
272 for (int col = 0; col < width; ++col) {
273 int src_idx = src_left + col;
274 int dest_idx = dest_left + col;
275 if (src_scan[(src_idx) / 8] & (1 << (7 - (src_idx) % 8)))
276 dest_scan[(dest_idx) / 8] |= 1 << (7 - (dest_idx) % 8);
277 else
278 dest_scan[(dest_idx) / 8] &= ~(1 << (7 - (dest_idx) % 8));
279 }
280 }
281 }
282
LoadChannelFromAlpha(FXDIB_Channel destChannel,const RetainPtr<CFX_DIBBase> & pSrcBitmap)283 bool CFX_DIBitmap::LoadChannelFromAlpha(
284 FXDIB_Channel destChannel,
285 const RetainPtr<CFX_DIBBase>& pSrcBitmap) {
286 if (!m_pBuffer)
287 return false;
288
289 RetainPtr<CFX_DIBBase> pSrcClone = pSrcBitmap;
290 if (!pSrcBitmap->HasAlpha() && !pSrcBitmap->IsAlphaMask())
291 return false;
292
293 if (pSrcBitmap->GetBPP() == 1) {
294 pSrcClone = pSrcBitmap->CloneConvert(FXDIB_8bppMask);
295 if (!pSrcClone)
296 return false;
297 }
298 int srcOffset = pSrcBitmap->GetFormat() == FXDIB_Argb ? 3 : 0;
299 int destOffset = 0;
300 if (destChannel == FXDIB_Alpha) {
301 if (IsAlphaMask()) {
302 if (!ConvertFormat(FXDIB_8bppMask))
303 return false;
304 } else {
305 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb))
306 return false;
307
308 if (GetFormat() == FXDIB_Argb)
309 destOffset = 3;
310 }
311 } else {
312 if (IsAlphaMask())
313 return false;
314
315 if (GetBPP() < 24) {
316 if (HasAlpha()) {
317 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb))
318 return false;
319 } else {
320 #if defined(OS_MACOSX)
321 constexpr FXDIB_Format kPlatformFormat = FXDIB_Rgb32;
322 #else
323 constexpr FXDIB_Format kPlatformFormat = FXDIB_Rgb;
324 #endif
325 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : kPlatformFormat))
326 return false;
327 }
328 }
329 destOffset = kChannelOffset[destChannel];
330 }
331 if (pSrcClone->m_pAlphaMask) {
332 RetainPtr<CFX_DIBBase> pAlphaMask = pSrcClone->m_pAlphaMask;
333 if (pSrcClone->GetWidth() != m_Width ||
334 pSrcClone->GetHeight() != m_Height) {
335 if (pAlphaMask) {
336 pAlphaMask = pAlphaMask->StretchTo(m_Width, m_Height,
337 FXDIB_ResampleOptions(), nullptr);
338 if (!pAlphaMask)
339 return false;
340 }
341 }
342 pSrcClone = std::move(pAlphaMask);
343 srcOffset = 0;
344 } else if (pSrcClone->GetWidth() != m_Width ||
345 pSrcClone->GetHeight() != m_Height) {
346 RetainPtr<CFX_DIBitmap> pSrcMatched = pSrcClone->StretchTo(
347 m_Width, m_Height, FXDIB_ResampleOptions(), nullptr);
348 if (!pSrcMatched)
349 return false;
350
351 pSrcClone = pSrcMatched;
352 }
353 RetainPtr<CFX_DIBitmap> pDst(this);
354 if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
355 pDst = m_pAlphaMask;
356 destOffset = 0;
357 }
358 int srcBytes = pSrcClone->GetBPP() / 8;
359 int destBytes = pDst->GetBPP() / 8;
360 for (int row = 0; row < m_Height; row++) {
361 uint8_t* dest_pos = pDst->GetWritableScanline(row) + destOffset;
362 const uint8_t* src_pos = pSrcClone->GetScanline(row) + srcOffset;
363 for (int col = 0; col < m_Width; col++) {
364 *dest_pos = *src_pos;
365 dest_pos += destBytes;
366 src_pos += srcBytes;
367 }
368 }
369 return true;
370 }
371
LoadChannel(FXDIB_Channel destChannel,int value)372 bool CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel, int value) {
373 if (!m_pBuffer)
374 return false;
375
376 int destOffset;
377 if (destChannel == FXDIB_Alpha) {
378 if (IsAlphaMask()) {
379 if (!ConvertFormat(FXDIB_8bppMask)) {
380 return false;
381 }
382 destOffset = 0;
383 } else {
384 destOffset = 0;
385 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
386 return false;
387 }
388 if (GetFormat() == FXDIB_Argb) {
389 destOffset = 3;
390 }
391 }
392 } else {
393 if (IsAlphaMask()) {
394 return false;
395 }
396 if (GetBPP() < 24) {
397 if (HasAlpha()) {
398 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
399 return false;
400 }
401 } else {
402 #if defined(OS_MACOSX)
403 constexpr FXDIB_Format kPlatformFormat = FXDIB_Rgb;
404 #else
405 constexpr FXDIB_Format kPlatformFormat = FXDIB_Rgb32;
406 #endif
407 if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : kPlatformFormat))
408 return false;
409 }
410 }
411 destOffset = kChannelOffset[destChannel];
412 }
413 int Bpp = GetBPP() / 8;
414 if (Bpp == 1) {
415 memset(m_pBuffer.Get(), value, m_Height * m_Pitch);
416 return true;
417 }
418 if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
419 memset(m_pAlphaMask->GetBuffer(), value,
420 m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch());
421 return true;
422 }
423 for (int row = 0; row < m_Height; row++) {
424 uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + destOffset;
425 for (int col = 0; col < m_Width; col++) {
426 *scan_line = value;
427 scan_line += Bpp;
428 }
429 }
430 return true;
431 }
432
MultiplyAlpha(const RetainPtr<CFX_DIBBase> & pSrcBitmap)433 bool CFX_DIBitmap::MultiplyAlpha(const RetainPtr<CFX_DIBBase>& pSrcBitmap) {
434 if (!m_pBuffer)
435 return false;
436
437 if (!pSrcBitmap->IsAlphaMask()) {
438 NOTREACHED();
439 return false;
440 }
441
442 if (!IsAlphaMask() && !HasAlpha())
443 return LoadChannelFromAlpha(FXDIB_Alpha, pSrcBitmap);
444
445 RetainPtr<CFX_DIBitmap> pSrcClone = pSrcBitmap.As<CFX_DIBitmap>();
446 if (pSrcBitmap->GetWidth() != m_Width ||
447 pSrcBitmap->GetHeight() != m_Height) {
448 pSrcClone = pSrcBitmap->StretchTo(m_Width, m_Height,
449 FXDIB_ResampleOptions(), nullptr);
450 if (!pSrcClone)
451 return false;
452 }
453 if (IsAlphaMask()) {
454 if (!ConvertFormat(FXDIB_8bppMask))
455 return false;
456
457 for (int row = 0; row < m_Height; row++) {
458 uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row;
459 uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
460 if (pSrcClone->GetBPP() == 1) {
461 for (int col = 0; col < m_Width; col++) {
462 if (!((1 << (7 - col % 8)) & src_scan[col / 8]))
463 dest_scan[col] = 0;
464 }
465 } else {
466 for (int col = 0; col < m_Width; col++) {
467 *dest_scan = (*dest_scan) * src_scan[col] / 255;
468 dest_scan++;
469 }
470 }
471 }
472 } else {
473 if (GetFormat() == FXDIB_Argb) {
474 if (pSrcClone->GetBPP() == 1)
475 return false;
476
477 for (int row = 0; row < m_Height; row++) {
478 uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row + 3;
479 uint8_t* src_scan =
480 pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
481 for (int col = 0; col < m_Width; col++) {
482 *dest_scan = (*dest_scan) * src_scan[col] / 255;
483 dest_scan += 4;
484 }
485 }
486 } else {
487 m_pAlphaMask->MultiplyAlpha(pSrcClone);
488 }
489 }
490 return true;
491 }
492
MultiplyAlpha(int alpha)493 bool CFX_DIBitmap::MultiplyAlpha(int alpha) {
494 if (!m_pBuffer)
495 return false;
496
497 switch (GetFormat()) {
498 case FXDIB_1bppMask:
499 if (!ConvertFormat(FXDIB_8bppMask)) {
500 return false;
501 }
502 MultiplyAlpha(alpha);
503 break;
504 case FXDIB_8bppMask: {
505 for (int row = 0; row < m_Height; row++) {
506 uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch;
507 for (int col = 0; col < m_Width; col++) {
508 scan_line[col] = scan_line[col] * alpha / 255;
509 }
510 }
511 break;
512 }
513 case FXDIB_Argb: {
514 for (int row = 0; row < m_Height; row++) {
515 uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + 3;
516 for (int col = 0; col < m_Width; col++) {
517 *scan_line = (*scan_line) * alpha / 255;
518 scan_line += 4;
519 }
520 }
521 break;
522 }
523 default:
524 if (HasAlpha()) {
525 m_pAlphaMask->MultiplyAlpha(alpha);
526 } else if (IsCmykImage()) {
527 if (!ConvertFormat((FXDIB_Format)(GetFormat() | 0x0200))) {
528 return false;
529 }
530 m_pAlphaMask->MultiplyAlpha(alpha);
531 } else {
532 if (!ConvertFormat(FXDIB_Argb)) {
533 return false;
534 }
535 MultiplyAlpha(alpha);
536 }
537 break;
538 }
539 return true;
540 }
541
GetPixel(int x,int y) const542 uint32_t CFX_DIBitmap::GetPixel(int x, int y) const {
543 if (!m_pBuffer)
544 return 0;
545
546 uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + x * GetBPP() / 8;
547 switch (GetFormat()) {
548 case FXDIB_1bppMask: {
549 if ((*pos) & (1 << (7 - x % 8))) {
550 return 0xff000000;
551 }
552 return 0;
553 }
554 case FXDIB_1bppRgb: {
555 if ((*pos) & (1 << (7 - x % 8))) {
556 return m_pPalette ? m_pPalette.get()[1] : 0xffffffff;
557 }
558 return m_pPalette ? m_pPalette.get()[0] : 0xff000000;
559 }
560 case FXDIB_8bppMask:
561 return (*pos) << 24;
562 case FXDIB_8bppRgb:
563 return m_pPalette ? m_pPalette.get()[*pos]
564 : (0xff000000 | ((*pos) * 0x10101));
565 case FXDIB_Rgb:
566 case FXDIB_Rgba:
567 case FXDIB_Rgb32:
568 return FXARGB_GETDIB(pos) | 0xff000000;
569 case FXDIB_Argb:
570 return FXARGB_GETDIB(pos);
571 default:
572 break;
573 }
574 return 0;
575 }
576
SetPixel(int x,int y,uint32_t color)577 void CFX_DIBitmap::SetPixel(int x, int y, uint32_t color) {
578 if (!m_pBuffer)
579 return;
580
581 if (x < 0 || x >= m_Width || y < 0 || y >= m_Height)
582 return;
583
584 uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + x * GetBPP() / 8;
585 switch (GetFormat()) {
586 case FXDIB_1bppMask:
587 if (color >> 24) {
588 *pos |= 1 << (7 - x % 8);
589 } else {
590 *pos &= ~(1 << (7 - x % 8));
591 }
592 break;
593 case FXDIB_1bppRgb:
594 if (m_pPalette) {
595 if (color == m_pPalette.get()[1]) {
596 *pos |= 1 << (7 - x % 8);
597 } else {
598 *pos &= ~(1 << (7 - x % 8));
599 }
600 } else {
601 if (color == 0xffffffff) {
602 *pos |= 1 << (7 - x % 8);
603 } else {
604 *pos &= ~(1 << (7 - x % 8));
605 }
606 }
607 break;
608 case FXDIB_8bppMask:
609 *pos = (uint8_t)(color >> 24);
610 break;
611 case FXDIB_8bppRgb: {
612 if (m_pPalette) {
613 for (int i = 0; i < 256; i++) {
614 if (m_pPalette.get()[i] == color) {
615 *pos = (uint8_t)i;
616 return;
617 }
618 }
619 *pos = 0;
620 } else {
621 *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
622 }
623 break;
624 }
625 case FXDIB_Rgb:
626 case FXDIB_Rgb32: {
627 int alpha = FXARGB_A(color);
628 pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255;
629 pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255;
630 pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255;
631 break;
632 }
633 case FXDIB_Rgba: {
634 pos[0] = FXARGB_B(color);
635 pos[1] = FXARGB_G(color);
636 pos[2] = FXARGB_R(color);
637 break;
638 }
639 case FXDIB_Argb:
640 FXARGB_SETDIB(pos, color);
641 break;
642 default:
643 break;
644 }
645 }
646
DownSampleScanline(int line,uint8_t * dest_scan,int dest_bpp,int dest_width,bool bFlipX,int clip_left,int clip_width) const647 void CFX_DIBitmap::DownSampleScanline(int line,
648 uint8_t* dest_scan,
649 int dest_bpp,
650 int dest_width,
651 bool bFlipX,
652 int clip_left,
653 int clip_width) const {
654 if (!m_pBuffer)
655 return;
656
657 int src_Bpp = m_bpp / 8;
658 uint8_t* scanline = m_pBuffer.Get() + line * m_Pitch;
659 if (src_Bpp == 0) {
660 for (int i = 0; i < clip_width; i++) {
661 uint32_t dest_x = clip_left + i;
662 uint32_t src_x = dest_x * m_Width / dest_width;
663 if (bFlipX) {
664 src_x = m_Width - src_x - 1;
665 }
666 src_x %= m_Width;
667 dest_scan[i] = (scanline[src_x / 8] & (1 << (7 - src_x % 8))) ? 255 : 0;
668 }
669 } else if (src_Bpp == 1) {
670 for (int i = 0; i < clip_width; i++) {
671 uint32_t dest_x = clip_left + i;
672 uint32_t src_x = dest_x * m_Width / dest_width;
673 if (bFlipX) {
674 src_x = m_Width - src_x - 1;
675 }
676 src_x %= m_Width;
677 int dest_pos = i;
678 if (m_pPalette) {
679 if (!IsCmykImage()) {
680 dest_pos *= 3;
681 FX_ARGB argb = m_pPalette.get()[scanline[src_x]];
682 dest_scan[dest_pos] = FXARGB_B(argb);
683 dest_scan[dest_pos + 1] = FXARGB_G(argb);
684 dest_scan[dest_pos + 2] = FXARGB_R(argb);
685 } else {
686 dest_pos *= 4;
687 FX_CMYK cmyk = m_pPalette.get()[scanline[src_x]];
688 dest_scan[dest_pos] = FXSYS_GetCValue(cmyk);
689 dest_scan[dest_pos + 1] = FXSYS_GetMValue(cmyk);
690 dest_scan[dest_pos + 2] = FXSYS_GetYValue(cmyk);
691 dest_scan[dest_pos + 3] = FXSYS_GetKValue(cmyk);
692 }
693 } else {
694 dest_scan[dest_pos] = scanline[src_x];
695 }
696 }
697 } else {
698 for (int i = 0; i < clip_width; i++) {
699 uint32_t dest_x = clip_left + i;
700 uint32_t src_x =
701 bFlipX ? (m_Width - dest_x * m_Width / dest_width - 1) * src_Bpp
702 : (dest_x * m_Width / dest_width) * src_Bpp;
703 src_x %= m_Width * src_Bpp;
704 int dest_pos = i * src_Bpp;
705 for (int b = 0; b < src_Bpp; b++) {
706 dest_scan[dest_pos + b] = scanline[src_x + b];
707 }
708 }
709 }
710 }
711
ConvertBGRColorScale(uint32_t forecolor,uint32_t backcolor)712 void CFX_DIBitmap::ConvertBGRColorScale(uint32_t forecolor,
713 uint32_t backcolor) {
714 int fr = FXSYS_GetRValue(forecolor);
715 int fg = FXSYS_GetGValue(forecolor);
716 int fb = FXSYS_GetBValue(forecolor);
717 int br = FXSYS_GetRValue(backcolor);
718 int bg = FXSYS_GetGValue(backcolor);
719 int bb = FXSYS_GetBValue(backcolor);
720 if (m_bpp <= 8) {
721 if (forecolor == 0 && backcolor == 0xffffff && !m_pPalette)
722 return;
723 if (!m_pPalette)
724 BuildPalette();
725 int size = 1 << m_bpp;
726 for (int i = 0; i < size; ++i) {
727 int gray = FXRGB2GRAY(FXARGB_R(m_pPalette.get()[i]),
728 FXARGB_G(m_pPalette.get()[i]),
729 FXARGB_B(m_pPalette.get()[i]));
730 m_pPalette.get()[i] =
731 ArgbEncode(0xff, br + (fr - br) * gray / 255,
732 bg + (fg - bg) * gray / 255, bb + (fb - bb) * gray / 255);
733 }
734 return;
735 }
736 if (forecolor == 0 && backcolor == 0xffffff) {
737 for (int row = 0; row < m_Height; ++row) {
738 uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
739 int gap = m_bpp / 8 - 2;
740 for (int col = 0; col < m_Width; ++col) {
741 int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
742 *scanline++ = gray;
743 *scanline++ = gray;
744 *scanline = gray;
745 scanline += gap;
746 }
747 }
748 return;
749 }
750 for (int row = 0; row < m_Height; ++row) {
751 uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
752 int gap = m_bpp / 8 - 2;
753 for (int col = 0; col < m_Width; ++col) {
754 int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
755 *scanline++ = bb + (fb - bb) * gray / 255;
756 *scanline++ = bg + (fg - bg) * gray / 255;
757 *scanline = br + (fr - br) * gray / 255;
758 scanline += gap;
759 }
760 }
761 }
762
ConvertCMYKColorScale(uint32_t forecolor,uint32_t backcolor)763 void CFX_DIBitmap::ConvertCMYKColorScale(uint32_t forecolor,
764 uint32_t backcolor) {
765 int fc = FXSYS_GetCValue(forecolor);
766 int fm = FXSYS_GetMValue(forecolor);
767 int fy = FXSYS_GetYValue(forecolor);
768 int fk = FXSYS_GetKValue(forecolor);
769 int bc = FXSYS_GetCValue(backcolor);
770 int bm = FXSYS_GetMValue(backcolor);
771 int by = FXSYS_GetYValue(backcolor);
772 int bk = FXSYS_GetKValue(backcolor);
773 if (m_bpp <= 8) {
774 if (forecolor == 0xff && backcolor == 0 && !m_pPalette)
775 return;
776 if (!m_pPalette)
777 BuildPalette();
778 int size = 1 << m_bpp;
779 for (int i = 0; i < size; ++i) {
780 uint8_t r;
781 uint8_t g;
782 uint8_t b;
783 std::tie(r, g, b) =
784 AdobeCMYK_to_sRGB1(FXSYS_GetCValue(m_pPalette.get()[i]),
785 FXSYS_GetMValue(m_pPalette.get()[i]),
786 FXSYS_GetYValue(m_pPalette.get()[i]),
787 FXSYS_GetKValue(m_pPalette.get()[i]));
788 int gray = 255 - FXRGB2GRAY(r, g, b);
789 m_pPalette.get()[i] =
790 CmykEncode(bc + (fc - bc) * gray / 255, bm + (fm - bm) * gray / 255,
791 by + (fy - by) * gray / 255, bk + (fk - bk) * gray / 255);
792 }
793 return;
794 }
795 if (forecolor == 0xff && backcolor == 0x00) {
796 for (int row = 0; row < m_Height; ++row) {
797 uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
798 for (int col = 0; col < m_Width; ++col) {
799 uint8_t r;
800 uint8_t g;
801 uint8_t b;
802 std::tie(r, g, b) = AdobeCMYK_to_sRGB1(scanline[0], scanline[1],
803 scanline[2], scanline[3]);
804 *scanline++ = 0;
805 *scanline++ = 0;
806 *scanline++ = 0;
807 *scanline++ = 255 - FXRGB2GRAY(r, g, b);
808 }
809 }
810 return;
811 }
812 for (int row = 0; row < m_Height; ++row) {
813 uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
814 for (int col = 0; col < m_Width; ++col) {
815 uint8_t r;
816 uint8_t g;
817 uint8_t b;
818 std::tie(r, g, b) = AdobeCMYK_to_sRGB1(scanline[0], scanline[1],
819 scanline[2], scanline[3]);
820 int gray = 255 - FXRGB2GRAY(r, g, b);
821 *scanline++ = bc + (fc - bc) * gray / 255;
822 *scanline++ = bm + (fm - bm) * gray / 255;
823 *scanline++ = by + (fy - by) * gray / 255;
824 *scanline++ = bk + (fk - bk) * gray / 255;
825 }
826 }
827 }
828
ConvertColorScale(uint32_t forecolor,uint32_t backcolor)829 bool CFX_DIBitmap::ConvertColorScale(uint32_t forecolor, uint32_t backcolor) {
830 if (!m_pBuffer || IsAlphaMask())
831 return false;
832
833 if (IsCmykImage())
834 ConvertCMYKColorScale(forecolor, backcolor);
835 else
836 ConvertBGRColorScale(forecolor, backcolor);
837 return true;
838 }
839
840 // static
CalculatePitchAndSize(int height,int width,FXDIB_Format format,uint32_t * pitch,uint32_t * size)841 bool CFX_DIBitmap::CalculatePitchAndSize(int height,
842 int width,
843 FXDIB_Format format,
844 uint32_t* pitch,
845 uint32_t* size) {
846 if (width <= 0 || height <= 0)
847 return false;
848
849 int bpp = GetBppFromFormat(format);
850 if (!bpp)
851 return false;
852
853 if ((INT_MAX - 31) / width < bpp)
854 return false;
855
856 if (!*pitch)
857 *pitch = static_cast<uint32_t>((width * bpp + 31) / 32 * 4);
858
859 if ((1 << 30) / *pitch < static_cast<uint32_t>(height))
860 return false;
861
862 *size = *pitch * static_cast<uint32_t>(height);
863 return true;
864 }
865
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)866 bool CFX_DIBitmap::CompositeBitmap(int dest_left,
867 int dest_top,
868 int width,
869 int height,
870 const RetainPtr<CFX_DIBBase>& pSrcBitmap,
871 int src_left,
872 int src_top,
873 BlendMode blend_type,
874 const CFX_ClipRgn* pClipRgn,
875 bool bRgbByteOrder) {
876 if (!m_pBuffer)
877 return false;
878
879 if (pSrcBitmap->IsAlphaMask() || m_bpp < 8) {
880 NOTREACHED();
881 return false;
882 }
883
884 if (!GetOverlapRect(dest_left, dest_top, width, height,
885 pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(), src_left,
886 src_top, pClipRgn)) {
887 return true;
888 }
889
890 RetainPtr<CFX_DIBitmap> pClipMask;
891 FX_RECT clip_box;
892 if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
893 ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF);
894 pClipMask = pClipRgn->GetMask();
895 clip_box = pClipRgn->GetBox();
896 }
897 CFX_ScanlineCompositor compositor;
898 if (!compositor.Init(GetFormat(), pSrcBitmap->GetFormat(), width,
899 pSrcBitmap->GetPalette(), 0, blend_type,
900 pClipMask != nullptr, bRgbByteOrder)) {
901 return false;
902 }
903 int dest_Bpp = m_bpp / 8;
904 int src_Bpp = pSrcBitmap->GetBPP() / 8;
905 bool bRgb = src_Bpp > 1 && !pSrcBitmap->IsCmykImage();
906 RetainPtr<CFX_DIBitmap> pSrcAlphaMask = pSrcBitmap->m_pAlphaMask;
907 for (int row = 0; row < height; row++) {
908 uint8_t* dest_scan =
909 m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * dest_Bpp;
910 const uint8_t* src_scan =
911 pSrcBitmap->GetScanline(src_top + row) + src_left * src_Bpp;
912 const uint8_t* src_scan_extra_alpha =
913 pSrcAlphaMask ? pSrcAlphaMask->GetScanline(src_top + row) + src_left
914 : nullptr;
915 uint8_t* dst_scan_extra_alpha =
916 m_pAlphaMask
917 ? m_pAlphaMask->GetWritableScanline(dest_top + row) + dest_left
918 : nullptr;
919 const uint8_t* clip_scan = nullptr;
920 if (pClipMask) {
921 clip_scan = pClipMask->m_pBuffer.Get() +
922 (dest_top + row - clip_box.top) * pClipMask->m_Pitch +
923 (dest_left - clip_box.left);
924 }
925 if (bRgb) {
926 compositor.CompositeRgbBitmapLine(dest_scan, src_scan, width, clip_scan,
927 src_scan_extra_alpha,
928 dst_scan_extra_alpha);
929 } else {
930 compositor.CompositePalBitmapLine(dest_scan, src_scan, src_left, width,
931 clip_scan, src_scan_extra_alpha,
932 dst_scan_extra_alpha);
933 }
934 }
935 return true;
936 }
937
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)938 bool CFX_DIBitmap::CompositeMask(int dest_left,
939 int dest_top,
940 int width,
941 int height,
942 const RetainPtr<CFX_DIBBase>& pMask,
943 uint32_t color,
944 int src_left,
945 int src_top,
946 BlendMode blend_type,
947 const CFX_ClipRgn* pClipRgn,
948 bool bRgbByteOrder) {
949 if (!m_pBuffer)
950 return false;
951
952 if (!pMask->IsAlphaMask() || m_bpp < 8) {
953 NOTREACHED();
954 return false;
955 }
956
957 if (!GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(),
958 pMask->GetHeight(), src_left, src_top, pClipRgn)) {
959 return true;
960 }
961
962 int src_alpha = FXARGB_A(color);
963 if (src_alpha == 0)
964 return true;
965
966 RetainPtr<CFX_DIBitmap> pClipMask;
967 FX_RECT clip_box;
968 if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
969 ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF);
970 pClipMask = pClipRgn->GetMask();
971 clip_box = pClipRgn->GetBox();
972 }
973 int src_bpp = pMask->GetBPP();
974 int Bpp = GetBPP() / 8;
975 CFX_ScanlineCompositor compositor;
976 if (!compositor.Init(GetFormat(), pMask->GetFormat(), width, nullptr, color,
977 blend_type, pClipMask != nullptr, bRgbByteOrder)) {
978 return false;
979 }
980 for (int row = 0; row < height; row++) {
981 uint8_t* dest_scan =
982 m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * Bpp;
983 const uint8_t* src_scan = pMask->GetScanline(src_top + row);
984 uint8_t* dst_scan_extra_alpha =
985 m_pAlphaMask
986 ? m_pAlphaMask->GetWritableScanline(dest_top + row) + dest_left
987 : nullptr;
988 const uint8_t* clip_scan = nullptr;
989 if (pClipMask) {
990 clip_scan = pClipMask->m_pBuffer.Get() +
991 (dest_top + row - clip_box.top) * pClipMask->m_Pitch +
992 (dest_left - clip_box.left);
993 }
994 if (src_bpp == 1) {
995 compositor.CompositeBitMaskLine(dest_scan, src_scan, src_left, width,
996 clip_scan, dst_scan_extra_alpha);
997 } else {
998 compositor.CompositeByteMaskLine(dest_scan, src_scan + src_left, width,
999 clip_scan, dst_scan_extra_alpha);
1000 }
1001 }
1002 return true;
1003 }
1004
CompositeRect(int left,int top,int width,int height,uint32_t color,int alpha_flag)1005 bool CFX_DIBitmap::CompositeRect(int left,
1006 int top,
1007 int width,
1008 int height,
1009 uint32_t color,
1010 int alpha_flag) {
1011 if (!m_pBuffer)
1012 return false;
1013
1014 int src_alpha = (alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color);
1015 if (src_alpha == 0)
1016 return true;
1017
1018 FX_RECT rect(left, top, left + width, top + height);
1019 rect.Intersect(0, 0, m_Width, m_Height);
1020 if (rect.IsEmpty())
1021 return true;
1022
1023 width = rect.Width();
1024 uint32_t dst_color;
1025 if (alpha_flag >> 8)
1026 dst_color = FXCMYK_TODIB(color);
1027 else
1028 dst_color = FXARGB_TODIB(color);
1029 uint8_t* color_p = reinterpret_cast<uint8_t*>(&dst_color);
1030 if (m_bpp == 8) {
1031 uint8_t gray = 255;
1032 if (!IsAlphaMask()) {
1033 if (alpha_flag >> 8) {
1034 uint8_t r;
1035 uint8_t g;
1036 uint8_t b;
1037 std::tie(r, g, b) =
1038 AdobeCMYK_to_sRGB1(color_p[0], color_p[1], color_p[2], color_p[3]);
1039 gray = FXRGB2GRAY(r, g, b);
1040 } else {
1041 gray = (uint8_t)FXRGB2GRAY((int)color_p[2], color_p[1], color_p[0]);
1042 }
1043 if (IsCmykImage()) {
1044 gray = ~gray;
1045 }
1046 }
1047 for (int row = rect.top; row < rect.bottom; row++) {
1048 uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left;
1049 if (src_alpha == 255) {
1050 memset(dest_scan, gray, width);
1051 } else {
1052 for (int col = 0; col < width; col++) {
1053 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
1054 dest_scan++;
1055 }
1056 }
1057 }
1058 return true;
1059 }
1060 if (m_bpp == 1) {
1061 ASSERT(!IsCmykImage());
1062 ASSERT(static_cast<uint8_t>(alpha_flag >> 8) == 0);
1063
1064 int left_shift = rect.left % 8;
1065 int right_shift = rect.right % 8;
1066 int new_width = rect.right / 8 - rect.left / 8;
1067 int index = 0;
1068 if (m_pPalette) {
1069 for (int i = 0; i < 2; i++) {
1070 if (m_pPalette.get()[i] == color)
1071 index = i;
1072 }
1073 } else {
1074 index = (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
1075 }
1076 for (int row = rect.top; row < rect.bottom; row++) {
1077 uint8_t* dest_scan_top = GetWritableScanline(row) + rect.left / 8;
1078 uint8_t* dest_scan_top_r = GetWritableScanline(row) + rect.right / 8;
1079 uint8_t left_flag = *dest_scan_top & (255 << (8 - left_shift));
1080 uint8_t right_flag = *dest_scan_top_r & (255 >> right_shift);
1081 if (new_width) {
1082 memset(dest_scan_top + 1, index ? 255 : 0, new_width - 1);
1083 if (!index) {
1084 *dest_scan_top &= left_flag;
1085 *dest_scan_top_r &= right_flag;
1086 } else {
1087 *dest_scan_top |= ~left_flag;
1088 *dest_scan_top_r |= ~right_flag;
1089 }
1090 } else {
1091 if (!index) {
1092 *dest_scan_top &= left_flag | right_flag;
1093 } else {
1094 *dest_scan_top |= ~(left_flag | right_flag);
1095 }
1096 }
1097 }
1098 return true;
1099 }
1100
1101 if (m_bpp < 24) {
1102 NOTREACHED();
1103 return false;
1104 }
1105
1106 if (!(alpha_flag >> 8) && IsCmykImage())
1107 return false;
1108
1109 if (alpha_flag >> 8 && !IsCmykImage()) {
1110 std::tie(color_p[2], color_p[1], color_p[0]) =
1111 AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color),
1112 FXSYS_GetYValue(color), FXSYS_GetKValue(color));
1113 }
1114 if (!IsCmykImage())
1115 color_p[3] = static_cast<uint8_t>(src_alpha);
1116 int Bpp = m_bpp / 8;
1117 bool bAlpha = HasAlpha();
1118 bool bArgb = GetFormat() == FXDIB_Argb;
1119 if (src_alpha == 255) {
1120 for (int row = rect.top; row < rect.bottom; row++) {
1121 uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
1122 uint8_t* dest_scan_alpha =
1123 m_pAlphaMask ? m_pAlphaMask->GetWritableScanline(row) + rect.left
1124 : nullptr;
1125 if (dest_scan_alpha)
1126 memset(dest_scan_alpha, 0xff, width);
1127
1128 if (Bpp == 4) {
1129 uint32_t* scan = reinterpret_cast<uint32_t*>(dest_scan);
1130 for (int col = 0; col < width; col++)
1131 *scan++ = dst_color;
1132 } else {
1133 for (int col = 0; col < width; col++) {
1134 *dest_scan++ = color_p[0];
1135 *dest_scan++ = color_p[1];
1136 *dest_scan++ = color_p[2];
1137 }
1138 }
1139 }
1140 return true;
1141 }
1142 for (int row = rect.top; row < rect.bottom; row++) {
1143 uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
1144 if (bAlpha) {
1145 if (bArgb) {
1146 for (int col = 0; col < width; col++) {
1147 uint8_t back_alpha = dest_scan[3];
1148 if (back_alpha == 0) {
1149 FXARGB_SETDIB(dest_scan, ArgbEncode(src_alpha, color_p[2],
1150 color_p[1], color_p[0]));
1151 dest_scan += 4;
1152 continue;
1153 }
1154 uint8_t dest_alpha =
1155 back_alpha + src_alpha - back_alpha * src_alpha / 255;
1156 int alpha_ratio = src_alpha * 255 / dest_alpha;
1157 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[0], alpha_ratio);
1158 dest_scan++;
1159 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[1], alpha_ratio);
1160 dest_scan++;
1161 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[2], alpha_ratio);
1162 dest_scan++;
1163 *dest_scan++ = dest_alpha;
1164 }
1165 } else {
1166 uint8_t* dest_scan_alpha =
1167 m_pAlphaMask->GetWritableScanline(row) + rect.left;
1168 for (int col = 0; col < width; col++) {
1169 uint8_t back_alpha = *dest_scan_alpha;
1170 if (back_alpha == 0) {
1171 *dest_scan_alpha++ = src_alpha;
1172 memcpy(dest_scan, color_p, Bpp);
1173 dest_scan += Bpp;
1174 continue;
1175 }
1176 uint8_t dest_alpha =
1177 back_alpha + src_alpha - back_alpha * src_alpha / 255;
1178 *dest_scan_alpha++ = dest_alpha;
1179 int alpha_ratio = src_alpha * 255 / dest_alpha;
1180 for (int comps = 0; comps < Bpp; comps++) {
1181 *dest_scan =
1182 FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], alpha_ratio);
1183 dest_scan++;
1184 }
1185 }
1186 }
1187 } else {
1188 for (int col = 0; col < width; col++) {
1189 for (int comps = 0; comps < Bpp; comps++) {
1190 if (comps == 3) {
1191 *dest_scan++ = 255;
1192 continue;
1193 }
1194 *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], src_alpha);
1195 dest_scan++;
1196 }
1197 }
1198 }
1199 }
1200 return true;
1201 }
1202
ConvertFormat(FXDIB_Format dest_format)1203 bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
1204 FXDIB_Format src_format = GetFormat();
1205 if (dest_format == src_format)
1206 return true;
1207
1208 if (dest_format == FXDIB_8bppMask && src_format == FXDIB_8bppRgb &&
1209 !m_pPalette) {
1210 m_AlphaFlag = 1;
1211 return true;
1212 }
1213 if (dest_format == FXDIB_Argb && src_format == FXDIB_Rgb32) {
1214 m_AlphaFlag = 2;
1215 for (int row = 0; row < m_Height; row++) {
1216 uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch + 3;
1217 for (int col = 0; col < m_Width; col++) {
1218 *scanline = 0xff;
1219 scanline += 4;
1220 }
1221 }
1222 return true;
1223 }
1224 int dest_bpp = GetBppFromFormat(dest_format);
1225 int dest_pitch = (dest_bpp * m_Width + 31) / 32 * 4;
1226 std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
1227 FX_TryAlloc(uint8_t, dest_pitch * m_Height + 4));
1228 if (!dest_buf)
1229 return false;
1230
1231 RetainPtr<CFX_DIBitmap> pAlphaMask;
1232 if (dest_format == FXDIB_Argb) {
1233 memset(dest_buf.get(), 0xff, dest_pitch * m_Height + 4);
1234 if (m_pAlphaMask) {
1235 for (int row = 0; row < m_Height; row++) {
1236 uint8_t* pDstScanline = dest_buf.get() + row * dest_pitch + 3;
1237 const uint8_t* pSrcScanline = m_pAlphaMask->GetScanline(row);
1238 for (int col = 0; col < m_Width; col++) {
1239 *pDstScanline = *pSrcScanline++;
1240 pDstScanline += 4;
1241 }
1242 }
1243 }
1244 } else if (GetIsAlphaFromFormat(dest_format)) {
1245 if (src_format == FXDIB_Argb) {
1246 pAlphaMask = CloneAlphaMask();
1247 if (!pAlphaMask)
1248 return false;
1249 } else {
1250 if (!m_pAlphaMask) {
1251 if (!BuildAlphaMask())
1252 return false;
1253 pAlphaMask = std::move(m_pAlphaMask);
1254 } else {
1255 pAlphaMask = m_pAlphaMask;
1256 }
1257 }
1258 }
1259 bool ret = false;
1260 RetainPtr<CFX_DIBBase> holder(this);
1261 std::unique_ptr<uint32_t, FxFreeDeleter> pal_8bpp;
1262 ret = ConvertBuffer(dest_format, dest_buf.get(), dest_pitch, m_Width,
1263 m_Height, holder, 0, 0, &pal_8bpp);
1264 if (!ret)
1265 return false;
1266
1267 m_pAlphaMask = pAlphaMask;
1268 m_pPalette = std::move(pal_8bpp);
1269 m_pBuffer = std::move(dest_buf);
1270 m_bpp = GetBppFromFormat(dest_format);
1271 m_AlphaFlag = GetAlphaFlagFromFormat(dest_format);
1272 m_Pitch = dest_pitch;
1273 return true;
1274 }
1275