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
19namespace flutter {
20
21// Indices for 32bit values.
22constexpr int kIsAntiAliasIndex = 0;
23constexpr int kColorIndex = 1;
24constexpr int kBlendModeIndex = 2;
25constexpr int kStyleIndex = 3;
26constexpr int kStrokeWidthIndex = 4;
27constexpr int kStrokeCapIndex = 5;
28constexpr int kStrokeJoinIndex = 6;
29constexpr int kStrokeMiterLimitIndex = 7;
30constexpr int kFilterQualityIndex = 8;
31constexpr int kMaskFilterIndex = 9;
32constexpr int kMaskFilterBlurStyleIndex = 10;
33constexpr int kMaskFilterSigmaIndex = 11;
34constexpr int kInvertColorIndex = 12;
35constexpr int kDitherIndex = 13;
36constexpr size_t kDataByteCount = 56; // 4 * (last index + 1)
37
38// Indices for objects.
39constexpr int kShaderIndex = 0;
40constexpr int kColorFilterIndex = 1;
41constexpr int kImageFilterIndex = 2;
42constexpr int kObjectCount = 3; // One larger than largest object index.
43
44// Must be kept in sync with the default in painting.dart.
45constexpr uint32_t kColorDefault = 0xFF000000;
46
47// Must be kept in sync with the default in painting.dart.
48constexpr 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).
53constexpr double kStrokeMiterLimitDefault = 4.0;
54
55// A color matrix which inverts colors.
56// clang-format off
57constexpr 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.
66enum MaskFilterType { Null, Blur };
67
68Paint::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
185namespace tonic {
186
187flutter::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
200flutter::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