Avi Drissman | 0987565 | 2022-09-15 20:03:19 | [diff] [blame] | 1 | // Copyright 2018 The Chromium Authors |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Miyoung Shin | 40adbd6 | 2019-07-30 07:33:40 | [diff] [blame] | 5 | #include "skia/public/mojom/image_info_mojom_traits.h" |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 6 | |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 7 | #include "base/notreached.h" |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 8 | #include "base/numerics/checked_math.h" |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 9 | #include "base/numerics/safe_conversions.h" |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 10 | #include "mojo/public/cpp/bindings/array_data_view.h" |
Anton Bikineev | 3ac3d30 | 2021-05-15 17:54:01 | [diff] [blame] | 11 | #include "third_party/abseil-cpp/absl/types/optional.h" |
Kevin Lubick | 040667a | 2022-04-07 13:49:03 | [diff] [blame] | 12 | #include "third_party/skia/include/core/SkColorSpace.h" |
Kevin Lubick | efd439a | 2022-07-11 13:50:45 | [diff] [blame] | 13 | #include "third_party/skia/modules/skcms/skcms.h" |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 14 | |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 15 | namespace mojo { |
| 16 | |
danakj | 630f1ca | 2020-11-19 19:49:47 | [diff] [blame] | 17 | namespace { |
| 18 | |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 19 | absl::optional<SkImageInfo> MakeSkImageInfo( |
| 20 | SkColorType color_type, |
| 21 | SkAlphaType alpha_type, |
| 22 | int width, |
| 23 | int height, |
| 24 | mojo::ArrayDataView<float> color_transfer_function, |
| 25 | mojo::ArrayDataView<float> color_to_xyz_matrix) { |
| 26 | if (width < 0 || height < 0) { |
| 27 | return absl::nullopt; |
| 28 | } |
danakj | 630f1ca | 2020-11-19 19:49:47 | [diff] [blame] | 29 | sk_sp<SkColorSpace> color_space; |
| 30 | if (!color_transfer_function.is_null() && !color_to_xyz_matrix.is_null()) { |
| 31 | const float* data = color_transfer_function.data(); |
| 32 | skcms_TransferFunction transfer_function; |
danakj | 12e3650 | 2023-05-04 22:02:28 | [diff] [blame] | 33 | // TODO(crbug.com/1394542): Mojo should validate this array size. We can CHECK it instead |
| 34 | // when it does. |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 35 | if (color_transfer_function.size() != 7u) { |
| 36 | return absl::nullopt; |
| 37 | } |
danakj | 630f1ca | 2020-11-19 19:49:47 | [diff] [blame] | 38 | transfer_function.g = data[0]; |
| 39 | transfer_function.a = data[1]; |
| 40 | transfer_function.b = data[2]; |
| 41 | transfer_function.c = data[3]; |
| 42 | transfer_function.d = data[4]; |
| 43 | transfer_function.e = data[5]; |
| 44 | transfer_function.f = data[6]; |
| 45 | |
| 46 | skcms_Matrix3x3 to_xyz_matrix; |
danakj | 12e3650 | 2023-05-04 22:02:28 | [diff] [blame] | 47 | // TODO(crbug.com/1394542): Mojo should validate this array size. We can CHECK it instead |
| 48 | // when it does. |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 49 | if (color_to_xyz_matrix.size() != 9u) { |
| 50 | return absl::nullopt; |
| 51 | } |
danakj | 630f1ca | 2020-11-19 19:49:47 | [diff] [blame] | 52 | memcpy(to_xyz_matrix.vals, color_to_xyz_matrix.data(), 9 * sizeof(float)); |
| 53 | color_space = SkColorSpace::MakeRGB(transfer_function, to_xyz_matrix); |
| 54 | } |
| 55 | |
| 56 | return SkImageInfo::Make(width, height, color_type, alpha_type, |
| 57 | std::move(color_space)); |
| 58 | } |
| 59 | |
| 60 | } // namespace |
| 61 | |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 62 | // static |
| 63 | skia::mojom::AlphaType EnumTraits<skia::mojom::AlphaType, SkAlphaType>::ToMojom( |
| 64 | SkAlphaType type) { |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 65 | switch (type) { |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 66 | case kOpaque_SkAlphaType: |
| 67 | return skia::mojom::AlphaType::ALPHA_TYPE_OPAQUE; |
| 68 | case kPremul_SkAlphaType: |
| 69 | return skia::mojom::AlphaType::PREMUL; |
| 70 | case kUnpremul_SkAlphaType: |
| 71 | return skia::mojom::AlphaType::UNPREMUL; |
Alex Gough | 405dd51 | 2022-05-02 19:23:38 | [diff] [blame] | 72 | case kUnknown_SkAlphaType: |
| 73 | // Unknown types should not be sent over mojo. |
| 74 | break; |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 75 | } |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 76 | NOTREACHED_NORETURN(); |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 77 | } |
| 78 | |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 79 | // static |
| 80 | bool EnumTraits<skia::mojom::AlphaType, SkAlphaType>::FromMojom( |
| 81 | skia::mojom::AlphaType in, |
| 82 | SkAlphaType* out) { |
| 83 | switch (in) { |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 84 | case skia::mojom::AlphaType::ALPHA_TYPE_OPAQUE: |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 85 | *out = kOpaque_SkAlphaType; |
| 86 | return true; |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 87 | case skia::mojom::AlphaType::PREMUL: |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 88 | *out = kPremul_SkAlphaType; |
| 89 | return true; |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 90 | case skia::mojom::AlphaType::UNPREMUL: |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 91 | *out = kUnpremul_SkAlphaType; |
| 92 | return true; |
Alex Gough | 405dd51 | 2022-05-02 19:23:38 | [diff] [blame] | 93 | case skia::mojom::AlphaType::UNKNOWN: |
| 94 | // Unknown types should not be sent over mojo. |
| 95 | return false; |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 96 | } |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 97 | return false; |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 98 | } |
| 99 | |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 100 | // static |
| 101 | skia::mojom::ColorType EnumTraits<skia::mojom::ColorType, SkColorType>::ToMojom( |
| 102 | SkColorType type) { |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 103 | switch (type) { |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 104 | case kAlpha_8_SkColorType: |
| 105 | return skia::mojom::ColorType::ALPHA_8; |
| 106 | case kRGB_565_SkColorType: |
| 107 | return skia::mojom::ColorType::RGB_565; |
| 108 | case kARGB_4444_SkColorType: |
| 109 | return skia::mojom::ColorType::ARGB_4444; |
| 110 | case kRGBA_8888_SkColorType: |
| 111 | return skia::mojom::ColorType::RGBA_8888; |
| 112 | case kBGRA_8888_SkColorType: |
| 113 | return skia::mojom::ColorType::BGRA_8888; |
| 114 | case kGray_8_SkColorType: |
| 115 | return skia::mojom::ColorType::GRAY_8; |
Alex Gough | 405dd51 | 2022-05-02 19:23:38 | [diff] [blame] | 116 | case kUnknown_SkColorType: |
| 117 | // Fall through as unknown values should not be sent over the wire. |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 118 | default: |
| 119 | // Skia has color types not used by Chrome. |
| 120 | break; |
| 121 | } |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 122 | NOTREACHED_NORETURN(); |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 123 | } |
| 124 | |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 125 | // static |
| 126 | bool EnumTraits<skia::mojom::ColorType, SkColorType>::FromMojom( |
| 127 | skia::mojom::ColorType in, |
| 128 | SkColorType* out) { |
| 129 | switch (in) { |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 130 | case skia::mojom::ColorType::ALPHA_8: |
| 131 | *out = kAlpha_8_SkColorType; |
| 132 | return true; |
| 133 | case skia::mojom::ColorType::RGB_565: |
| 134 | *out = kRGB_565_SkColorType; |
| 135 | return true; |
| 136 | case skia::mojom::ColorType::ARGB_4444: |
| 137 | *out = kARGB_4444_SkColorType; |
| 138 | return true; |
| 139 | case skia::mojom::ColorType::RGBA_8888: |
| 140 | *out = kRGBA_8888_SkColorType; |
| 141 | return true; |
| 142 | case skia::mojom::ColorType::BGRA_8888: |
| 143 | *out = kBGRA_8888_SkColorType; |
| 144 | return true; |
| 145 | case skia::mojom::ColorType::GRAY_8: |
| 146 | *out = kGray_8_SkColorType; |
| 147 | return true; |
| 148 | case skia::mojom::ColorType::DEPRECATED_INDEX_8: |
Alex Gough | 405dd51 | 2022-05-02 19:23:38 | [diff] [blame] | 149 | case skia::mojom::ColorType::UNKNOWN: |
| 150 | // UNKNOWN or unsupported values should not be sent over mojo. |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 151 | break; |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 152 | } |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 153 | return false; |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 154 | } |
| 155 | |
| 156 | // static |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 157 | uint32_t StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo>::width( |
| 158 | const SkImageInfo& info) { |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 159 | // Negative width images are invalid. |
| 160 | return base::checked_cast<uint32_t>(info.width()); |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | // static |
| 164 | uint32_t StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo>::height( |
| 165 | const SkImageInfo& info) { |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 166 | // Negative height images are invalid. |
| 167 | return base::checked_cast<uint32_t>(info.height()); |
| 168 | } |
| 169 | |
| 170 | // static |
Anton Bikineev | 3ac3d30 | 2021-05-15 17:54:01 | [diff] [blame] | 171 | absl::optional<std::vector<float>> |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 172 | StructTraits<skia::mojom::ImageInfoDataView, |
| 173 | SkImageInfo>::color_transfer_function(const SkImageInfo& info) { |
| 174 | SkColorSpace* color_space = info.colorSpace(); |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 175 | if (!color_space) { |
Anton Bikineev | 3ac3d30 | 2021-05-15 17:54:01 | [diff] [blame] | 176 | return absl::nullopt; |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 177 | } |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 178 | skcms_TransferFunction fn; |
| 179 | color_space->transferFn(&fn); |
| 180 | return std::vector<float>({fn.g, fn.a, fn.b, fn.c, fn.d, fn.e, fn.f}); |
| 181 | } |
| 182 | |
| 183 | // static |
Anton Bikineev | 3ac3d30 | 2021-05-15 17:54:01 | [diff] [blame] | 184 | absl::optional<std::vector<float>> |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 185 | StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo>::color_to_xyz_matrix( |
| 186 | const SkImageInfo& info) { |
| 187 | SkColorSpace* color_space = info.colorSpace(); |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 188 | if (!color_space) { |
Anton Bikineev | 3ac3d30 | 2021-05-15 17:54:01 | [diff] [blame] | 189 | return absl::nullopt; |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 190 | } |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 191 | skcms_Matrix3x3 to_xyz_matrix; |
| 192 | CHECK(color_space->toXYZD50(&to_xyz_matrix)); |
| 193 | |
| 194 | // C-style arrays-of-arrays are tightly packed, so directly copy into vector. |
| 195 | static_assert(sizeof(to_xyz_matrix.vals) == sizeof(float) * 9, |
| 196 | "matrix must be 3x3 floats"); |
| 197 | float* values = &to_xyz_matrix.vals[0][0]; |
| 198 | return std::vector<float>(values, values + 9); |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | // static |
| 202 | bool StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo>::Read( |
| 203 | skia::mojom::ImageInfoDataView data, |
| 204 | SkImageInfo* info) { |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 205 | SkColorType color_type; |
| 206 | SkAlphaType alpha_type; |
| 207 | |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 208 | if (!data.ReadColorType(&color_type) || !data.ReadAlphaType(&alpha_type)) { |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 209 | return false; |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 210 | } |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 211 | |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 212 | mojo::ArrayDataView<float> color_transfer_function; |
| 213 | data.GetColorTransferFunctionDataView(&color_transfer_function); |
| 214 | mojo::ArrayDataView<float> color_to_xyz_matrix; |
| 215 | data.GetColorToXyzMatrixDataView(&color_to_xyz_matrix); |
| 216 | |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 217 | // The ImageInfo wire types are uint32_t, but the Skia type uses int, and the |
| 218 | // values can't be negative. |
| 219 | auto width = base::MakeCheckedNum(data.width()).Cast<int>(); |
| 220 | auto height = base::MakeCheckedNum(data.height()).Cast<int>(); |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 221 | if (!width.IsValid() || !height.IsValid()) { |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 222 | return false; |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 223 | } |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 224 | |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 225 | absl::optional<SkImageInfo> maybe_info = MakeSkImageInfo( |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 226 | color_type, alpha_type, width.ValueOrDie(), height.ValueOrDie(), |
| 227 | std::move(color_transfer_function), std::move(color_to_xyz_matrix)); |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 228 | if (!maybe_info.has_value()) { |
| 229 | return false; |
| 230 | } |
| 231 | *info = *maybe_info; |
danakj | 630f1ca | 2020-11-19 19:49:47 | [diff] [blame] | 232 | return true; |
| 233 | } |
| 234 | |
| 235 | // static |
| 236 | bool StructTraits<skia::mojom::BitmapN32ImageInfoDataView, SkImageInfo>::Read( |
| 237 | skia::mojom::BitmapN32ImageInfoDataView data, |
| 238 | SkImageInfo* info) { |
| 239 | SkAlphaType alpha_type; |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 240 | if (!data.ReadAlphaType(&alpha_type)) { |
Daniel Cheng | 212e520 | 2020-11-07 01:16:48 | [diff] [blame] | 241 | return false; |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 242 | } |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 243 | |
danakj | 630f1ca | 2020-11-19 19:49:47 | [diff] [blame] | 244 | mojo::ArrayDataView<float> color_transfer_function; |
| 245 | data.GetColorTransferFunctionDataView(&color_transfer_function); |
| 246 | mojo::ArrayDataView<float> color_to_xyz_matrix; |
| 247 | data.GetColorToXyzMatrixDataView(&color_to_xyz_matrix); |
James Cook | 862440f3 | 2020-08-31 19:55:44 | [diff] [blame] | 248 | |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 249 | // The ImageInfo wire types are uint32_t, but the Skia type uses int, and the |
| 250 | // values can't be negative. |
| 251 | auto width = base::MakeCheckedNum(data.width()).Cast<int>(); |
| 252 | auto height = base::MakeCheckedNum(data.height()).Cast<int>(); |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 253 | if (!width.IsValid() || !height.IsValid()) { |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 254 | return false; |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 255 | } |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 256 | |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 257 | absl::optional<SkImageInfo> maybe_info = MakeSkImageInfo( |
danakj | d9c2783 | 2022-04-26 22:05:08 | [diff] [blame] | 258 | kN32_SkColorType, alpha_type, width.ValueOrDie(), height.ValueOrDie(), |
| 259 | std::move(color_transfer_function), std::move(color_to_xyz_matrix)); |
danakj | f699367 | 2023-05-04 18:15:30 | [diff] [blame] | 260 | if (!maybe_info.has_value()) { |
| 261 | return false; |
| 262 | } |
| 263 | *info = *maybe_info; |
Saman Sami | e4d5f8a | 2018-04-13 19:58:19 | [diff] [blame] | 264 | return true; |
| 265 | } |
| 266 | |
| 267 | } // namespace mojo |