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_skia.cpp
Go to the documentation of this file.
1// Copyright 2023 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#include "core/fxge/dib/cfx_dibbase.h"
6
7#include <stddef.h>
8#include <stdint.h>
9
10#include <memory>
11#include <type_traits>
12#include <utility>
13
14#include "core/fxcrt/check_op.h"
15#include "core/fxcrt/compiler_specific.h"
16#include "core/fxcrt/fx_2d_size.h"
17#include "core/fxcrt/fx_memory.h"
18#include "core/fxcrt/fx_memory_wrappers.h"
19#include "core/fxcrt/fx_safe_types.h"
20#include "core/fxcrt/notreached.h"
21#include "core/fxcrt/retain_ptr.h"
22#include "core/fxcrt/span.h"
23#include "core/fxge/calculate_pitch.h"
24#include "core/fxge/dib/cfx_dibitmap.h"
25#include "core/fxge/dib/fx_dib.h"
26#include "third_party/skia/include/core/SkAlphaType.h"
27#include "third_party/skia/include/core/SkColor.h"
28#include "third_party/skia/include/core/SkColorPriv.h"
29#include "third_party/skia/include/core/SkColorType.h"
30#include "third_party/skia/include/core/SkImage.h"
31#include "third_party/skia/include/core/SkImageInfo.h"
32#include "third_party/skia/include/core/SkPixmap.h"
33#include "third_party/skia/include/core/SkRefCnt.h"
34
35namespace {
36
37// Releases `CFX_DIBitmap` "leaked" by `CreateSkiaImageFromDib()`.
38void ReleaseRetainedHeldBySkImage(const void* /*pixels*/,
39 SkImages::ReleaseContext context) {
40 RetainPtr<const CFX_DIBitmap> realized_bitmap;
41 realized_bitmap.Unleak(reinterpret_cast<const CFX_DIBitmap*>(context));
42}
43
44// Creates an `SkImage` from a `CFX_DIBBase`.
45sk_sp<SkImage> CreateSkiaImageFromDib(const CFX_DIBBase* source,
46 SkColorType color_type,
47 SkAlphaType alpha_type) {
48 // Make sure the DIB is backed by a buffer.
49 RetainPtr<const CFX_DIBitmap> realized_bitmap = source->RealizeIfNeeded();
50 if (!realized_bitmap) {
51 return nullptr;
52 }
53 CHECK(!realized_bitmap->GetBuffer().empty());
54
55 // Transfer ownership of `realized_bitmap` to `bitmap`, which will be freed by
56 // ReleaseRetainedHeldBySkImage().
57 const CFX_DIBitmap* bitmap = realized_bitmap.Leak();
58 SkImageInfo info = SkImageInfo::Make(bitmap->GetWidth(), bitmap->GetHeight(),
59 color_type, alpha_type);
60 auto result = SkImages::RasterFromPixmap(
61 SkPixmap(info, bitmap->GetBuffer().data(), bitmap->GetPitch()),
62 /*rasterReleaseProc=*/ReleaseRetainedHeldBySkImage,
63 /*releaseContext=*/const_cast<CFX_DIBitmap*>(bitmap));
64 CHECK(result); // Otherwise, `bitmap` leaks.
65 return result;
66}
67
68// Releases allocated memory "leaked" by `CreateSkiaImageFromTransformedDib()`.
69void ReleaseAllocatedHeldBySkImage(const void* pixels,
70 SkImages::ReleaseContext /*context*/) {
71 FX_Free(const_cast<void*>(pixels));
72}
73
74// Template defining traits of a pixel transform function.
75template <size_t source_bits_per_pixel, typename PixelTransform>
76class PixelTransformTraits;
77
78template <typename PixelTransform>
79class PixelTransformTraits<1, PixelTransform> {
80 public:
81 using Result = std::invoke_result_t<PixelTransform, bool>;
82
83 static Result Invoke(PixelTransform&& pixel_transform,
84 pdfium::span<const uint8_t> scanline,
85 size_t column) {
86 uint8_t kMask = 1 << (7 - column % 8);
87 return pixel_transform(!!(scanline[column / 8] & kMask));
88 }
89};
90
91template <typename PixelTransform>
92class PixelTransformTraits<8, PixelTransform> {
93 public:
94 using Result = std::invoke_result_t<PixelTransform, uint8_t>;
95
96 static Result Invoke(PixelTransform&& pixel_transform,
97 pdfium::span<const uint8_t> scanline,
98 size_t column) {
99 return pixel_transform(scanline[column]);
100 }
101};
102
103template <typename PixelTransform>
104class PixelTransformTraits<24, PixelTransform> {
105 public:
106 using Result =
107 std::invoke_result_t<PixelTransform, uint8_t, uint8_t, uint8_t>;
108
109 static Result Invoke(PixelTransform&& pixel_transform,
110 pdfium::span<const uint8_t> scanline,
111 size_t column) {
112 size_t offset = column * 3;
113 return pixel_transform(scanline[offset + 2], scanline[offset + 1],
114 scanline[offset]);
115 }
116};
117
118template <typename PixelTransform>
119class PixelTransformTraits<32, PixelTransform> {
120 public:
121 using Result =
122 std::invoke_result_t<PixelTransform, uint8_t, uint8_t, uint8_t>;
123
124 static Result Invoke(PixelTransform&& pixel_transform,
125 pdfium::span<const uint8_t> scanline,
126 size_t column) {
127 size_t offset = column * 4;
128 return pixel_transform(scanline[offset + 2], scanline[offset + 1],
129 scanline[offset]);
130 }
131};
132
133void ValidateScanlineSize(pdfium::span<const uint8_t> scanline,
134 size_t min_row_bytes) {
135 DCHECK_GE(scanline.size(), min_row_bytes);
136}
137
138// Creates an `SkImage` from a `CFX_DIBBase`, transforming the source pixels
139// using `pixel_transform`.
140//
141// TODO(crbug.com/pdfium/2048): Consolidate with `CFX_DIBBase::ConvertBuffer()`.
142template <size_t source_bits_per_pixel, typename PixelTransform>
143sk_sp<SkImage> CreateSkiaImageFromTransformedDib(
144 const CFX_DIBBase& source,
145 SkColorType color_type,
146 SkAlphaType alpha_type,
147 PixelTransform&& pixel_transform) {
148 using Traits = PixelTransformTraits<source_bits_per_pixel, PixelTransform>;
149 using Result = typename Traits::Result;
150
151 // Allocate output buffer.
152 const int width = source.GetWidth();
153 const int height = source.GetHeight();
154 SkImageInfo info = SkImageInfo::Make(width, height, color_type, alpha_type);
155 DCHECK_EQ(info.minRowBytes(), width * sizeof(Result));
156
157 size_t output_size = Fx2DSizeOrDie(info.minRowBytes(), height);
158 std::unique_ptr<void, FxFreeDeleter> output(
159 FX_TryAlloc(uint8_t, output_size));
160 if (!output) {
161 return nullptr;
162 }
163
164 // Transform source pixels to output pixels. Iterate by individual scanline.
165 Result* output_cursor = reinterpret_cast<Result*>(output.get());
166 const size_t min_row_bytes =
167 fxge::CalculatePitch8OrDie(source.GetBPP(), /*components=*/1, width);
168 DCHECK_LE(min_row_bytes, source.GetPitch());
169
170 int line = 0;
171 for (int row = 0; row < height; ++row) {
172 pdfium::span<const uint8_t> scanline = source.GetScanline(line++);
173 ValidateScanlineSize(scanline, min_row_bytes);
174
175 for (int column = 0; column < width; ++column) {
176 UNSAFE_TODO(*output_cursor++) = Traits::Invoke(
177 std::forward<PixelTransform>(pixel_transform), scanline, column);
178 }
179 }
180
181 // "Leak" allocated memory to `SkImage`.
182 return SkImages::RasterFromPixmap(
183 SkPixmap(info, output.release(), info.minRowBytes()),
184 /*rasterReleaseProc=*/ReleaseAllocatedHeldBySkImage,
185 /*releaseContext=*/nullptr);
186}
187
188bool IsRGBColorGrayScale(uint32_t color) {
189 return FXARGB_R(color) == FXARGB_G(color) &&
190 FXARGB_R(color) == FXARGB_B(color);
191}
192
193} // namespace
194
195sk_sp<SkImage> CFX_DIBBase::RealizeSkImage() const {
196 switch (GetBPP()) {
197 case 1: {
198 // By default, the two colors for grayscale are 0xFF and 0x00 unless they
199 // are specified in the palette.
200 uint8_t color0 = 0x00;
201 uint8_t color1 = 0xFF;
202
204 uint32_t palette_color0 = GetPaletteArgb(0);
205 uint32_t palette_color1 = GetPaletteArgb(1);
206 bool use_gray_colors = IsRGBColorGrayScale(palette_color0) &&
207 IsRGBColorGrayScale(palette_color1);
208 if (!use_gray_colors) {
209 return CreateSkiaImageFromTransformedDib</*source_bits_per_pixel=*/1>(
210 *this, kBGRA_8888_SkColorType, kPremul_SkAlphaType,
211 [palette_color0, palette_color1](bool bit) {
212 return bit ? palette_color1 : palette_color0;
213 });
214 }
215
216 color0 = FXARGB_R(palette_color0);
217 color1 = FXARGB_R(palette_color1);
218 }
219
220 return CreateSkiaImageFromTransformedDib</*source_bits_per_pixel=*/1>(
221 *this, IsMaskFormat() ? kAlpha_8_SkColorType : kGray_8_SkColorType,
222 kPremul_SkAlphaType,
223 [color0, color1](bool bit) { return bit ? color1 : color0; });
224 }
225
226 case 8:
227 // we upscale ctables to 32bit.
228 if (HasPalette()) {
229 return CreateSkiaImageFromTransformedDib</*source_bits_per_pixel=*/8>(
230 *this, kBGRA_8888_SkColorType, kPremul_SkAlphaType,
231 [palette = GetPaletteSpan().first(GetRequiredPaletteSize())](
232 uint8_t index) {
233 if (index >= palette.size()) {
234 index = 0;
235 }
236 return palette[index];
237 });
238 }
239 return CreateSkiaImageFromDib(
240 this, IsMaskFormat() ? kAlpha_8_SkColorType : kGray_8_SkColorType,
241 kPremul_SkAlphaType);
242
243 case 24:
244 return CreateSkiaImageFromTransformedDib</*source_bits_per_pixel=*/24>(
245 *this, kBGRA_8888_SkColorType, kOpaque_SkAlphaType,
246 [](uint8_t red, uint8_t green, uint8_t blue) {
247 return SkPackARGB32(0xFF, red, green, blue);
248 });
249
250 case 32:
251 switch (GetFormat()) {
252 case FXDIB_Format::kBgrx:
253 return CreateSkiaImageFromTransformedDib<
254 /*source_bits_per_pixel=*/32>(
255 *this, kBGRA_8888_SkColorType, kOpaque_SkAlphaType,
256 [](uint8_t red, uint8_t green, uint8_t blue) {
257 return SkPackARGB32(0xFF, red, green, blue);
258 });
259 case FXDIB_Format::kBgra:
260 return CreateSkiaImageFromDib(this, kBGRA_8888_SkColorType,
261 kUnpremul_SkAlphaType);
262 case FXDIB_Format::kBgraPremul:
263 return CreateSkiaImageFromDib(this, kBGRA_8888_SkColorType,
264 kPremul_SkAlphaType);
265 default:
267 }
268 default:
270 }
271}
#define DCHECK_GE(x, y)
Definition check_op.h:22
#define DCHECK_LE(x, y)
Definition check_op.h:21
#define DCHECK_EQ(x, y)
Definition check_op.h:17
bool HasPalette() const
Definition cfx_dibbase.h:78
FXDIB_Format GetFormat() const
Definition cfx_dibbase.h:69
int GetBPP() const
Definition cfx_dibbase.h:72
uint32_t GetPitch() const
Definition cfx_dibbase.h:67
int GetHeight() const
Definition cfx_dibbase.h:66
int GetWidth() const
Definition cfx_dibbase.h:65
uint32_t GetPaletteArgb(int index) const
#define UNSAFE_TODO(...)
#define FXARGB_B(argb)
Definition fx_dib.h:199
#define FXARGB_G(argb)
Definition fx_dib.h:198
#define FXARGB_R(argb)
Definition fx_dib.h:197
FXDIB_Format
Definition fx_dib.h:21
uint32_t CalculatePitch8OrDie(uint32_t bits_per_component, uint32_t components_per_pixel, int width_in_pixels)
void Dealloc(void *ptr)
#define NOTREACHED_NORETURN()
Definition notreached.h:22
#define CHECK(cvref)