Skip to content

Commit

Permalink
Add bounds cache for the Path class. (#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
domchen authored Feb 25, 2024
1 parent d71b281 commit 35f2ff5
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 10 deletions.
12 changes: 2 additions & 10 deletions src/core/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,16 +161,7 @@ bool Path::isLine(Point line[2]) const {
}

Rect Path::getBounds() const {
// Internally, SkPath lazily computes bounds. Use this function instead of path.getBounds()
// for thread safety.
const auto& path = pathRef->path;
auto count = path.countPoints();
auto points = new SkPoint[static_cast<size_t>(count)];
path.getPoints(points, count);
auto rect = SkRect::MakeEmpty();
rect.setBounds(points, count);
delete[] points;
return {rect.fLeft, rect.fTop, rect.fRight, rect.fBottom};
return pathRef->getBounds();
}

bool Path::isEmpty() const {
Expand Down Expand Up @@ -401,6 +392,7 @@ PathRef* Path::writableRef() {
pathRef = std::make_shared<PathRef>(pathRef->path);
} else {
pathRef->uniqueKey.reset();
pathRef->resetBounds();
}
return pathRef.get();
}
Expand Down
30 changes: 30 additions & 0 deletions src/core/PathRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,34 @@ SkPath& PathRef::WriteAccess(Path& path) {
UniqueKey PathRef::GetUniqueKey(const Path& path) {
return path.pathRef->uniqueKey.get();
}

PathRef::~PathRef() {
resetBounds();
}

Rect PathRef::getBounds() {
auto cacheBounds = bounds.load(std::memory_order_acquire);
if (cacheBounds == nullptr) {
// Internally, SkPath lazily computes bounds. Use this function instead of path.getBounds()
// for thread safety.
auto count = path.countPoints();
auto points = new SkPoint[static_cast<size_t>(count)];
path.getPoints(points, count);
auto rect = SkRect::MakeEmpty();
rect.setBounds(points, count);
delete[] points;
auto newBounds = new Rect{rect.fLeft, rect.fTop, rect.fRight, rect.fBottom};
if (bounds.compare_exchange_strong(cacheBounds, newBounds, std::memory_order_acq_rel)) {
cacheBounds = newBounds;
} else {
delete newBounds;
}
}
return *cacheBounds;
}

void PathRef::resetBounds() {
auto oldBounds = bounds.exchange(nullptr, std::memory_order_acq_rel);
delete oldBounds;
}
} // namespace tgfx
7 changes: 7 additions & 0 deletions src/core/PathRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,17 @@ class PathRef {
explicit PathRef(const pk::SkPath& path) : path(path) {
}

~PathRef();

Rect getBounds();

private:
LazyUniqueKey uniqueKey = {};
std::atomic<Rect*> bounds = {nullptr};
pk::SkPath path = {};

void resetBounds();

friend bool operator==(const Path& a, const Path& b);
friend bool operator!=(const Path& a, const Path& b);
friend class Path;
Expand Down

0 comments on commit 35f2ff5

Please sign in to comment.