blob: 4ab67aec647401a3718a221f49230e8c6f9f6676 [file]
// 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"
namespace flutter {
const SkPath& DlPath::GetSkPath() const {
return sk_path_;
}
impeller::Path DlPath::GetPath() const {
if (path_.IsEmpty() && !sk_path_.isEmpty()) {
path_ = ConvertToImpellerPath(sk_path_);
}
return path_;
}
bool DlPath::IsInverseFillType() const {
return sk_path_.isInverseFillType();
}
bool DlPath::IsRect(DlRect* rect, bool* is_closed) const {
return sk_path_.isRect(ToSkRect(rect), is_closed);
}
bool DlPath::IsOval(DlRect* bounds) const {
return sk_path_.isOval(ToSkRect(bounds));
}
bool DlPath::IsSkRect(SkRect* rect, bool* is_closed) const {
return sk_path_.isRect(rect, is_closed);
}
bool DlPath::IsSkOval(SkRect* bounds) const {
return sk_path_.isOval(bounds);
}
bool DlPath::IsSkRRect(SkRRect* rrect) const {
return sk_path_.isRRect(rrect);
}
SkRect DlPath::GetSkBounds() const {
return sk_path_.getBounds();
}
DlRect DlPath::GetBounds() const {
return ToDlRect(sk_path_.getBounds());
}
bool DlPath::operator==(const DlPath& other) const {
return sk_path_ == other.sk_path_;
}
bool DlPath::IsConverted() const {
if (!path_.IsEmpty()) {
return true;
}
if (sk_path_.isEmpty()) {
return true;
}
return false;
}
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) {
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