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_dibbase.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_dibbase.h"
8
9#include <stdint.h>
10#include <string.h>
11
12#include <algorithm>
13#include <utility>
14#include <vector>
15
16#include "core/fxcrt/data_vector.h"
17#include "core/fxcrt/fx_2d_size.h"
18#include "core/fxcrt/fx_coordinates.h"
19#include "core/fxcrt/fx_memory.h"
20#include "core/fxcrt/fx_safe_types.h"
21#include "core/fxcrt/span_util.h"
22#include "core/fxge/calculate_pitch.h"
23#include "core/fxge/cfx_cliprgn.h"
24#include "core/fxge/dib/cfx_bitmapstorer.h"
25#include "core/fxge/dib/cfx_dibitmap.h"
26#include "core/fxge/dib/cfx_imagestretcher.h"
27#include "core/fxge/dib/cfx_imagetransformer.h"
28#include "third_party/base/check.h"
29#include "third_party/base/check_op.h"
30#include "third_party/base/containers/span.h"
31#include "third_party/base/notreached.h"
32
33namespace {
34
35void ColorDecode(uint32_t pal_v, uint8_t* r, uint8_t* g, uint8_t* b) {
36 *r = static_cast<uint8_t>((pal_v & 0xf00) >> 4);
37 *g = static_cast<uint8_t>(pal_v & 0x0f0);
38 *b = static_cast<uint8_t>((pal_v & 0x00f) << 4);
39}
40
41class CFX_Palette {
42 public:
43 // (Amount, Color) pairs
44 using LutsData = std::pair<uint32_t, uint32_t>;
45
46 explicit CFX_Palette(const RetainPtr<const CFX_DIBBase>& pBitmap);
47 ~CFX_Palette();
48
49 pdfium::span<const uint32_t> GetPalette() { return m_Palette; }
50 pdfium::span<const LutsData> GetValidLuts() {
51 return pdfium::make_span(m_Luts).first(m_lut);
52 }
53
54 private:
55 void ObtainPalette();
56
57 std::vector<uint32_t> m_Palette;
58 std::vector<LutsData> m_Luts;
59 uint32_t m_lut = 0;
60};
61
62CFX_Palette::CFX_Palette(const RetainPtr<const CFX_DIBBase>& pBitmap)
63 : m_Palette(256), m_Luts(4096) {
64 int bpp = pBitmap->GetBPP() / 8;
65 int width = pBitmap->GetWidth();
66 int height = pBitmap->GetHeight();
67 for (int row = 0; row < height; ++row) {
68 pdfium::span<const uint8_t> scan_line = pBitmap->GetScanline(row);
69 for (int col = 0; col < width; ++col) {
70 const uint8_t* src_port =
71 scan_line.subspan(Fx2DSizeOrDie(col, bpp)).data();
72 uint32_t b = src_port[0] & 0xf0;
73 uint32_t g = src_port[1] & 0xf0;
74 uint32_t r = src_port[2] & 0xf0;
75 uint32_t index = (r << 4) + g + (b >> 4);
76 ++m_Luts[index].first;
77 }
78 }
79 // Move non-zeros to the front and count them
80 for (uint32_t row = 0; row < m_Luts.size(); ++row) {
81 if (m_Luts[row].first != 0) {
82 m_Luts[m_lut].first = m_Luts[row].first;
83 m_Luts[m_lut].second = row;
84 ++m_lut;
85 }
86 }
87 pdfium::span<LutsData> lut_span = pdfium::make_span(m_Luts).first(m_lut);
88 std::sort(lut_span.begin(), lut_span.end(),
89 [](const LutsData& arg1, const LutsData& arg2) {
90 return arg1.first < arg2.first;
91 });
92 ObtainPalette();
93}
94
95CFX_Palette::~CFX_Palette() = default;
96
97void CFX_Palette::ObtainPalette() {
98 for (uint32_t row = 0; row < m_Palette.size(); ++row) {
99 const uint32_t lut_offset = (m_lut - row - 1) % m_Palette.size();
100 const uint32_t color = m_Luts[lut_offset].second;
101 uint8_t r;
102 uint8_t g;
103 uint8_t b;
104 ColorDecode(color, &r, &g, &b);
105 m_Palette[row] = (static_cast<uint32_t>(r) << 16) |
106 (static_cast<uint32_t>(g) << 8) | b | 0xff000000;
107 m_Luts[lut_offset].first = row;
108 }
109 if (m_lut > 256) {
110 int err;
111 int min_err;
112 const uint32_t lut_256 = m_lut - 256;
113 for (uint32_t row = 0; row < lut_256; ++row) {
114 min_err = 1000000;
115 uint8_t r;
116 uint8_t g;
117 uint8_t b;
118 ColorDecode(m_Luts[row].second, &r, &g, &b);
119 uint32_t clrindex = 0;
120 for (int col = 0; col < 256; ++col) {
121 uint32_t p_color = m_Palette[col];
122 int d_r = r - static_cast<uint8_t>(p_color >> 16);
123 int d_g = g - static_cast<uint8_t>(p_color >> 8);
124 int d_b = b - static_cast<uint8_t>(p_color);
125 err = d_r * d_r + d_g * d_g + d_b * d_b;
126 if (err < min_err) {
127 min_err = err;
128 clrindex = col;
129 }
130 }
131 m_Luts[row].first = clrindex;
132 }
133 }
134}
135
136void ConvertBuffer_1bppMask2Gray(pdfium::span<uint8_t> dest_buf,
137 int dest_pitch,
138 int width,
139 int height,
140 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
141 int src_left,
142 int src_top) {
143 static constexpr uint8_t kSetGray = 0xff;
144 static constexpr uint8_t kResetGray = 0x00;
145 for (int row = 0; row < height; ++row) {
146 pdfium::span<uint8_t> dest_span =
147 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch));
148 pdfium::span<const uint8_t> src_span =
149 pSrcBitmap->GetScanline(src_top + row);
150 fxcrt::spanset(dest_span.first(width), kResetGray);
151 uint8_t* dest_scan = dest_span.data();
152 const uint8_t* src_scan = src_span.data();
153 for (int col = src_left; col < src_left + width; ++col) {
154 if (src_scan[col / 8] & (1 << (7 - col % 8)))
155 *dest_scan = kSetGray;
156 ++dest_scan;
157 }
158 }
159}
160
161void ConvertBuffer_8bppMask2Gray(pdfium::span<uint8_t> dest_buf,
162 int dest_pitch,
163 int width,
164 int height,
165 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
166 int src_left,
167 int src_top) {
168 for (int row = 0; row < height; ++row) {
169 fxcrt::spancpy(
170 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)),
171 pSrcBitmap->GetScanline(src_top + row).subspan(src_left, width));
172 }
173}
174
175void ConvertBuffer_1bppPlt2Gray(pdfium::span<uint8_t> dest_buf,
176 int dest_pitch,
177 int width,
178 int height,
179 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
180 int src_left,
181 int src_top) {
182 pdfium::span<const uint32_t> src_palette = pSrcBitmap->GetPaletteSpan();
183 const uint8_t reset_r = FXARGB_R(src_palette[0]);
184 const uint8_t reset_g = FXARGB_G(src_palette[0]);
185 const uint8_t reset_b = FXARGB_B(src_palette[0]);
186 const uint8_t set_r = FXARGB_R(src_palette[1]);
187 const uint8_t set_g = FXARGB_G(src_palette[1]);
188 const uint8_t set_b = FXARGB_B(src_palette[1]);
189 const uint8_t gray0 = FXRGB2GRAY(reset_r, reset_g, reset_b);
190 const uint8_t gray1 = FXRGB2GRAY(set_r, set_g, set_b);
191
192 for (int row = 0; row < height; ++row) {
193 pdfium::span<uint8_t> dest_span =
194 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch));
195 fxcrt::spanset(dest_span.first(width), gray0);
196 uint8_t* dest_scan = dest_span.data();
197 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
198 for (int col = src_left; col < src_left + width; ++col) {
199 if (src_scan[col / 8] & (1 << (7 - col % 8)))
200 *dest_scan = gray1;
201 ++dest_scan;
202 }
203 }
204}
205
206void ConvertBuffer_8bppPlt2Gray(pdfium::span<uint8_t> dest_buf,
207 int dest_pitch,
208 int width,
209 int height,
210 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
211 int src_left,
212 int src_top) {
213 pdfium::span<const uint32_t> src_palette = pSrcBitmap->GetPaletteSpan();
214 uint8_t gray[256];
215 for (size_t i = 0; i < std::size(gray); ++i) {
216 gray[i] = FXRGB2GRAY(FXARGB_R(src_palette[i]), FXARGB_G(src_palette[i]),
217 FXARGB_B(src_palette[i]));
218 }
219
220 for (int row = 0; row < height; ++row) {
221 uint8_t* dest_scan =
222 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
223 const uint8_t* src_scan =
224 pSrcBitmap->GetScanline(src_top + row).subspan(src_left).data();
225 for (int col = 0; col < width; ++col)
226 *dest_scan++ = gray[*src_scan++];
227 }
228}
229
230void ConvertBuffer_Rgb2Gray(pdfium::span<uint8_t> dest_buf,
231 int dest_pitch,
232 int width,
233 int height,
234 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
235 int src_left,
236 int src_top) {
237 const int Bpp = pSrcBitmap->GetBPP() / 8;
238 const size_t x_offset = Fx2DSizeOrDie(src_left, Bpp);
239 for (int row = 0; row < height; ++row) {
240 uint8_t* dest_scan =
241 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
242 const uint8_t* src_scan =
243 pSrcBitmap->GetScanline(src_top + row).subspan(x_offset).data();
244 for (int col = 0; col < width; ++col) {
245 *dest_scan++ = FXRGB2GRAY(src_scan[2], src_scan[1], src_scan[0]);
246 src_scan += Bpp;
247 }
248 }
249}
250
251void ConvertBuffer_IndexCopy(pdfium::span<uint8_t> dest_buf,
252 int dest_pitch,
253 int width,
254 int height,
255 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
256 int src_left,
257 int src_top) {
258 if (pSrcBitmap->GetBPP() == 1) {
259 for (int row = 0; row < height; ++row) {
260 pdfium::span<uint8_t> dest_span =
261 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch));
262 // Set all destination pixels to be white initially.
263 fxcrt::spanset(dest_span.first(width), 255);
264 uint8_t* dest_scan = dest_span.data();
265 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
266 for (int col = src_left; col < src_left + width; ++col) {
267 // If the source bit is set, then set the destination pixel to be black.
268 if (src_scan[col / 8] & (1 << (7 - col % 8)))
269 *dest_scan = 0;
270
271 ++dest_scan;
272 }
273 }
274 } else {
275 for (int row = 0; row < height; ++row) {
276 fxcrt::spancpy(
277 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)),
278 pSrcBitmap->GetScanline(src_top + row).subspan(src_left, width));
279 }
280 }
281}
282
283// Returns a palette of a fixed size.
284DataVector<uint32_t> ConvertBuffer_Plt2PltRgb8(
285 pdfium::span<uint8_t> dest_buf,
286 int dest_pitch,
287 int width,
288 int height,
289 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
290 int src_left,
291 int src_top) {
292 ConvertBuffer_IndexCopy(dest_buf, dest_pitch, width, height, pSrcBitmap,
293 src_left, src_top);
294 const size_t plt_size = pSrcBitmap->GetRequiredPaletteSize();
295 pdfium::span<const uint32_t> src_span = pSrcBitmap->GetPaletteSpan();
296 CHECK_LE(plt_size, src_span.size());
297
298 pdfium::span<const uint32_t> src_palette_span = src_span.first(plt_size);
299 return DataVector<uint32_t>(src_palette_span.begin(), src_palette_span.end());
300}
301
302DataVector<uint32_t> ConvertBuffer_Rgb2PltRgb8(
303 pdfium::span<uint8_t> dest_buf,
304 int dest_pitch,
305 int width,
306 int height,
307 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
308 int src_left,
309 int src_top) {
310 int bpp = pSrcBitmap->GetBPP() / 8;
311 CFX_Palette src_palette(pSrcBitmap);
312 pdfium::span<const CFX_Palette::LutsData> luts = src_palette.GetValidLuts();
313 for (int row = 0; row < height; ++row) {
314 pdfium::span<const uint8_t> src_span =
315 pSrcBitmap->GetScanline(src_top + row).subspan(src_left);
316 uint8_t* dest_scan =
317 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
318 for (int col = 0; col < width; ++col) {
319 const uint8_t* src_port =
320 src_span.subspan(Fx2DSizeOrDie(col, bpp)).data();
321 int r = src_port[2] & 0xf0;
322 int g = src_port[1] & 0xf0;
323 int b = src_port[0] & 0xf0;
324 uint32_t clrindex = (r << 4) + g + (b >> 4);
325 for (size_t i = luts.size(); i > 0; --i) {
326 if (clrindex == luts[i - 1].second) {
327 *(dest_scan + col) = static_cast<uint8_t>(luts[i - 1].first);
328 break;
329 }
330 }
331 }
332 }
333
334 pdfium::span<const uint32_t> src_palette_span = src_palette.GetPalette();
335 return DataVector<uint32_t>(src_palette_span.begin(), src_palette_span.end());
336}
337
338void ConvertBuffer_1bppMask2Rgb(FXDIB_Format dest_format,
339 pdfium::span<uint8_t> dest_buf,
340 int dest_pitch,
341 int width,
342 int height,
343 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
344 int src_left,
345 int src_top) {
346 int comps = GetCompsFromFormat(dest_format);
347 static constexpr uint8_t kSetGray = 0xff;
348 static constexpr uint8_t kResetGray = 0x00;
349 for (int row = 0; row < height; ++row) {
350 uint8_t* dest_scan =
351 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
352 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
353 for (int col = src_left; col < src_left + width; ++col) {
354 uint8_t value =
355 (src_scan[col / 8] & (1 << (7 - col % 8))) ? kSetGray : kResetGray;
356 memset(dest_scan, value, 3);
357 dest_scan += comps;
358 }
359 }
360}
361
362void ConvertBuffer_8bppMask2Rgb(FXDIB_Format dest_format,
363 pdfium::span<uint8_t> dest_buf,
364 int dest_pitch,
365 int width,
366 int height,
367 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
368 int src_left,
369 int src_top) {
370 int comps = GetCompsFromFormat(dest_format);
371 for (int row = 0; row < height; ++row) {
372 uint8_t* dest_scan =
373 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
374 const uint8_t* src_scan =
375 pSrcBitmap->GetScanline(src_top + row).subspan(src_left).data();
376 for (int col = 0; col < width; ++col) {
377 memset(dest_scan, *src_scan, 3);
378 dest_scan += comps;
379 ++src_scan;
380 }
381 }
382}
383
384void ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dest_format,
385 pdfium::span<uint8_t> dest_buf,
386 int dest_pitch,
387 int width,
388 int height,
389 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
390 int src_left,
391 int src_top) {
392 pdfium::span<const uint32_t> src_palette = pSrcBitmap->GetPaletteSpan();
393 const uint8_t dst_palette[6] = {
394 FXARGB_B(src_palette[0]), FXARGB_G(src_palette[0]),
395 FXARGB_R(src_palette[0]), FXARGB_B(src_palette[1]),
396 FXARGB_G(src_palette[1]), FXARGB_R(src_palette[1])};
397 int comps = GetCompsFromFormat(dest_format);
398 for (int row = 0; row < height; ++row) {
399 uint8_t* dest_scan =
400 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
401 const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row).data();
402 for (int col = src_left; col < src_left + width; ++col) {
403 size_t offset = (src_scan[col / 8] & (1 << (7 - col % 8))) ? 3 : 0;
404 memcpy(dest_scan, dst_palette + offset, 3);
405 dest_scan += comps;
406 }
407 }
408}
409
410void ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dest_format,
411 pdfium::span<uint8_t> dest_buf,
412 int dest_pitch,
413 int width,
414 int height,
415 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
416 int src_left,
417 int src_top) {
418 pdfium::span<const uint32_t> src_palette = pSrcBitmap->GetPaletteSpan();
419 uint8_t dst_palette[768];
420 for (int i = 0; i < 256; ++i) {
421 dst_palette[3 * i] = FXARGB_B(src_palette[i]);
422 dst_palette[3 * i + 1] = FXARGB_G(src_palette[i]);
423 dst_palette[3 * i + 2] = FXARGB_R(src_palette[i]);
424 }
425 int comps = GetCompsFromFormat(dest_format);
426 for (int row = 0; row < height; ++row) {
427 uint8_t* dest_scan =
428 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
429 const uint8_t* src_scan =
430 pSrcBitmap->GetScanline(src_top + row).subspan(src_left).data();
431 for (int col = 0; col < width; ++col) {
432 uint8_t* src_pixel = dst_palette + 3 * (*src_scan++);
433 memcpy(dest_scan, src_pixel, 3);
434 dest_scan += comps;
435 }
436 }
437}
438
439void ConvertBuffer_24bppRgb2Rgb24(
440 pdfium::span<uint8_t> dest_buf,
441 int dest_pitch,
442 int width,
443 int height,
444 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
445 int src_left,
446 int src_top) {
447 const size_t x_offset = Fx2DSizeOrDie(src_left, 3);
448 const size_t byte_count = Fx2DSizeOrDie(width, 3);
449 for (int row = 0; row < height; ++row) {
450 fxcrt::spancpy(
451 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)),
452 pSrcBitmap->GetScanline(src_top + row).subspan(x_offset, byte_count));
453 }
454}
455
456void ConvertBuffer_32bppRgb2Rgb24(
457 pdfium::span<uint8_t> dest_buf,
458 int dest_pitch,
459 int width,
460 int height,
461 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
462 int src_left,
463 int src_top) {
464 const size_t x_offset = Fx2DSizeOrDie(src_left, 4);
465 for (int row = 0; row < height; ++row) {
466 uint8_t* dest_scan =
467 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
468 const uint8_t* src_scan =
469 pSrcBitmap->GetScanline(src_top + row).subspan(x_offset).data();
470 for (int col = 0; col < width; ++col) {
471 memcpy(dest_scan, src_scan, 3);
472 dest_scan += 3;
473 src_scan += 4;
474 }
475 }
476}
477
478void ConvertBuffer_Rgb2Rgb32(pdfium::span<uint8_t> dest_buf,
479 int dest_pitch,
480 int width,
481 int height,
482 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
483 int src_left,
484 int src_top) {
485 const int comps = pSrcBitmap->GetBPP() / 8;
486 const size_t x_offset = Fx2DSizeOrDie(src_left, comps);
487 for (int row = 0; row < height; ++row) {
488 uint8_t* dest_scan =
489 dest_buf.subspan(Fx2DSizeOrDie(row, dest_pitch)).data();
490 const uint8_t* src_scan =
491 pSrcBitmap->GetScanline(src_top + row).subspan(x_offset).data();
492 for (int col = 0; col < width; ++col) {
493 memcpy(dest_scan, src_scan, 3);
494 dest_scan += 4;
495 src_scan += comps;
496 }
497 }
498}
499
500void ConvertBuffer_8bppMask(int bpp,
501 pdfium::span<uint8_t> dest_buf,
502 int dest_pitch,
503 int width,
504 int height,
505 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
506 int src_left,
507 int src_top) {
508 switch (bpp) {
509 case 1:
510 if (pSrcBitmap->HasPalette()) {
511 ConvertBuffer_1bppPlt2Gray(dest_buf, dest_pitch, width, height,
512 pSrcBitmap, src_left, src_top);
513 } else {
514 ConvertBuffer_1bppMask2Gray(dest_buf, dest_pitch, width, height,
515 pSrcBitmap, src_left, src_top);
516 }
517 break;
518 case 8:
519 if (pSrcBitmap->HasPalette()) {
520 ConvertBuffer_8bppPlt2Gray(dest_buf, dest_pitch, width, height,
521 pSrcBitmap, src_left, src_top);
522 } else {
523 ConvertBuffer_8bppMask2Gray(dest_buf, dest_pitch, width, height,
524 pSrcBitmap, src_left, src_top);
525 }
526 break;
527 case 24:
528 case 32:
529 ConvertBuffer_Rgb2Gray(dest_buf, dest_pitch, width, height, pSrcBitmap,
530 src_left, src_top);
531 break;
532 default:
533 NOTREACHED_NORETURN();
534 }
535}
536
537void ConvertBuffer_Rgb(int bpp,
538 FXDIB_Format dest_format,
539 pdfium::span<uint8_t> dest_buf,
540 int dest_pitch,
541 int width,
542 int height,
543 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
544 int src_left,
545 int src_top) {
546 switch (bpp) {
547 case 1:
548 if (pSrcBitmap->HasPalette()) {
549 ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
550 height, pSrcBitmap, src_left, src_top);
551 } else {
552 ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
553 height, pSrcBitmap, src_left, src_top);
554 }
555 break;
556 case 8:
557 if (pSrcBitmap->HasPalette()) {
558 ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
559 height, pSrcBitmap, src_left, src_top);
560 } else {
561 ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
562 height, pSrcBitmap, src_left, src_top);
563 }
564 break;
565 case 24:
566 ConvertBuffer_24bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
567 pSrcBitmap, src_left, src_top);
568 break;
569 case 32:
570 ConvertBuffer_32bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
571 pSrcBitmap, src_left, src_top);
572 break;
573 default:
574 NOTREACHED_NORETURN();
575 }
576}
577
578void ConvertBuffer_Argb(int bpp,
579 FXDIB_Format dest_format,
580 pdfium::span<uint8_t> dest_buf,
581 int dest_pitch,
582 int width,
583 int height,
584 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
585 int src_left,
586 int src_top) {
587 switch (bpp) {
588 case 1:
589 if (pSrcBitmap->HasPalette()) {
590 ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
591 height, pSrcBitmap, src_left, src_top);
592 } else {
593 ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
594 height, pSrcBitmap, src_left, src_top);
595 }
596 break;
597 case 8:
598 if (pSrcBitmap->HasPalette()) {
599 ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
600 height, pSrcBitmap, src_left, src_top);
601 } else {
602 ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
603 height, pSrcBitmap, src_left, src_top);
604 }
605 break;
606 case 24:
607 case 32:
608 ConvertBuffer_Rgb2Rgb32(dest_buf, dest_pitch, width, height, pSrcBitmap,
609 src_left, src_top);
610 break;
611 default:
612 NOTREACHED_NORETURN();
613 }
614}
615
616} // namespace
617
618CFX_DIBBase::CFX_DIBBase() = default;
619
620CFX_DIBBase::~CFX_DIBBase() = default;
621
622bool CFX_DIBBase::SkipToScanline(int line, PauseIndicatorIface* pPause) const {
623 return false;
624}
625
627 return GetRequiredPaletteSize() * sizeof(uint32_t);
628}
629
630#if BUILDFLAG(IS_WIN) || defined(PDF_USE_SKIA)
631RetainPtr<const CFX_DIBitmap> CFX_DIBBase::RealizeIfNeeded() const {
632 return Realize();
633}
634#endif
635
636RetainPtr<CFX_DIBitmap> CFX_DIBBase::Realize() const {
637 return ClipToInternal(nullptr);
638}
639
640RetainPtr<CFX_DIBitmap> CFX_DIBBase::ClipTo(const FX_RECT& rect) const {
641 return ClipToInternal(&rect);
642}
643
645 const FX_RECT* pClip) const {
647 if (pClip) {
648 rect.Intersect(*pClip);
649 if (rect.IsEmpty())
650 return nullptr;
651 }
652 auto pNewBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
653 if (!pNewBitmap->Create(rect.Width(), rect.Height(), GetFormat()))
654 return nullptr;
655
656 pNewBitmap->SetPalette(GetPaletteSpan());
657 if (GetBPP() == 1 && rect.left % 8 != 0) {
658 int left_shift = rect.left % 32;
659 int right_shift = 32 - left_shift;
660 int dword_count = pNewBitmap->m_Pitch / 4;
661 for (int row = rect.top; row < rect.bottom; ++row) {
662 auto src_span = fxcrt::reinterpret_span<const uint32_t>(GetScanline(row));
663 auto dst_span = fxcrt::reinterpret_span<uint32_t>(
664 pNewBitmap->GetWritableScanline(row - rect.top));
665 // Bounds check for free with first/subspan.
666 const uint32_t* src_scan =
667 src_span.subspan(rect.left / 32, dword_count + 1).data();
668 uint32_t* dst_scan = dst_span.first(dword_count).data();
669 for (int i = 0; i < dword_count; ++i) {
670 dst_scan[i] =
671 (src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift);
672 }
673 }
674 } else {
675 absl::optional<uint32_t> copy_len = fxge::CalculatePitch8(
676 pNewBitmap->GetBPP(), /*components=*/1, pNewBitmap->GetWidth());
677 if (!copy_len.has_value()) {
678 return nullptr;
679 }
680
681 copy_len = std::min<uint32_t>(m_Pitch, copy_len.value());
682
683 FX_SAFE_UINT32 offset = rect.left;
685 offset /= 8;
686 if (!offset.IsValid())
687 return nullptr;
688
689 for (int row = rect.top; row < rect.bottom; ++row) {
690 const uint8_t* src_scan =
691 GetScanline(row).subspan(offset.ValueOrDie()).data();
692 uint8_t* dest_scan =
693 pNewBitmap->GetWritableScanline(row - rect.top).data();
694 memcpy(dest_scan, src_scan, copy_len.value());
695 }
696 }
697 return pNewBitmap;
698}
699
701 if (HasPalette())
702 return;
703
704 if (GetBPP() == 1) {
705 m_palette = {0xff000000, 0xffffffff};
706 } else if (GetBPP() == 8) {
707 m_palette.resize(256);
708 for (int i = 0; i < 256; ++i)
709 m_palette[i] = ArgbEncode(0xff, i, i, i);
710 }
711}
712
714 if (IsMaskFormat())
715 return 0;
716
718 case 1:
719 return 2;
720 case 8:
721 return 256;
722 default:
723 return 0;
724 }
725}
726
727uint32_t CFX_DIBBase::GetPaletteArgb(int index) const {
728 DCHECK((GetBPP() == 1 || GetBPP() == 8) && !IsMaskFormat());
729 if (HasPalette())
730 return GetPaletteSpan()[index];
731
732 if (GetBPP() == 1)
733 return index ? 0xffffffff : 0xff000000;
734
735 return ArgbEncode(0xff, index, index, index);
736}
737
738void CFX_DIBBase::SetPaletteArgb(int index, uint32_t color) {
739 DCHECK((GetBPP() == 1 || GetBPP() == 8) && !IsMaskFormat());
741 m_palette[index] = color;
742}
743
744int CFX_DIBBase::FindPalette(uint32_t color) const {
745 DCHECK((GetBPP() == 1 || GetBPP() == 8) && !IsMaskFormat());
746 if (HasPalette()) {
747 int palsize = (1 << GetBPP());
748 pdfium::span<const uint32_t> palette = GetPaletteSpan();
749 for (int i = 0; i < palsize; ++i) {
750 if (palette[i] == color)
751 return i;
752 }
753 return -1;
754 }
755
756 if (GetBPP() == 1)
757 return (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
758 return static_cast<uint8_t>(color);
759}
760
761bool CFX_DIBBase::GetOverlapRect(int& dest_left,
762 int& dest_top,
763 int& width,
764 int& height,
765 int src_width,
766 int src_height,
767 int& src_left,
768 int& src_top,
769 const CFX_ClipRgn* pClipRgn) const {
770 if (width == 0 || height == 0)
771 return false;
772
773 DCHECK_GT(width, 0);
774 DCHECK_GT(height, 0);
775
776 if (dest_left > m_Width || dest_top > m_Height)
777 return false;
778
779 FX_SAFE_INT32 safe_src_width = src_left;
780 safe_src_width += width;
781 if (!safe_src_width.IsValid())
782 return false;
783
784 FX_SAFE_INT32 safe_src_height = src_top;
785 safe_src_height += height;
786 if (!safe_src_height.IsValid())
787 return false;
788
789 FX_RECT src_rect(src_left, src_top, safe_src_width.ValueOrDie(),
790 safe_src_height.ValueOrDie());
791 FX_RECT src_bound(0, 0, src_width, src_height);
792 src_rect.Intersect(src_bound);
793
794 FX_SAFE_INT32 safe_x_offset = dest_left;
795 safe_x_offset -= src_left;
796 if (!safe_x_offset.IsValid())
797 return false;
798
799 FX_SAFE_INT32 safe_y_offset = dest_top;
800 safe_y_offset -= src_top;
801 if (!safe_y_offset.IsValid())
802 return false;
803
804 FX_SAFE_INT32 safe_dest_left = safe_x_offset;
805 safe_dest_left += src_rect.left;
806 if (!safe_dest_left.IsValid())
807 return false;
808
809 FX_SAFE_INT32 safe_dest_top = safe_y_offset;
810 safe_dest_top += src_rect.top;
811 if (!safe_dest_top.IsValid())
812 return false;
813
814 FX_SAFE_INT32 safe_dest_right = safe_x_offset;
815 safe_dest_right += src_rect.right;
816 if (!safe_dest_right.IsValid())
817 return false;
818
819 FX_SAFE_INT32 safe_dest_bottom = safe_y_offset;
820 safe_dest_bottom += src_rect.bottom;
821 if (!safe_dest_bottom.IsValid())
822 return false;
823
824 FX_RECT dest_rect(safe_dest_left.ValueOrDie(), safe_dest_top.ValueOrDie(),
825 safe_dest_right.ValueOrDie(),
826 safe_dest_bottom.ValueOrDie());
827 FX_RECT dest_bound(0, 0, m_Width, m_Height);
828 dest_rect.Intersect(dest_bound);
829
830 if (pClipRgn)
831 dest_rect.Intersect(pClipRgn->GetBox());
832 dest_left = dest_rect.left;
833 dest_top = dest_rect.top;
834
835 FX_SAFE_INT32 safe_new_src_left = dest_left;
836 safe_new_src_left -= safe_x_offset;
837 if (!safe_new_src_left.IsValid())
838 return false;
839 src_left = safe_new_src_left.ValueOrDie();
840
841 FX_SAFE_INT32 safe_new_src_top = dest_top;
842 safe_new_src_top -= safe_y_offset;
843 if (!safe_new_src_top.IsValid())
844 return false;
845 src_top = safe_new_src_top.ValueOrDie();
846
847 if (dest_rect.IsEmpty())
848 return false;
849
850 width = dest_rect.Width();
851 height = dest_rect.Height();
852 return true;
853}
854
855void CFX_DIBBase::SetPalette(pdfium::span<const uint32_t> src_palette) {
856 TakePalette(DataVector<uint32_t>(src_palette.begin(), src_palette.end()));
857}
858
859void CFX_DIBBase::TakePalette(DataVector<uint32_t> src_palette) {
860 if (src_palette.empty() || GetBPP() > 8) {
861 m_palette.clear();
862 return;
863 }
864
865 m_palette = std::move(src_palette);
866 uint32_t pal_size = 1 << GetBPP();
867 CHECK_LE(pal_size, kPaletteSize);
868 m_palette.resize(pal_size);
869}
870
871RetainPtr<CFX_DIBitmap> CFX_DIBBase::CloneAlphaMask() const {
873 auto pMask = pdfium::MakeRetain<CFX_DIBitmap>();
874 if (!pMask->Create(m_Width, m_Height, FXDIB_Format::k8bppMask))
875 return nullptr;
876
877 for (int row = 0; row < m_Height; ++row) {
878 const uint8_t* src_scan = GetScanline(row).subspan(3).data();
879 uint8_t* dest_scan = pMask->GetWritableScanline(row).data();
880 for (int col = 0; col < m_Width; ++col) {
881 *dest_scan++ = *src_scan;
882 src_scan += 4;
883 }
884 }
885 return pMask;
886}
887
888RetainPtr<CFX_DIBitmap> CFX_DIBBase::FlipImage(bool bXFlip, bool bYFlip) const {
889 auto pFlipped = pdfium::MakeRetain<CFX_DIBitmap>();
890 if (!pFlipped->Create(m_Width, m_Height, GetFormat()))
891 return nullptr;
892
893 pFlipped->SetPalette(GetPaletteSpan());
894 int Bpp = GetBppFromFormat(m_Format) / 8;
895 for (int row = 0; row < m_Height; ++row) {
896 const uint8_t* src_scan = GetScanline(row).data();
897 uint8_t* dest_scan =
898 pFlipped->GetWritableScanline(bYFlip ? m_Height - row - 1 : row).data();
899 if (!bXFlip) {
900 memcpy(dest_scan, src_scan, m_Pitch);
901 continue;
902 }
904 memset(dest_scan, 0, m_Pitch);
905 for (int col = 0; col < m_Width; ++col) {
906 if (src_scan[col / 8] & (1 << (7 - col % 8))) {
907 int dest_col = m_Width - col - 1;
908 dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8));
909 }
910 }
911 continue;
912 }
913
914 dest_scan += (m_Width - 1) * Bpp;
915 if (Bpp == 1) {
916 for (int col = 0; col < m_Width; ++col) {
917 *dest_scan = *src_scan;
918 --dest_scan;
919 ++src_scan;
920 }
921 } else if (Bpp == 3) {
922 for (int col = 0; col < m_Width; ++col) {
923 memcpy(dest_scan, src_scan, 3);
924 dest_scan -= 3;
925 src_scan += 3;
926 }
927 } else {
928 DCHECK_EQ(Bpp, 4);
929 for (int col = 0; col < m_Width; ++col) {
930 const auto* src_scan32 = reinterpret_cast<const uint32_t*>(src_scan);
931 uint32_t* dest_scan32 = reinterpret_cast<uint32_t*>(dest_scan);
932 *dest_scan32 = *src_scan32;
933 dest_scan -= 4;
934 src_scan += 4;
935 }
936 }
937 }
938 return pFlipped;
939}
940
941RetainPtr<CFX_DIBitmap> CFX_DIBBase::ConvertTo(FXDIB_Format dest_format) const {
942 if (dest_format == GetFormat())
943 return Realize();
944
945 auto pClone = pdfium::MakeRetain<CFX_DIBitmap>();
946 if (!pClone->Create(m_Width, m_Height, dest_format))
947 return nullptr;
948
949 if (dest_format == FXDIB_Format::kArgb) {
950 if (!pClone->SetUniformOpaqueAlpha()) {
951 return nullptr;
952 }
953 }
954
955 RetainPtr<const CFX_DIBBase> holder(this);
956 DataVector<uint32_t> pal_8bpp =
957 ConvertBuffer(dest_format, pClone->GetWritableBuffer(),
958 pClone->GetPitch(), m_Width, m_Height, holder, 0, 0);
959 if (!pal_8bpp.empty()) {
960 pClone->TakePalette(std::move(pal_8bpp));
961 }
962 return pClone;
963}
964
965RetainPtr<CFX_DIBitmap> CFX_DIBBase::SwapXY(bool bXFlip, bool bYFlip) const {
966 FX_RECT dest_clip(0, 0, m_Height, m_Width);
967 if (dest_clip.IsEmpty())
968 return nullptr;
969
970 auto pTransBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
971 const int result_height = dest_clip.Height();
972 const int result_width = dest_clip.Width();
973 if (!pTransBitmap->Create(result_width, result_height, GetFormat()))
974 return nullptr;
975
976 pTransBitmap->SetPalette(GetPaletteSpan());
977 const int dest_pitch = pTransBitmap->GetPitch();
978 pdfium::span<uint8_t> dest_span = pTransBitmap->GetWritableBuffer().first(
979 Fx2DSizeOrDie(dest_pitch, result_height));
980 const size_t dest_last_row_offset =
981 Fx2DSizeOrDie(dest_pitch, result_height - 1);
982 const int row_start = bXFlip ? m_Height - dest_clip.right : dest_clip.left;
983 const int row_end = bXFlip ? m_Height - dest_clip.left : dest_clip.right;
984 const int col_start = bYFlip ? m_Width - dest_clip.bottom : dest_clip.top;
985 const int col_end = bYFlip ? m_Width - dest_clip.top : dest_clip.bottom;
986 if (GetBPP() == 1) {
987 fxcrt::spanset(dest_span, 0xff);
988 if (bYFlip)
989 dest_span = dest_span.subspan(dest_last_row_offset);
990 const int dest_step = bYFlip ? -dest_pitch : dest_pitch;
991 for (int row = row_start; row < row_end; ++row) {
992 const uint8_t* src_scan = GetScanline(row).data();
993 int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
994 dest_clip.left;
995 uint8_t* dest_scan = dest_span.data();
996 for (int col = col_start; col < col_end; ++col) {
997 if (!(src_scan[col / 8] & (1 << (7 - col % 8))))
998 dest_scan[dest_col / 8] &= ~(1 << (7 - dest_col % 8));
999 dest_scan += dest_step;
1000 }
1001 }
1002 } else {
1003 int nBytes = GetBPP() / 8;
1004 int dest_step = bYFlip ? -dest_pitch : dest_pitch;
1005 if (nBytes == 3)
1006 dest_step -= 2;
1007 if (bYFlip)
1008 dest_span = dest_span.subspan(dest_last_row_offset);
1009 for (int row = row_start; row < row_end; ++row) {
1010 int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
1011 dest_clip.left;
1012 size_t dest_offset = Fx2DSizeOrDie(dest_col, nBytes);
1013 uint8_t* dest_scan = dest_span.subspan(dest_offset).data();
1014 if (nBytes == 4) {
1015 const uint32_t* src_scan =
1016 fxcrt::reinterpret_span<const uint32_t>(GetScanline(row))
1017 .subspan(col_start)
1018 .data();
1019 for (int col = col_start; col < col_end; ++col) {
1020 uint32_t* dest_scan32 = reinterpret_cast<uint32_t*>(dest_scan);
1021 *dest_scan32 = *src_scan++;
1022 dest_scan += dest_step;
1023 }
1024 } else {
1025 const uint8_t* src_scan =
1026 GetScanline(row).subspan(col_start * nBytes).data();
1027 if (nBytes == 1) {
1028 for (int col = col_start; col < col_end; ++col) {
1029 *dest_scan = *src_scan++;
1030 dest_scan += dest_step;
1031 }
1032 } else {
1033 for (int col = col_start; col < col_end; ++col) {
1034 memcpy(dest_scan, src_scan, 3);
1035 dest_scan += 2 + dest_step;
1036 src_scan += 3;
1037 }
1038 }
1039 }
1040 }
1041 }
1042 return pTransBitmap;
1043}
1044
1045RetainPtr<CFX_DIBitmap> CFX_DIBBase::TransformTo(const CFX_Matrix& mtDest,
1046 int* result_left,
1047 int* result_top) const {
1048 RetainPtr<const CFX_DIBBase> holder(this);
1049 CFX_ImageTransformer transformer(holder, mtDest, FXDIB_ResampleOptions(),
1050 nullptr);
1051 transformer.Continue(nullptr);
1052 *result_left = transformer.result().left;
1053 *result_top = transformer.result().top;
1054 return transformer.DetachBitmap();
1055}
1056
1058 int dest_width,
1059 int dest_height,
1060 const FXDIB_ResampleOptions& options,
1061 const FX_RECT* pClip) const {
1062 RetainPtr<const CFX_DIBBase> holder(this);
1063 FX_RECT clip_rect(0, 0, abs(dest_width), abs(dest_height));
1064 if (pClip)
1065 clip_rect.Intersect(*pClip);
1066
1067 if (clip_rect.IsEmpty())
1068 return nullptr;
1069
1070 if (dest_width == m_Width && dest_height == m_Height)
1071 return ClipTo(clip_rect);
1072
1073 CFX_BitmapStorer storer;
1074 CFX_ImageStretcher stretcher(&storer, holder, dest_width, dest_height,
1075 clip_rect, options);
1076 if (stretcher.Start())
1077 stretcher.Continue(nullptr);
1078
1079 return storer.Detach();
1080}
1081
1082// static
1083DataVector<uint32_t> CFX_DIBBase::ConvertBuffer(
1084 FXDIB_Format dest_format,
1085 pdfium::span<uint8_t> dest_buf,
1086 int dest_pitch,
1087 int width,
1088 int height,
1089 const RetainPtr<const CFX_DIBBase>& pSrcBitmap,
1090 int src_left,
1091 int src_top) {
1092 FXDIB_Format src_format = pSrcBitmap->GetFormat();
1093 const int src_bpp = GetBppFromFormat(src_format);
1094 switch (dest_format) {
1096 ConvertBuffer_8bppMask(src_bpp, dest_buf, dest_pitch, width, height,
1097 pSrcBitmap, src_left, src_top);
1098 return {};
1099 }
1101 if (src_bpp == 1 || src_bpp == 8) {
1102 if (pSrcBitmap->HasPalette()) {
1103 return ConvertBuffer_Plt2PltRgb8(dest_buf, dest_pitch, width, height,
1104 pSrcBitmap, src_left, src_top);
1105 }
1106 return ConvertBuffer(FXDIB_Format::k8bppMask, dest_buf, dest_pitch,
1107 width, height, pSrcBitmap, src_left, src_top);
1108 }
1109 CHECK_GE(src_bpp, 24);
1110 return ConvertBuffer_Rgb2PltRgb8(dest_buf, dest_pitch, width, height,
1111 pSrcBitmap, src_left, src_top);
1112 }
1113 case FXDIB_Format::kRgb: {
1114 ConvertBuffer_Rgb(src_bpp, dest_format, dest_buf, dest_pitch, width,
1115 height, pSrcBitmap, src_left, src_top);
1116 return {};
1117 }
1119 case FXDIB_Format::kRgb32: {
1120 ConvertBuffer_Argb(src_bpp, dest_format, dest_buf, dest_pitch, width,
1121 height, pSrcBitmap, src_left, src_top);
1122 return {};
1123 }
1124 default:
1125 NOTREACHED_NORETURN();
1126 }
1127}
RetainPtr< CFX_DIBitmap > Detach()
const FX_RECT & GetBox() const
Definition cfx_cliprgn.h:24
int FindPalette(uint32_t color) const
virtual size_t GetEstimatedImageMemoryBurden() const
RetainPtr< CFX_DIBitmap > ClipTo(const FX_RECT &rect) const
RetainPtr< CFX_DIBitmap > Realize() const
RetainPtr< CFX_DIBitmap > SwapXY(bool bXFlip, bool bYFlip) const
void TakePalette(DataVector< uint32_t > src_palette)
virtual pdfium::span< const uint8_t > GetScanline(int line) const =0
bool HasPalette() const
Definition cfx_dibbase.h:62
virtual bool SkipToScanline(int line, PauseIndicatorIface *pPause) const
RetainPtr< CFX_DIBitmap > CloneAlphaMask() const
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()
~CFX_DIBBase() override
RetainPtr< CFX_DIBitmap > TransformTo(const CFX_Matrix &mtDest, int *left, int *top) const
void SetPaletteArgb(int index, uint32_t color)
RetainPtr< CFX_DIBitmap > ClipToInternal(const FX_RECT *pClip) const
RetainPtr< CFX_DIBitmap > ConvertTo(FXDIB_Format format) const
RetainPtr< CFX_DIBitmap > StretchTo(int dest_width, int dest_height, const FXDIB_ResampleOptions &options, const FX_RECT *pClip) const
static constexpr uint32_t kPaletteSize
Definition cfx_dibbase.h:42
size_t GetRequiredPaletteSize() const
bool IsMaskFormat() const
Definition cfx_dibbase.h:58
RetainPtr< CFX_DIBitmap > FlipImage(bool bXFlip, bool bYFlip) const
uint32_t GetPaletteArgb(int index) const
bool Continue(PauseIndicatorIface *pPause)
RetainPtr< CFX_DIBitmap > DetachBitmap()
bool Continue(PauseIndicatorIface *pPause)
const FX_RECT & result() const
#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
constexpr FX_ARGB ArgbEncode(uint32_t a, uint32_t r, uint32_t g, uint32_t b)
Definition fx_dib.h:118
int GetBppFromFormat(FXDIB_Format format)
Definition fx_dib.h:90
#define FXARGB_R(argb)
Definition fx_dib.h:125
int GetCompsFromFormat(FXDIB_Format format)
Definition fx_dib.h:95
FXDIB_Format
Definition fx_dib.h:19
int Height() const
int32_t bottom
int32_t right
int Width() const
int32_t top
int32_t left
void Intersect(const FX_RECT &src)
bool IsEmpty() const
constexpr FX_RECT(int l, int t, int r, int b)