| /* | |
| * Copyright 2025 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SkBmpRustCodec_DEFINED | |
| #define SkBmpRustCodec_DEFINED | |
| #include <memory> | |
| #include <optional> | |
| #include "include/codec/SkCodec.h" | |
| #include "include/codec/SkEncodedImageFormat.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkSpan.h" | |
| #include "rust/bmp/FFI.rs.h" | |
| #include "third_party/rust/cxx/v1/cxx.h" | |
| struct SkEncodedInfo; | |
| class SkData; | |
| class SkStream; | |
| class SkSwizzler; | |
| // This class provides the Skia image decoding API (`SkCodec`) on top of: | |
| // * The third-party `image` crate (containing BMP decompression and decoding | |
| // implemented in Rust) | |
| // * Skia's `SkSwizzler` and `skcms_Transform` (pixel format and color space | |
| // transformations implemented in C++). | |
| class SkBmpRustCodec final : public SkCodec { | |
| public: | |
| // Discriminates a standalone BMP stream from a BMP embedded in an ICO file. | |
| // ICO streams have no "BM" file header, store a doubled height, and may carry | |
| // alpha via an AND mask, so they need ICO-aware metadata parsing. | |
| enum class StreamType { kBMP, kICO }; | |
| static std::unique_ptr<SkBmpRustCodec> MakeFromStream(std::unique_ptr<SkStream>, | |
| Result*, | |
| StreamType = StreamType::kBMP); | |
| static std::unique_ptr<SkBmpRustCodec> MakeFromData(sk_sp<const SkData>, Result*); | |
| ~SkBmpRustCodec() override; | |
| protected: | |
| SkBmpRustCodec(SkEncodedInfo&&, | |
| std::unique_ptr<SkStream>, | |
| rust::Box<rust_bmp::Reader>, | |
| StreamType, | |
| sk_sp<const SkData> inMemoryData); | |
| SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kBMP; } | |
| bool onRewind() override; | |
| bool onGetFrameInfo(int, FrameInfo*) const override; | |
| private: | |
| static std::unique_ptr<SkBmpRustCodec> MakeFromStreamAndReader( | |
| std::unique_ptr<SkStream>, | |
| rust::Box<rust_bmp::ResultOfReader>, | |
| StreamType, | |
| sk_sp<const SkData>, | |
| Result*); | |
| // We cannot use the SkCodec implementation since we pass nullptr to the superclass out of | |
| // an abundance of caution w/r to rewinding the stream. | |
| // | |
| // TODO(crbug.com/370522089): See if `SkCodec` can be tweaked to avoid | |
| // the need to hide the stream from it. | |
| sk_sp<const SkData> getEncodedData() const override; | |
| // Codec implementation | |
| Result onGetPixels(const SkImageInfo& info, | |
| void* dst, | |
| size_t dstRowStride, | |
| const Options& options, | |
| int* rowsDecoded) override; | |
| // Incremental decoding support | |
| bool onSupportsIncrementalDecode(const SkImageInfo&) override { return true; } | |
| Result onStartIncrementalDecode(const SkImageInfo& dstInfo, | |
| void* dst, | |
| size_t dstRowBytes, | |
| const Options&) override; | |
| Result onIncrementalDecode(int* rowsDecoded) override; | |
| // Helper methods | |
| Result performFullDecode(const SkImageInfo& dstInfo, void* dst, size_t dstRowStride); | |
| Result initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts); | |
| void swizzleRow(const uint8_t* srcRow, void* dstRow); | |
| // Build a codec from a metadata-loaded Reader. Extracts dimensions, color | |
| // info, and ICC profile from `reader`, validates the pixel format, and | |
| // constructs the codec. Sets `*result` to the appropriate status. | |
| static std::unique_ptr<SkBmpRustCodec> MakeFromReader(std::unique_ptr<SkStream> stream, | |
| rust::Box<rust_bmp::Reader> reader, | |
| StreamType streamType, | |
| sk_sp<const SkData> inMemoryData, | |
| Result* result); | |
| // Internal state for incremental decoding | |
| struct DecodingState { | |
| SkSpan<uint8_t> fDst; | |
| size_t fDstRowStride; | |
| int fTotalRowsDecoded = 0; // Accumulated count of rows decoded | |
| }; | |
| Result incrementalDecode(DecodingState& state, int* rowsDecoded); | |
| std::optional<DecodingState> fIncrementalDecodingState; | |
| rust::Box<rust_bmp::Reader> fReader; | |
| std::unique_ptr<SkStream> fPrivStream; | |
| sk_sp<const SkData> fInMemoryData; | |
| std::unique_ptr<SkSwizzler> fSwizzler; | |
| // Whether this codec was created from a standalone BMP or a BMP embedded in | |
| // an ICO stream. | |
| const StreamType fStreamType; | |
| // Using 4-bytes-wide `uint32_t` for each pixel, because | |
| // `kXformSrcColorType = kRGBA_8888_SkColorType`. | |
| std::unique_ptr<uint32_t[]> fXformBuffer; | |
| }; | |
| #endif // SkBmpRustCodec_DEFINED |