1 | // Copyright 2013 The Flutter 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 "flutter/lib/ui/painting/paint.h" |
6 | |
7 | #include "flutter/fml/logging.h" |
8 | #include "flutter/lib/ui/painting/color_filter.h" |
9 | #include "flutter/lib/ui/painting/image_filter.h" |
10 | #include "flutter/lib/ui/painting/shader.h" |
11 | #include "third_party/skia/include/core/SkColorFilter.h" |
12 | #include "third_party/skia/include/core/SkImageFilter.h" |
13 | #include "third_party/skia/include/core/SkMaskFilter.h" |
14 | #include "third_party/skia/include/core/SkShader.h" |
15 | #include "third_party/skia/include/core/SkString.h" |
16 | #include "third_party/tonic/typed_data/dart_byte_data.h" |
17 | #include "third_party/tonic/typed_data/typed_list.h" |
18 | |
19 | namespace flutter { |
20 | |
21 | // Indices for 32bit values. |
22 | constexpr int kIsAntiAliasIndex = 0; |
23 | constexpr int kColorIndex = 1; |
24 | constexpr int kBlendModeIndex = 2; |
25 | constexpr int kStyleIndex = 3; |
26 | constexpr int kStrokeWidthIndex = 4; |
27 | constexpr int kStrokeCapIndex = 5; |
28 | constexpr int kStrokeJoinIndex = 6; |
29 | constexpr int kStrokeMiterLimitIndex = 7; |
30 | constexpr int kFilterQualityIndex = 8; |
31 | constexpr int kMaskFilterIndex = 9; |
32 | constexpr int kMaskFilterBlurStyleIndex = 10; |
33 | constexpr int kMaskFilterSigmaIndex = 11; |
34 | constexpr int kInvertColorIndex = 12; |
35 | constexpr int kDitherIndex = 13; |
36 | constexpr size_t kDataByteCount = 56; // 4 * (last index + 1) |
37 | |
38 | // Indices for objects. |
39 | constexpr int kShaderIndex = 0; |
40 | constexpr int kColorFilterIndex = 1; |
41 | constexpr int kImageFilterIndex = 2; |
42 | constexpr int kObjectCount = 3; // One larger than largest object index. |
43 | |
44 | // Must be kept in sync with the default in painting.dart. |
45 | constexpr uint32_t kColorDefault = 0xFF000000; |
46 | |
47 | // Must be kept in sync with the default in painting.dart. |
48 | constexpr uint32_t kBlendModeDefault = |
49 | static_cast<uint32_t>(SkBlendMode::kSrcOver); |
50 | |
51 | // Must be kept in sync with the default in painting.dart, and also with the |
52 | // default SkPaintDefaults_MiterLimit in Skia (which is not in a public header). |
53 | constexpr double kStrokeMiterLimitDefault = 4.0; |
54 | |
55 | // A color matrix which inverts colors. |
56 | // clang-format off |
57 | constexpr float invert_colors[20] = { |
58 | -1.0, 0, 0, 1.0, 0, |
59 | 0, -1.0, 0, 1.0, 0, |
60 | 0, 0, -1.0, 1.0, 0, |
61 | 1.0, 1.0, 1.0, 1.0, 0 |
62 | }; |
63 | // clang-format on |
64 | |
65 | // Must be kept in sync with the MaskFilter private constants in painting.dart. |
66 | enum MaskFilterType { Null, Blur }; |
67 | |
68 | Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) { |
69 | is_null_ = Dart_IsNull(paint_data); |
70 | if (is_null_) { |
71 | return; |
72 | } |
73 | |
74 | Dart_Handle values[kObjectCount]; |
75 | if (!Dart_IsNull(paint_objects)) { |
76 | FML_DCHECK(Dart_IsList(paint_objects)); |
77 | intptr_t length = 0; |
78 | Dart_ListLength(paint_objects, &length); |
79 | |
80 | FML_CHECK(length == kObjectCount); |
81 | if (Dart_IsError( |
82 | Dart_ListGetRange(paint_objects, 0, kObjectCount, values))) { |
83 | return; |
84 | } |
85 | |
86 | Dart_Handle shader = values[kShaderIndex]; |
87 | if (!Dart_IsNull(shader)) { |
88 | Shader* decoded = tonic::DartConverter<Shader*>::FromDart(shader); |
89 | paint_.setShader(decoded->shader()); |
90 | } |
91 | |
92 | Dart_Handle color_filter = values[kColorFilterIndex]; |
93 | if (!Dart_IsNull(color_filter)) { |
94 | ColorFilter* decoded_color_filter = |
95 | tonic::DartConverter<ColorFilter*>::FromDart(color_filter); |
96 | paint_.setColorFilter(decoded_color_filter->filter()); |
97 | } |
98 | |
99 | Dart_Handle image_filter = values[kImageFilterIndex]; |
100 | if (!Dart_IsNull(image_filter)) { |
101 | ImageFilter* decoded = |
102 | tonic::DartConverter<ImageFilter*>::FromDart(image_filter); |
103 | paint_.setImageFilter(decoded->filter()); |
104 | } |
105 | } |
106 | |
107 | tonic::DartByteData byte_data(paint_data); |
108 | FML_CHECK(byte_data.length_in_bytes() == kDataByteCount); |
109 | |
110 | const uint32_t* uint_data = static_cast<const uint32_t*>(byte_data.data()); |
111 | const float* float_data = static_cast<const float*>(byte_data.data()); |
112 | |
113 | paint_.setAntiAlias(uint_data[kIsAntiAliasIndex] == 0); |
114 | |
115 | uint32_t encoded_color = uint_data[kColorIndex]; |
116 | if (encoded_color) { |
117 | SkColor color = encoded_color ^ kColorDefault; |
118 | paint_.setColor(color); |
119 | } |
120 | |
121 | uint32_t encoded_blend_mode = uint_data[kBlendModeIndex]; |
122 | if (encoded_blend_mode) { |
123 | uint32_t blend_mode = encoded_blend_mode ^ kBlendModeDefault; |
124 | paint_.setBlendMode(static_cast<SkBlendMode>(blend_mode)); |
125 | } |
126 | |
127 | uint32_t style = uint_data[kStyleIndex]; |
128 | if (style) { |
129 | paint_.setStyle(static_cast<SkPaint::Style>(style)); |
130 | } |
131 | |
132 | float stroke_width = float_data[kStrokeWidthIndex]; |
133 | if (stroke_width != 0.0) { |
134 | paint_.setStrokeWidth(stroke_width); |
135 | } |
136 | |
137 | uint32_t stroke_cap = uint_data[kStrokeCapIndex]; |
138 | if (stroke_cap) { |
139 | paint_.setStrokeCap(static_cast<SkPaint::Cap>(stroke_cap)); |
140 | } |
141 | |
142 | uint32_t stroke_join = uint_data[kStrokeJoinIndex]; |
143 | if (stroke_join) { |
144 | paint_.setStrokeJoin(static_cast<SkPaint::Join>(stroke_join)); |
145 | } |
146 | |
147 | float stroke_miter_limit = float_data[kStrokeMiterLimitIndex]; |
148 | if (stroke_miter_limit != 0.0) { |
149 | paint_.setStrokeMiter(stroke_miter_limit + kStrokeMiterLimitDefault); |
150 | } |
151 | |
152 | uint32_t filter_quality = uint_data[kFilterQualityIndex]; |
153 | if (filter_quality) { |
154 | paint_.setFilterQuality(static_cast<SkFilterQuality>(filter_quality)); |
155 | } |
156 | |
157 | if (uint_data[kInvertColorIndex]) { |
158 | sk_sp<SkColorFilter> invert_filter = |
159 | ColorFilter::MakeColorMatrixFilter255(invert_colors); |
160 | sk_sp<SkColorFilter> current_filter = paint_.refColorFilter(); |
161 | if (current_filter) { |
162 | invert_filter = invert_filter->makeComposed(current_filter); |
163 | } |
164 | paint_.setColorFilter(invert_filter); |
165 | } |
166 | |
167 | if (uint_data[kDitherIndex]) { |
168 | paint_.setDither(true); |
169 | } |
170 | |
171 | switch (uint_data[kMaskFilterIndex]) { |
172 | case Null: |
173 | break; |
174 | case Blur: |
175 | SkBlurStyle blur_style = |
176 | static_cast<SkBlurStyle>(uint_data[kMaskFilterBlurStyleIndex]); |
177 | double sigma = float_data[kMaskFilterSigmaIndex]; |
178 | paint_.setMaskFilter(SkMaskFilter::MakeBlur(blur_style, sigma)); |
179 | break; |
180 | } |
181 | } |
182 | |
183 | } // namespace flutter |
184 | |
185 | namespace tonic { |
186 | |
187 | flutter::Paint DartConverter<flutter::Paint>::FromArguments( |
188 | Dart_NativeArguments args, |
189 | int index, |
190 | Dart_Handle& exception) { |
191 | Dart_Handle paint_objects = Dart_GetNativeArgument(args, index); |
192 | FML_DCHECK(!LogIfError(paint_objects)); |
193 | |
194 | Dart_Handle paint_data = Dart_GetNativeArgument(args, index + 1); |
195 | FML_DCHECK(!LogIfError(paint_data)); |
196 | |
197 | return flutter::Paint(paint_objects, paint_data); |
198 | } |
199 | |
200 | flutter::PaintData DartConverter<flutter::PaintData>::FromArguments( |
201 | Dart_NativeArguments args, |
202 | int index, |
203 | Dart_Handle& exception) { |
204 | return flutter::PaintData(); |
205 | } |
206 | |
207 | } // namespace tonic |
208 | |