1 // Copyright 2017 The Chromium Authors. All rights reserved.
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 "third_party/blink/renderer/platform/graphics/canvas_color_params.h"
6 
7 #include "cc/paint/skia_paint_canvas.h"
8 #include "components/viz/common/resources/resource_format_utils.h"
9 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
10 #include "third_party/khronos/GLES2/gl2.h"
11 #include "third_party/khronos/GLES2/gl2ext.h"
12 #include "third_party/khronos/GLES3/gl3.h"
13 #include "third_party/skia/include/core/SkSurfaceProps.h"
14 #include "ui/gfx/color_space.h"
15 
16 namespace blink {
17 
18 namespace {
19 
GetPrimaryID(CanvasColorSpace color_space)20 gfx::ColorSpace::PrimaryID GetPrimaryID(CanvasColorSpace color_space) {
21   gfx::ColorSpace::PrimaryID primary_id = gfx::ColorSpace::PrimaryID::BT709;
22   switch (color_space) {
23     case CanvasColorSpace::kSRGB:
24     case CanvasColorSpace::kLinearRGB:
25       primary_id = gfx::ColorSpace::PrimaryID::BT709;
26       break;
27     case CanvasColorSpace::kRec2020:
28       primary_id = gfx::ColorSpace::PrimaryID::BT2020;
29       break;
30     case CanvasColorSpace::kP3:
31       primary_id = gfx::ColorSpace::PrimaryID::SMPTEST432_1;
32       break;
33   }
34   return primary_id;
35 }
36 
37 }  // namespace
38 
39 CanvasColorParams::CanvasColorParams() = default;
40 
CanvasColorParams(CanvasColorSpace color_space,CanvasPixelFormat pixel_format,OpacityMode opacity_mode)41 CanvasColorParams::CanvasColorParams(CanvasColorSpace color_space,
42                                      CanvasPixelFormat pixel_format,
43                                      OpacityMode opacity_mode)
44     : color_space_(color_space),
45       pixel_format_(pixel_format),
46       opacity_mode_(opacity_mode) {}
47 
CanvasColorParams(const SkImageInfo & info)48 CanvasColorParams::CanvasColorParams(const SkImageInfo& info)
49     : CanvasColorParams(info.refColorSpace(), info.colorType()) {}
50 
GetSkColorSpaceForSkSurfaces() const51 sk_sp<SkColorSpace> CanvasColorParams::GetSkColorSpaceForSkSurfaces() const {
52   return GetSkColorSpace();
53 }
54 
NeedsColorConversion(const CanvasColorParams & dest_color_params) const55 bool CanvasColorParams::NeedsColorConversion(
56     const CanvasColorParams& dest_color_params) const {
57   if ((color_space_ == dest_color_params.ColorSpace() &&
58        pixel_format_ == dest_color_params.PixelFormat()))
59     return false;
60   return true;
61 }
62 
GetSkColorType() const63 SkColorType CanvasColorParams::GetSkColorType() const {
64   switch (pixel_format_) {
65     case CanvasPixelFormat::kF16:
66       return kRGBA_F16_SkColorType;
67     case CanvasPixelFormat::kRGBA8:
68       return kRGBA_8888_SkColorType;
69     case CanvasPixelFormat::kBGRA8:
70       return kBGRA_8888_SkColorType;
71   }
72   NOTREACHED();
73   return kN32_SkColorType;
74 }
75 
GetSkAlphaType() const76 SkAlphaType CanvasColorParams::GetSkAlphaType() const {
77   return opacity_mode_ == kOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
78 }
79 
GetSkSurfaceProps() const80 const SkSurfaceProps* CanvasColorParams::GetSkSurfaceProps() const {
81   static const SkSurfaceProps disable_lcd_props(0, kUnknown_SkPixelGeometry);
82   if (opacity_mode_ == kOpaque)
83     return nullptr;
84   return &disable_lcd_props;
85 }
86 
BytesPerPixel() const87 uint8_t CanvasColorParams::BytesPerPixel() const {
88   return SkColorTypeBytesPerPixel(GetSkColorType());
89 }
90 
GetSamplerGfxColorSpace() const91 gfx::ColorSpace CanvasColorParams::GetSamplerGfxColorSpace() const {
92   gfx::ColorSpace::PrimaryID primary_id = GetPrimaryID(color_space_);
93 
94   // TODO(ccameron): This needs to take into account whether or not this texture
95   // will be sampled in linear or nonlinear space.
96   gfx::ColorSpace::TransferID transfer_id =
97       gfx::ColorSpace::TransferID::IEC61966_2_1;
98   if (pixel_format_ == CanvasPixelFormat::kF16)
99     transfer_id = gfx::ColorSpace::TransferID::LINEAR_HDR;
100 
101   return gfx::ColorSpace(primary_id, transfer_id);
102 }
103 
GetStorageGfxColorSpace() const104 gfx::ColorSpace CanvasColorParams::GetStorageGfxColorSpace() const {
105   gfx::ColorSpace::PrimaryID primary_id = GetPrimaryID(color_space_);
106 
107   gfx::ColorSpace::TransferID transfer_id =
108       gfx::ColorSpace::TransferID::IEC61966_2_1;
109   // Only sRGB and e-sRGB use sRGB transfer function. Other canvas color spaces,
110   // i.e., linear-rgb, p3 and rec2020 use linear transfer function.
111   if (color_space_ != CanvasColorSpace::kSRGB)
112     transfer_id = gfx::ColorSpace::TransferID::LINEAR_HDR;
113 
114   return gfx::ColorSpace(primary_id, transfer_id);
115 }
116 
GetSkColorSpace() const117 sk_sp<SkColorSpace> CanvasColorParams::GetSkColorSpace() const {
118   static_assert(kN32_SkColorType == kRGBA_8888_SkColorType ||
119                     kN32_SkColorType == kBGRA_8888_SkColorType,
120                 "Unexpected kN32_SkColorType value.");
121   skcms_Matrix3x3 gamut = SkNamedGamut::kSRGB;
122   skcms_TransferFunction transferFn = SkNamedTransferFn::kSRGB;
123   switch (color_space_) {
124     case CanvasColorSpace::kSRGB:
125       break;
126     case CanvasColorSpace::kLinearRGB:
127       transferFn = SkNamedTransferFn::kLinear;
128       break;
129     case CanvasColorSpace::kRec2020:
130       gamut = SkNamedGamut::kRec2020;
131       transferFn = SkNamedTransferFn::kLinear;
132       break;
133     case CanvasColorSpace::kP3:
134       gamut = SkNamedGamut::kDCIP3;
135       transferFn = SkNamedTransferFn::kLinear;
136       break;
137   }
138   return SkColorSpace::MakeRGB(transferFn, gamut);
139 }
140 
GetBufferFormat() const141 gfx::BufferFormat CanvasColorParams::GetBufferFormat() const {
142   switch (GetSkColorType()) {
143     case kRGBA_8888_SkColorType:
144       return gfx::BufferFormat::RGBA_8888;
145     case kBGRA_8888_SkColorType:
146       return gfx::BufferFormat::BGRA_8888;
147     case kRGBA_F16_SkColorType:
148       return gfx::BufferFormat::RGBA_F16;
149     default:
150       NOTREACHED();
151   }
152 
153   return gfx::BufferFormat::RGBA_8888;
154 }
155 
GLUnsizedInternalFormat() const156 GLenum CanvasColorParams::GLUnsizedInternalFormat() const {
157   // TODO(junov): try GL_RGB when opacity_mode_ == kOpaque
158   switch (GetSkColorType()) {
159     case kRGBA_8888_SkColorType:
160       return GL_RGBA;
161     case kBGRA_8888_SkColorType:
162       return GL_BGRA_EXT;
163     case kRGBA_F16_SkColorType:
164       return GL_RGBA;
165     default:
166       NOTREACHED();
167   }
168 
169   return GL_RGBA;
170 }
171 
GLSizedInternalFormat() const172 GLenum CanvasColorParams::GLSizedInternalFormat() const {
173   switch (GetSkColorType()) {
174     case kRGBA_8888_SkColorType:
175       return GL_RGBA8;
176     case kBGRA_8888_SkColorType:
177       return GL_BGRA8_EXT;
178     case kRGBA_F16_SkColorType:
179       return GL_RGBA16F;
180     default:
181       NOTREACHED();
182   }
183 
184   return GL_RGBA8;
185 }
186 
GLType() const187 GLenum CanvasColorParams::GLType() const {
188   switch (GetSkColorType()) {
189     case kRGBA_8888_SkColorType:
190     case kBGRA_8888_SkColorType:
191       return GL_UNSIGNED_BYTE;
192     case kRGBA_F16_SkColorType:
193       return GL_HALF_FLOAT_OES;
194     default:
195       NOTREACHED();
196   }
197 
198   return GL_UNSIGNED_BYTE;
199 }
200 
TransferableResourceFormat() const201 viz::ResourceFormat CanvasColorParams::TransferableResourceFormat() const {
202   return viz::GetResourceFormat(GetBufferFormat());
203 }
204 
CanvasColorParams(const sk_sp<SkColorSpace> color_space,SkColorType color_type)205 CanvasColorParams::CanvasColorParams(const sk_sp<SkColorSpace> color_space,
206                                      SkColorType color_type) {
207   color_space_ = CanvasColorSpace::kSRGB;
208   pixel_format_ = GetNativeCanvasPixelFormat();
209   // When there is no color space information, the SkImage is in legacy mode and
210   // the color type is kRGBA8 canvas pixel format.
211   if (!color_space)
212     return;
213 
214   // CanvasColorSpace::kSRGB covers sRGB and e-sRGB. We need to check for
215   // linear-rgb, rec2020 and p3.
216   if (SkColorSpace::Equals(color_space.get(),
217                            SkColorSpace::MakeSRGB()->makeLinearGamma().get())) {
218     color_space_ = CanvasColorSpace::kLinearRGB;
219   } else if (SkColorSpace::Equals(
220                  color_space.get(),
221                  SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear,
222                                        SkNamedGamut::kRec2020)
223                      .get())) {
224     color_space_ = CanvasColorSpace::kRec2020;
225   } else if (SkColorSpace::Equals(
226                  color_space.get(),
227                  SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear,
228                                        SkNamedGamut::kDCIP3)
229                      .get())) {
230     color_space_ = CanvasColorSpace::kP3;
231   }
232 
233   if (color_type == kRGBA_F16_SkColorType)
234     pixel_format_ = CanvasPixelFormat::kF16;
235   else if (color_type == kRGBA_8888_SkColorType)
236     pixel_format_ = CanvasPixelFormat::kRGBA8;
237 }
238 
239 }  // namespace blink
240