Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
329 changes: 151 additions & 178 deletions impeller/geometry/path.cc

Large diffs are not rendered by default.

45 changes: 23 additions & 22 deletions impeller/geometry/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ class Path {
kContour,
};

static constexpr size_t VerbToOffset(Path::ComponentType verb) {
switch (verb) {
case Path::ComponentType::kLinear:
return 2u;
case Path::ComponentType::kQuadratic:
return 3u;
case Path::ComponentType::kCubic:
return 4u;
case Path::ComponentType::kContour:
return 2u;
break;
}
FML_UNREACHABLE();
}

struct PolylineContour {
struct Component {
size_t component_start_index;
Expand Down Expand Up @@ -138,14 +153,6 @@ class Path {

bool IsEmpty() const;

template <class T>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was only used in a single test so I removed it.

using Applier = std::function<void(size_t index, const T& component)>;
void EnumerateComponents(
const Applier<LinearPathComponent>& linear_applier,
const Applier<QuadraticPathComponent>& quad_applier,
const Applier<CubicPathComponent>& cubic_applier,
const Applier<ContourComponent>& contour_applier) const;

bool GetLinearComponentAtIndex(size_t index,
LinearPathComponent& linear) const;

Expand All @@ -169,6 +176,12 @@ class Path {
std::make_unique<std::vector<Point>>(),
Polyline::ReclaimPointBufferCallback reclaim = nullptr) const;

void EndContour(
size_t storage_offset,
Polyline& polyline,
std::optional<size_t> previous_path_component_index,
std::vector<PolylineContour::Component>& poly_components) const;

std::optional<Rect> GetBoundingBox() const;

std::optional<Rect> GetTransformedBoundingBox(const Matrix& transform) const;
Expand All @@ -183,16 +196,6 @@ class Path {
private:
friend class PathBuilder;

struct ComponentIndexPair {
ComponentType type = ComponentType::kLinear;
size_t index = 0;

ComponentIndexPair() {}

ComponentIndexPair(ComponentType a_type, size_t a_index)
: type(a_type), index(a_index) {}
};

// All of the data for the path is stored in this structure which is
// held by a shared_ptr. Since they all share the structure, the
// copy constructor for Path is very cheap and we don't need to deal
Expand All @@ -213,11 +216,9 @@ class Path {

FillType fill = FillType::kNonZero;
Convexity convexity = Convexity::kUnknown;
std::vector<ComponentIndexPair> components;
std::vector<Point> points;
std::vector<ContourComponent> contours;

std::optional<Rect> bounds;
std::vector<Point> points;
std::vector<ComponentType> components;
};

explicit Path(Data data);
Expand Down
124 changes: 81 additions & 43 deletions impeller/geometry/path_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <cmath>

#include "impeller/geometry/path_component.h"

namespace impeller {

PathBuilder::PathBuilder() {
Expand All @@ -22,6 +24,7 @@ Path PathBuilder::CopyPath(FillType fill) {
Path PathBuilder::TakePath(FillType fill) {
prototype_.fill = fill;
UpdateBounds();
current_contour_location_ = 0u;
return Path(std::move(prototype_));
}

Expand Down Expand Up @@ -264,36 +267,38 @@ PathBuilder& PathBuilder::AddRoundedRectBottomLeft(Rect rect,
void PathBuilder::AddContourComponent(const Point& destination,
bool is_closed) {
auto& components = prototype_.components;
auto& contours = prototype_.contours;
auto& points = prototype_.points;
auto closed = is_closed ? Point{0, 0} : Point{1, 1};
if (components.size() > 0 &&
components.back().type == Path::ComponentType::kContour) {
components.back() == Path::ComponentType::kContour) {
// Never insert contiguous contours.
contours.back() = ContourComponent(destination, is_closed);
points[current_contour_location_] = destination;
points[current_contour_location_ + 1] = closed;
} else {
contours.emplace_back(ContourComponent(destination, is_closed));
components.emplace_back(Path::ComponentType::kContour, contours.size() - 1);
current_contour_location_ = points.size();
points.push_back(destination);
points.push_back(closed);
components.push_back(Path::ComponentType::kContour);
}
prototype_.bounds.reset();
}

void PathBuilder::AddLinearComponent(const Point& p1, const Point& p2) {
auto& points = prototype_.points;
auto index = points.size();
points.emplace_back(p1);
points.emplace_back(p2);
prototype_.components.emplace_back(Path::ComponentType::kLinear, index);
points.push_back(p1);
points.push_back(p2);
prototype_.components.push_back(Path::ComponentType::kLinear);
prototype_.bounds.reset();
}

void PathBuilder::AddQuadraticComponent(const Point& p1,
const Point& cp,
const Point& p2) {
auto& points = prototype_.points;
auto index = points.size();
points.emplace_back(p1);
points.emplace_back(cp);
points.emplace_back(p2);
prototype_.components.emplace_back(Path::ComponentType::kQuadratic, index);
points.push_back(p1);
points.push_back(cp);
points.push_back(p2);
prototype_.components.push_back(Path::ComponentType::kQuadratic);
prototype_.bounds.reset();
}

Expand All @@ -302,17 +307,17 @@ void PathBuilder::AddCubicComponent(const Point& p1,
const Point& cp2,
const Point& p2) {
auto& points = prototype_.points;
auto index = points.size();
points.emplace_back(p1);
points.emplace_back(cp1);
points.emplace_back(cp2);
points.emplace_back(p2);
prototype_.components.emplace_back(Path::ComponentType::kCubic, index);
points.push_back(p1);
points.push_back(cp1);
points.push_back(cp2);
points.push_back(p2);
prototype_.components.push_back(Path::ComponentType::kCubic);
prototype_.bounds.reset();
}

void PathBuilder::SetContourClosed(bool is_closed) {
prototype_.contours.back().is_closed = is_closed;
prototype_.points[current_contour_location_ + 1] =
is_closed ? Point{0, 0} : Point{1, 1};
}

PathBuilder& PathBuilder::AddArc(const Rect& oval_bounds,
Expand Down Expand Up @@ -428,29 +433,60 @@ PathBuilder& PathBuilder::AddLine(const Point& p1, const Point& p2) {
}

PathBuilder& PathBuilder::AddPath(const Path& path) {
auto linear = [&](size_t index, const LinearPathComponent& l) {
AddLinearComponent(l.p1, l.p2);
};
auto quadratic = [&](size_t index, const QuadraticPathComponent& q) {
AddQuadraticComponent(q.p1, q.cp, q.p2);
};
auto cubic = [&](size_t index, const CubicPathComponent& c) {
AddCubicComponent(c.p1, c.cp1, c.cp2, c.p2);
};
auto move = [&](size_t index, const ContourComponent& m) {
AddContourComponent(m.destination);
};
path.EnumerateComponents(linear, quadratic, cubic, move);
auto& points = prototype_.points;
auto& components = prototype_.components;

points.insert(points.end(), path.data_->points.begin(),
path.data_->points.end());
components.insert(components.end(), path.data_->components.begin(),
path.data_->components.end());

size_t source_offset = points.size();
for (auto component : path.data_->components) {
if (component == Path::ComponentType::kContour) {
current_contour_location_ = source_offset;
}
source_offset += Path::VerbToOffset(component);
}
return *this;
}

PathBuilder& PathBuilder::Shift(Point offset) {
for (auto& point : prototype_.points) {
point += offset;
}
for (auto& contour : prototype_.contours) {
contour.destination += offset;
auto& points = prototype_.points;
size_t storage_offset = 0u;
for (const auto& component : prototype_.components) {
switch (component) {
case Path::ComponentType::kLinear: {
auto* linear =
reinterpret_cast<LinearPathComponent*>(&points[storage_offset]);
linear->p1 += offset;
linear->p2 += offset;
break;
}
case Path::ComponentType::kQuadratic: {
auto* quad =
reinterpret_cast<QuadraticPathComponent*>(&points[storage_offset]);
quad->p1 += offset;
quad->p2 += offset;
quad->cp += offset;
} break;
case Path::ComponentType::kCubic: {
auto* cubic =
reinterpret_cast<CubicPathComponent*>(&points[storage_offset]);
cubic->p1 += offset;
cubic->p2 += offset;
cubic->cp1 += offset;
cubic->cp2 += offset;
} break;
case Path::ComponentType::kContour:
auto* contour =
reinterpret_cast<ContourComponent*>(&points[storage_offset]);
contour->destination += offset;
break;
}
storage_offset += Path::VerbToOffset(component);
}

prototype_.bounds.reset();
return *this;
}
Expand Down Expand Up @@ -499,33 +535,35 @@ std::optional<std::pair<Point, Point>> PathBuilder::GetMinMaxCoveragePoints()
}
};

size_t storage_offset = 0u;
for (const auto& component : prototype_.components) {
switch (component.type) {
switch (component) {
case Path::ComponentType::kLinear: {
auto* linear = reinterpret_cast<const LinearPathComponent*>(
&points[component.index]);
&points[storage_offset]);
clamp(linear->p1);
clamp(linear->p2);
break;
}
case Path::ComponentType::kQuadratic:
for (const auto& extrema :
reinterpret_cast<const QuadraticPathComponent*>(
&points[component.index])
&points[storage_offset])
->Extrema()) {
clamp(extrema);
}
break;
case Path::ComponentType::kCubic:
for (const auto& extrema : reinterpret_cast<const CubicPathComponent*>(
&points[component.index])
&points[storage_offset])
->Extrema()) {
clamp(extrema);
}
break;
case Path::ComponentType::kContour:
break;
}
storage_offset += Path::VerbToOffset(component);
}

if (!min.has_value() || !max.has_value()) {
Expand Down
1 change: 1 addition & 0 deletions impeller/geometry/path_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ class PathBuilder {
private:
Point subpath_start_;
Point current_;
size_t current_contour_location_ = 0u;
Path::Data prototype_;

PathBuilder& AddRoundedRectTopLeft(Rect rect, RoundingRadii radii);
Expand Down
48 changes: 0 additions & 48 deletions impeller/geometry/path_component.cc
Original file line number Diff line number Diff line change
Expand Up @@ -373,52 +373,4 @@ std::optional<Vector2> CubicPathComponent::GetEndDirection() const {
return std::nullopt;
}

std::optional<Vector2> PathComponentStartDirectionVisitor::operator()(
const LinearPathComponent* component) {
if (!component) {
return std::nullopt;
}
return component->GetStartDirection();
}

std::optional<Vector2> PathComponentStartDirectionVisitor::operator()(
const QuadraticPathComponent* component) {
if (!component) {
return std::nullopt;
}
return component->GetStartDirection();
}

std::optional<Vector2> PathComponentStartDirectionVisitor::operator()(
const CubicPathComponent* component) {
if (!component) {
return std::nullopt;
}
return component->GetStartDirection();
}

std::optional<Vector2> PathComponentEndDirectionVisitor::operator()(
const LinearPathComponent* component) {
if (!component) {
return std::nullopt;
}
return component->GetEndDirection();
}

std::optional<Vector2> PathComponentEndDirectionVisitor::operator()(
const QuadraticPathComponent* component) {
if (!component) {
return std::nullopt;
}
return component->GetEndDirection();
}

std::optional<Vector2> PathComponentEndDirectionVisitor::operator()(
const CubicPathComponent* component) {
if (!component) {
return std::nullopt;
}
return component->GetEndDirection();
}

} // namespace impeller
Loading