xref: /aosp_15_r20/external/skia/experimental/rust_png/encoder/impl/SkPngRustEncoderImpl.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2024 Google LLC.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "experimental/rust_png/encoder/impl/SkPngRustEncoderImpl.h"
9 
10 #include <memory>
11 #include <utility>
12 
13 #include "experimental/rust_png/ffi/FFI.rs.h"
14 #include "experimental/rust_png/ffi/UtilsForFFI.h"
15 #include "include/core/SkSpan.h"
16 #include "include/core/SkStream.h"
17 #include "include/private/SkEncodedInfo.h"
18 #include "include/private/base/SkAssert.h"
19 #include "src/base/SkSafeMath.h"
20 #include "src/encode/SkImageEncoderPriv.h"
21 #include "third_party/rust/cxx/v1/cxx.h"
22 
23 #ifdef __clang__
24 #pragma clang diagnostic error "-Wconversion"
25 #endif
26 
27 namespace {
28 
ToColorType(SkEncodedInfo::Color color)29 rust_png::ColorType ToColorType(SkEncodedInfo::Color color) {
30     switch (color) {
31         case SkEncodedInfo::kRGB_Color:
32             return rust_png::ColorType::Rgb;
33         case SkEncodedInfo::kRGBA_Color:
34             return rust_png::ColorType::Rgba;
35         case SkEncodedInfo::kGray_Color:
36             return rust_png::ColorType::Grayscale;
37         case SkEncodedInfo::kGrayAlpha_Color:
38             return rust_png::ColorType::GrayscaleAlpha;
39         default:
40             SkUNREACHABLE;
41     }
42 }
43 
44 // This helper class adapts `SkWStream` to expose the API required by Rust FFI
45 // (i.e. the `WriteTrait` API).
46 class WriteTraitAdapterForSkWStream final : public rust_png::WriteTrait {
47 public:
48     // SAFETY: The caller needs to guarantee that `stream` will be alive for
49     // as long as `WriteTraitAdapterForSkWStream`.
WriteTraitAdapterForSkWStream(SkWStream * stream)50     explicit WriteTraitAdapterForSkWStream(SkWStream* stream) : fStream(stream) {
51         SkASSERT(fStream);
52     }
53 
54     ~WriteTraitAdapterForSkWStream() override = default;
55 
56     // Non-copyable and non-movable.
57     WriteTraitAdapterForSkWStream(const WriteTraitAdapterForSkWStream&) = delete;
58     WriteTraitAdapterForSkWStream& operator=(const WriteTraitAdapterForSkWStream&) = delete;
59     WriteTraitAdapterForSkWStream(WriteTraitAdapterForSkWStream&&) = delete;
60     WriteTraitAdapterForSkWStream& operator=(WriteTraitAdapterForSkWStream&&) = delete;
61 
62     // Implementation of the `std::io::Read::read` method.  See `RustTrait`'s
63     // doc comments and
64     // https://doc.rust-lang.org/nightly/std/io/trait.Read.html#tymethod.read
65     // for guidance on the desired implementation and behavior of this method.
write(rust::Slice<const uint8_t> buffer)66     bool write(rust::Slice<const uint8_t> buffer) override {
67         SkSpan<const uint8_t> span = ToSkSpan(buffer);
68         return fStream->write(span.data(), span.size());
69     }
70 
flush()71     void flush() override { fStream->flush(); }
72 
73 private:
74     SkWStream* fStream = nullptr;  // Non-owning pointer.
75 };
76 
77 }  // namespace
78 
79 // static
Make(SkWStream * dst,const SkPixmap & src)80 std::unique_ptr<SkEncoder> SkPngRustEncoderImpl::Make(SkWStream* dst, const SkPixmap& src) {
81     if (!SkPixmapIsValid(src)) {
82         return nullptr;
83     }
84 
85     std::optional<TargetInfo> maybeTargetInfo = SkPngEncoderBase::getTargetInfo(src.info());
86     if (!maybeTargetInfo.has_value()) {
87         return nullptr;
88     }
89     const SkEncodedInfo& dstInfo = maybeTargetInfo->fDstInfo;
90 
91     SkSafeMath safe;
92     uint32_t width = safe.castTo<uint32_t>(dstInfo.width());
93     uint32_t height = safe.castTo<uint32_t>(dstInfo.height());
94     if (!safe.ok()) {
95         return nullptr;
96     }
97 
98     auto writeTraitAdapter = std::make_unique<WriteTraitAdapterForSkWStream>(dst);
99     rust::Box<rust_png::ResultOfStreamWriter> resultOfStreamWriter =
100             rust_png::new_stream_writer(std::move(writeTraitAdapter),
101                                         width,
102                                         height,
103                                         ToColorType(dstInfo.color()),
104                                         dstInfo.bitsPerComponent());
105     if (resultOfStreamWriter->err() != rust_png::EncodingResult::Success) {
106         return nullptr;
107     }
108     rust::Box<rust_png::StreamWriter> stream_writer = resultOfStreamWriter->unwrap();
109 
110     return std::make_unique<SkPngRustEncoderImpl>(
111             std::move(*maybeTargetInfo), src, std::move(stream_writer));
112 }
113 
SkPngRustEncoderImpl(TargetInfo targetInfo,const SkPixmap & src,rust::Box<rust_png::StreamWriter> stream_writer)114 SkPngRustEncoderImpl::SkPngRustEncoderImpl(TargetInfo targetInfo,
115                                            const SkPixmap& src,
116                                            rust::Box<rust_png::StreamWriter> stream_writer)
117         : SkPngEncoderBase(std::move(targetInfo), src), fStreamWriter(std::move(stream_writer)) {}
118 
119 SkPngRustEncoderImpl::~SkPngRustEncoderImpl() = default;
120 
onEncodeRow(SkSpan<const uint8_t> row)121 bool SkPngRustEncoderImpl::onEncodeRow(SkSpan<const uint8_t> row) {
122     return fStreamWriter->write(rust::Slice<const uint8_t>(row)) ==
123            rust_png::EncodingResult::Success;
124 }
125 
onFinishEncoding()126 bool SkPngRustEncoderImpl::onFinishEncoding() {
127     return rust_png::finish_encoding(std::move(fStreamWriter)) == rust_png::EncodingResult::Success;
128 }
129