forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dl_path.cc
171 lines (146 loc) · 5.04 KB
/
dl_path.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/display_list/geometry/dl_path.h"
#include "flutter/display_list/geometry/dl_geometry_types.h"
#include "flutter/impeller/geometry/path_builder.h"
#include "impeller/geometry/path.h"
namespace flutter {
const SkPath& DlPath::GetSkPath() const {
return data_->sk_path;
}
impeller::Path DlPath::GetPath() const {
if (!data_->path.has_value()) {
data_->path = ConvertToImpellerPath(data_->sk_path);
}
// Covered by check above.
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
return data_->path.value();
}
void DlPath::WillRenderSkPath() const {
if (data_->render_count >= kMaxVolatileUses) {
data_->sk_path.setIsVolatile(false);
} else {
data_->render_count++;
}
}
bool DlPath::IsInverseFillType() const {
return data_->sk_path.isInverseFillType();
}
bool DlPath::IsRect(DlRect* rect, bool* is_closed) const {
return data_->sk_path.isRect(ToSkRect(rect), is_closed);
}
bool DlPath::IsOval(DlRect* bounds) const {
return data_->sk_path.isOval(ToSkRect(bounds));
}
bool DlPath::IsSkRect(SkRect* rect, bool* is_closed) const {
return data_->sk_path.isRect(rect, is_closed);
}
bool DlPath::IsSkOval(SkRect* bounds) const {
return data_->sk_path.isOval(bounds);
}
bool DlPath::IsSkRRect(SkRRect* rrect) const {
return data_->sk_path.isRRect(rrect);
}
SkRect DlPath::GetSkBounds() const {
return data_->sk_path.getBounds();
}
DlRect DlPath::GetBounds() const {
return ToDlRect(data_->sk_path.getBounds());
}
bool DlPath::operator==(const DlPath& other) const {
return data_->sk_path == other.data_->sk_path;
}
bool DlPath::IsConverted() const {
return data_->path.has_value();
}
bool DlPath::IsVolatile() const {
return data_->sk_path.isVolatile();
}
using Path = impeller::Path;
using PathBuilder = impeller::PathBuilder;
using FillType = impeller::FillType;
using Convexity = impeller::Convexity;
Path DlPath::ConvertToImpellerPath(const SkPath& path, const DlPoint& shift) {
if (path.isEmpty()) {
return impeller::Path{};
}
auto iterator = SkPath::Iter(path, false);
struct PathData {
union {
SkPoint points[4];
};
};
PathBuilder builder;
PathData data;
// Reserve a path size with some arbitrarily additional padding.
builder.Reserve(path.countPoints() + 8, path.countVerbs() + 8);
auto verb = SkPath::Verb::kDone_Verb;
do {
verb = iterator.next(data.points);
switch (verb) {
case SkPath::kMove_Verb:
builder.MoveTo(ToDlPoint(data.points[0]));
break;
case SkPath::kLine_Verb:
builder.LineTo(ToDlPoint(data.points[1]));
break;
case SkPath::kQuad_Verb:
builder.QuadraticCurveTo(ToDlPoint(data.points[1]),
ToDlPoint(data.points[2]));
break;
case SkPath::kConic_Verb: {
constexpr auto kPow2 = 1; // Only works for sweeps up to 90 degrees.
constexpr auto kQuadCount = 1 + (2 * (1 << kPow2));
SkPoint points[kQuadCount];
const auto curve_count =
SkPath::ConvertConicToQuads(data.points[0], //
data.points[1], //
data.points[2], //
iterator.conicWeight(), //
points, //
kPow2 //
);
for (int curve_index = 0, point_index = 0; //
curve_index < curve_count; //
curve_index++, point_index += 2 //
) {
builder.QuadraticCurveTo(ToDlPoint(points[point_index + 1]),
ToDlPoint(points[point_index + 2]));
}
} break;
case SkPath::kCubic_Verb:
builder.CubicCurveTo(ToDlPoint(data.points[1]),
ToDlPoint(data.points[2]),
ToDlPoint(data.points[3]));
break;
case SkPath::kClose_Verb:
builder.Close();
break;
case SkPath::kDone_Verb:
break;
}
} while (verb != SkPath::Verb::kDone_Verb);
FillType fill_type;
switch (path.getFillType()) {
case SkPathFillType::kWinding:
fill_type = FillType::kNonZero;
break;
case SkPathFillType::kEvenOdd:
fill_type = FillType::kOdd;
break;
case SkPathFillType::kInverseWinding:
case SkPathFillType::kInverseEvenOdd:
// Flutter doesn't expose these path fill types. These are only visible
// via the receiver interface. We should never get here.
fill_type = FillType::kNonZero;
break;
}
builder.SetConvexity(path.isConvex() ? Convexity::kConvex
: Convexity::kUnknown);
builder.Shift(shift);
auto sk_bounds = path.getBounds().makeOutset(shift.x, shift.y);
builder.SetBounds(ToDlRect(sk_bounds));
return builder.TakePath(fill_type);
}
} // namespace flutter