Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions engine/src/flutter/display_list/geometry/dl_geometry_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ inline const SkPoint* ToSkPoints(const DlPoint* points) {
return points == nullptr ? nullptr : reinterpret_cast<const SkPoint*>(points);
}

inline SkPoint* ToSkPoints(DlPoint* points) {
return points == nullptr ? nullptr : reinterpret_cast<SkPoint*>(points);
}

inline const SkRect& ToSkRect(const DlRect& rect) {
return *reinterpret_cast<const SkRect*>(&rect);
}
Expand Down
80 changes: 43 additions & 37 deletions engine/src/flutter/display_list/geometry/dl_path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,39 +265,46 @@ SkPath DlPath::ConvertToSkiaPath(const Path& path, const DlPoint& shift) {
}
};

size_t count = path.GetComponentCount();
for (size_t i = 0; i < count; i++) {
switch (path.GetComponentTypeAtIndex(i)) {
for (auto it = path.begin(), end = path.end(); it != end; ++it) {
switch (it.type()) {
case ComponentType::kContour: {
impeller::ContourComponent contour;
path.GetContourComponentAtIndex(i, contour);
const impeller::ContourComponent* contour = it.contour();
FML_DCHECK(contour != nullptr);
if (subpath_needs_close) {
sk_path.close();
}
pending_moveto = contour.destination;
subpath_needs_close = contour.IsClosed();
pending_moveto = contour->destination;
subpath_needs_close = contour->IsClosed();
break;
}
case ComponentType::kLinear: {
impeller::LinearPathComponent linear;
path.GetLinearComponentAtIndex(i, linear);
const impeller::LinearPathComponent* linear = it.linear();
FML_DCHECK(linear != nullptr);
resolve_moveto();
sk_path.lineTo(ToSkPoint(linear.p2));
sk_path.lineTo(ToSkPoint(linear->p2));
break;
}
case ComponentType::kQuadratic: {
impeller::QuadraticPathComponent quadratic;
path.GetQuadraticComponentAtIndex(i, quadratic);
const impeller::QuadraticPathComponent* quadratic = it.quadratic();
FML_DCHECK(quadratic != nullptr);
resolve_moveto();
sk_path.quadTo(ToSkPoint(quadratic.cp), ToSkPoint(quadratic.p2));
sk_path.quadTo(ToSkPoint(quadratic->cp), ToSkPoint(quadratic->p2));
break;
}
case ComponentType::kConic: {
const impeller::ConicPathComponent* conic = it.conic();
FML_DCHECK(conic != nullptr);
resolve_moveto();
sk_path.conicTo(ToSkPoint(conic->cp), ToSkPoint(conic->p2),
conic->weight.x);
break;
}
case ComponentType::kCubic: {
impeller::CubicPathComponent cubic;
path.GetCubicComponentAtIndex(i, cubic);
const impeller::CubicPathComponent* cubic = it.cubic();
FML_DCHECK(cubic != nullptr);
resolve_moveto();
sk_path.cubicTo(ToSkPoint(cubic.cp1), ToSkPoint(cubic.cp2),
ToSkPoint(cubic.p2));
sk_path.cubicTo(ToSkPoint(cubic->cp1), ToSkPoint(cubic->cp2),
ToSkPoint(cubic->p2));
break;
}
}
Expand Down Expand Up @@ -339,27 +346,26 @@ Path DlPath::ConvertToImpellerPath(const SkPath& path, const DlPoint& shift) {
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]));
case SkPath::kConic_Verb:
// We might eventually have conic conversion math that deals with
// degenerate conics gracefully (or just handle them directly),
// but until then, we will detect and ignore them.
if (data.points[0] != data.points[1]) {
if (data.points[1] != data.points[2]) {
std::array<DlPoint, 5> points;
impeller::ConicPathComponent conic(
ToDlPoint(data.points[0]), ToDlPoint(data.points[1]),
ToDlPoint(data.points[2]), iterator.conicWeight());
conic.SubdivideToQuadraticPoints(points);
builder.QuadraticCurveTo(points[1], points[2]);
builder.QuadraticCurveTo(points[3], points[4]);
} else {
builder.LineTo(ToDlPoint(data.points[1]));
}
} else if (data.points[1] != data.points[2]) {
builder.LineTo(ToDlPoint(data.points[2]));
}
} break;
break;
case SkPath::kCubic_Verb:
builder.CubicCurveTo(ToDlPoint(data.points[1]),
ToDlPoint(data.points[2]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "flutter/display_list/effects/dl_color_sources.h"
#include "flutter/display_list/effects/dl_image_filters.h"
#include "flutter/display_list/skia/dl_sk_conversions.h"
#include "flutter/impeller/geometry/path_component.h"
#include "gtest/gtest.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkSamplingOptions.h"
Expand Down Expand Up @@ -372,5 +373,92 @@ TEST(DisplayListSkConversions, ToSkRSTransform) {
}
}

// This tests the new conic subdivision code in the Impeller conic path
// component object vs the code we used to rely on inside Skia
TEST(DisplayListSkConversions, ConicToQuads) {
SkScalar weights[4] = {
0.02f,
0.5f,
SK_ScalarSqrt2 * 0.5f,
1.0f,
};

for (SkScalar weight : weights) {
SkPoint sk_points[5];
int ncurves = SkPath::ConvertConicToQuads(
SkPoint::Make(10, 10), SkPoint::Make(20, 10), SkPoint::Make(20, 20),
weight, sk_points, 1);
ASSERT_EQ(ncurves, 2) << "weight: " << weight;

std::array<DlPoint, 5> i_points;
impeller::ConicPathComponent i_conic(DlPoint(10, 10), DlPoint(20, 10),
DlPoint(20, 20), weight);
i_conic.SubdivideToQuadraticPoints(i_points);

for (int i = 0; i < 5; i++) {
EXPECT_FLOAT_EQ(sk_points[i].fX, i_points[i].x)
<< "weight: " << weight << "point[" << i << "].x";
EXPECT_FLOAT_EQ(sk_points[i].fY, i_points[i].y)
<< "weight: " << weight << "point[" << i << "].y";
}
}
}

// This tests the new conic subdivision code in the Impeller conic path
// component object vs the code we used to rely on inside Skia
TEST(DisplayListSkConversions, ConicPathToQuads) {
// If we execute conicTo with a weight of exactly 1.0, SkPath will turn
// it into a quadTo, so we avoid that by using 0.999
SkScalar weights[4] = {
0.02f,
0.5f,
SK_ScalarSqrt2 * 0.5f,
1.0f - kEhCloseEnough,
};

for (SkScalar weight : weights) {
SkPath sk_path;
sk_path.moveTo(10, 10);
sk_path.conicTo(20, 10, 20, 20, weight);

DlPath dl_path(sk_path);
impeller::Path i_path = dl_path.GetPath();

auto it = i_path.begin();
ASSERT_EQ(it.type(), impeller::Path::ComponentType::kContour);
++it;

ASSERT_EQ(it.type(), impeller::Path::ComponentType::kQuadratic);
auto quad1 = it.quadratic();
ASSERT_NE(quad1, nullptr);
++it;

ASSERT_EQ(it.type(), impeller::Path::ComponentType::kQuadratic);
auto quad2 = it.quadratic();
ASSERT_NE(quad2, nullptr);
++it;

SkPoint sk_points[5];
int ncurves = SkPath::ConvertConicToQuads(
SkPoint::Make(10, 10), SkPoint::Make(20, 10), SkPoint::Make(20, 20),
weight, sk_points, 1);
ASSERT_EQ(ncurves, 2);

EXPECT_FLOAT_EQ(sk_points[0].fX, quad1->p1.x) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[0].fY, quad1->p1.y) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[1].fX, quad1->cp.x) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[1].fY, quad1->cp.y) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[2].fX, quad1->p2.x) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[2].fY, quad1->p2.y) << "weight: " << weight;

EXPECT_FLOAT_EQ(sk_points[2].fX, quad2->p1.x) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[2].fY, quad2->p1.y) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[3].fX, quad2->cp.x) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[3].fY, quad2->cp.y) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[4].fX, quad2->p2.x) << "weight: " << weight;
EXPECT_FLOAT_EQ(sk_points[4].fY, quad2->p2.y) << "weight: " << weight;
}
}

} // namespace testing
} // namespace flutter
3 changes: 2 additions & 1 deletion engine/src/flutter/impeller/geometry/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ constexpr float k2OverSqrtPi = 1.12837916709551257390f;
// sqrt(2)
constexpr float kSqrt2 = 1.41421356237309504880f;

// 1/sqrt(2)
// sqrt(2) / 2 == 1/sqrt(2)
constexpr float k1OverSqrt2 = 0.70710678118654752440f;
constexpr float kSqrt2Over2 = 0.70710678118654752440f;

// phi
constexpr float kPhi = 1.61803398874989484820f;
Expand Down
Loading