Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
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 impeller/geometry/geometry_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,10 @@ TEST(GeometryTest, SimplePath) {
.AddCubicComponent({300, 300}, {400, 400}, {500, 500}, {600, 600});

ASSERT_EQ(path.GetComponentCount(), 4u);
ASSERT_EQ(path.GetComponentCount(Path::ComponentType::kLinear), 1u);
ASSERT_EQ(path.GetComponentCount(Path::ComponentType::kQuadratic), 1u);
ASSERT_EQ(path.GetComponentCount(Path::ComponentType::kCubic), 1u);
ASSERT_EQ(path.GetComponentCount(Path::ComponentType::kContour), 1u);

path.EnumerateComponents(
[](size_t index, const LinearPathComponent& linear) {
Expand Down
47 changes: 31 additions & 16 deletions impeller/geometry/path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
#include "impeller/geometry/path.h"

#include <optional>
#include <variant>

#include "impeller/geometry/path_component.h"
#include "path_component.h"

namespace impeller {

Expand All @@ -29,7 +29,19 @@ std::tuple<size_t, size_t> Path::Polyline::GetContourPointBounds(
return std::make_tuple(start_index, end_index);
}

size_t Path::GetComponentCount() const {
size_t Path::GetComponentCount(std::optional<ComponentType> type) const {
if (type.has_value()) {
switch (type.value()) {
case ComponentType::kLinear:
return linears_.size();
case ComponentType::kQuadratic:
return quads_.size();
case ComponentType::kCubic:
return cubics_.size();
case ComponentType::kContour:
return contours_.size();
}
}
return components_.size();
}

Expand Down Expand Up @@ -243,10 +255,9 @@ Path::Polyline Path::CreatePolyline(Scalar scale) const {
}
};

auto get_path_component =
[this](size_t component_i) -> std::optional<const PathComponent*> {
auto get_path_component = [this](size_t component_i) -> PathComponentVariant {
if (component_i >= components_.size()) {
return std::nullopt;
return std::monostate{};
}
const auto& component = components_[component_i];
switch (component.type) {
Expand All @@ -257,18 +268,20 @@ Path::Polyline Path::CreatePolyline(Scalar scale) const {
case ComponentType::kCubic:
return &cubics_[component.index];
case ComponentType::kContour:
return std::nullopt;
return std::monostate{};
}
};

auto compute_contour_start_direction =
[&get_path_component](size_t current_path_component_index) {
size_t next_component_index = current_path_component_index + 1;
while (get_path_component(next_component_index).has_value()) {
auto next_component =
get_path_component(next_component_index).value();
if (next_component->GetStartDirection().has_value()) {
return next_component->GetStartDirection().value();
while (!std::holds_alternative<std::monostate>(
get_path_component(next_component_index))) {
auto next_component = get_path_component(next_component_index);
auto maybe_vector =
std::visit(PathComponentStartDirectionVisitor(), next_component);
if (maybe_vector.has_value()) {
return maybe_vector.value();
} else {
next_component_index++;
}
Expand All @@ -293,11 +306,13 @@ Path::Polyline Path::CreatePolyline(Scalar scale) const {
contour.end_direction = Vector2(0, 1);

size_t previous_index = previous_path_component_index.value();
while (get_path_component(previous_index).has_value()) {
auto previous_path_component = get_path_component(previous_index).value();
if (previous_path_component->GetEndDirection().has_value()) {
contour.end_direction =
previous_path_component->GetEndDirection().value();
while (!std::holds_alternative<std::monostate>(
get_path_component(previous_index))) {
auto previous_component = get_path_component(previous_index);
auto maybe_vector =
std::visit(PathComponentEndDirectionVisitor(), previous_component);
if (maybe_vector.has_value()) {
contour.end_direction = maybe_vector.value();
break;
} else {
if (previous_index == 0) {
Expand Down
2 changes: 1 addition & 1 deletion impeller/geometry/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class Path {

~Path();

size_t GetComponentCount() const;
size_t GetComponentCount(std::optional<ComponentType> type = {}) const;

void SetFillType(FillType fill);

Expand Down
50 changes: 48 additions & 2 deletions impeller/geometry/path_component.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

namespace impeller {

PathComponent::~PathComponent() = default;

/*
* Based on: https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Specific_cases
*/
Expand Down Expand Up @@ -345,4 +343,52 @@ 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
54 changes: 38 additions & 16 deletions impeller/geometry/path_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#pragma once

#include <type_traits>
#include <variant>
#include <vector>

#include "impeller/geometry/point.h"
Expand All @@ -22,14 +24,7 @@ namespace impeller {
// points for the given scale.
static constexpr Scalar kDefaultCurveTolerance = .1f;

struct PathComponent {
virtual ~PathComponent();

virtual std::optional<Vector2> GetStartDirection() const = 0;
virtual std::optional<Vector2> GetEndDirection() const = 0;
};

struct LinearPathComponent : public PathComponent {
struct LinearPathComponent {
Point p1;
Point p2;

Expand All @@ -47,12 +42,12 @@ struct LinearPathComponent : public PathComponent {
return p1 == other.p1 && p2 == other.p2;
}

std::optional<Vector2> GetStartDirection() const override;
std::optional<Vector2> GetStartDirection() const;

std::optional<Vector2> GetEndDirection() const override;
std::optional<Vector2> GetEndDirection() const;
};

struct QuadraticPathComponent : public PathComponent {
struct QuadraticPathComponent {
Point p1;
Point cp;
Point p2;
Expand Down Expand Up @@ -87,12 +82,12 @@ struct QuadraticPathComponent : public PathComponent {
return p1 == other.p1 && cp == other.cp && p2 == other.p2;
}

std::optional<Vector2> GetStartDirection() const override;
std::optional<Vector2> GetStartDirection() const;

std::optional<Vector2> GetEndDirection() const override;
std::optional<Vector2> GetEndDirection() const;
};

struct CubicPathComponent : public PathComponent {
struct CubicPathComponent {
Point p1;
Point cp1;
Point cp2;
Expand Down Expand Up @@ -131,9 +126,9 @@ struct CubicPathComponent : public PathComponent {
p2 == other.p2;
}

std::optional<Vector2> GetStartDirection() const override;
std::optional<Vector2> GetStartDirection() const;

std::optional<Vector2> GetEndDirection() const override;
std::optional<Vector2> GetEndDirection() const;

private:
QuadraticPathComponent Lower() const;
Expand All @@ -153,4 +148,31 @@ struct ContourComponent {
}
};

using PathComponentVariant = std::variant<std::monostate,
const LinearPathComponent*,
const QuadraticPathComponent*,
const CubicPathComponent*>;

struct PathComponentStartDirectionVisitor {
std::optional<Vector2> operator()(const LinearPathComponent* component);
std::optional<Vector2> operator()(const QuadraticPathComponent* component);
std::optional<Vector2> operator()(const CubicPathComponent* component);
std::optional<Vector2> operator()(std::monostate monostate) {
return std::nullopt;
}
};

struct PathComponentEndDirectionVisitor {
std::optional<Vector2> operator()(const LinearPathComponent* component);
std::optional<Vector2> operator()(const QuadraticPathComponent* component);
std::optional<Vector2> operator()(const CubicPathComponent* component);
std::optional<Vector2> operator()(std::monostate monostate) {
return std::nullopt;
}
};

static_assert(!std::is_polymorphic<LinearPathComponent>::value);
static_assert(!std::is_polymorphic<QuadraticPathComponent>::value);
static_assert(!std::is_polymorphic<CubicPathComponent>::value);
Comment on lines +174 to +176
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is my "test" that these stay POD.

Copy link
Member

Choose a reason for hiding this comment

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

Ooh nice, I didn't know this was a thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was going to add some asserts about the sizes but this is better


} // namespace impeller