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