Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add missing pybind11 include #263

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
49 changes: 40 additions & 9 deletions src/skia/Picture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <include/core/SkBBHFactory.h>
#include <include/core/SkPictureRecorder.h>
#include <pybind11/operators.h>
#include <pybind11/stl.h>

namespace {

Expand All @@ -27,11 +28,32 @@ class PyPicture : public SkPicture {
class PyBBoxHierarchy : public SkBBoxHierarchy {
public:
using SkBBoxHierarchy::SkBBoxHierarchy;

// https://pybind11.readthedocs.io/en/stable/advanced/classes.html#different-method-signatures
void insert(const SkRect rects[], int N) override {
PYBIND11_OVERRIDE_PURE(void, SkBBoxHierarchy, insert, rects, N);
pybind11::gil_scoped_acquire gil;
pybind11::function override = pybind11::get_override(this, "insert");
if (override) {
override(std::vector<SkRect>(rects, rects + N));
}
}
void insert(const SkRect rects[], const Metadata metadata[], int N) override {
pybind11::gil_scoped_acquire gil;
pybind11::function override = pybind11::get_override(this, "insert");
if (override) {
override(std::vector<SkRect>(rects, rects + N),
std::vector<Metadata>(metadata, metadata + N));
}
}
void search(const SkRect& query, std::vector<int> *results) const override {
PYBIND11_OVERRIDE_PURE(void, SkBBoxHierarchy, search, query, results);
pybind11::gil_scoped_acquire gil;
pybind11::function override = pybind11::get_override(this, "search");
if (override) {
auto obj = override(query);
if (py::isinstance<py::list>(obj)) {
*results = obj.cast<std::vector<int>>();
}
}
}
size_t bytesUsed() const override {
PYBIND11_OVERRIDE_PURE(size_t, SkBBoxHierarchy, bytesUsed);
Expand Down Expand Up @@ -289,21 +311,30 @@ py::class_<SkBBoxHierarchy::Metadata>(bboxhierarchy, "Metadata")
bboxhierarchy
.def(py::init())
.def("insert",
py::overload_cast<const SkRect[], int>(&SkBBoxHierarchy::insert),
[] (SkBBoxHierarchy& bbh, const std::vector<SkRect>& rects) {
return bbh.insert(rects.data(), rects.size());
},
R"docstring(
Insert N bounding boxes into the hierarchy.
)docstring",
py::arg("rects"), py::arg("N"))
py::arg("rects"))
.def("insert",
py::overload_cast<const SkRect[], const SkBBoxHierarchy::Metadata[],
int>(&SkBBoxHierarchy::insert),
py::arg("rects"), py::arg("metadata"), py::arg("N"))
.def("search", &SkBBoxHierarchy::search,
[] (SkBBoxHierarchy& bbh, const std::vector<SkRect>& rects,
const std::vector<SkBBoxHierarchy::Metadata>& metadata) {
return bbh.insert(rects.data(), metadata.data(), rects.size());
},
py::arg("rects"), py::arg("metadata"))
.def("search",
[] (SkBBoxHierarchy& bbh, const SkRect& query) {
std::vector<int> results;
bbh.search(query, &results);
return results;
},
R"docstring(
Populate results with the indices of bounding boxes intersecting that
query.
)docstring",
py::arg("query"), py::arg("results"))
py::arg("query"))
.def("bytesUsed", &SkBBoxHierarchy::bytesUsed,
R"docstring(
Return approximate size in memory of this.
Expand Down
1 change: 1 addition & 0 deletions src/skia/Point.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "common.h"
#include <include/core/SkPoint3.h>
#include <pybind11/operators.h>
#include <pybind11/stl.h>

void initPoint(py::module &m) {
// IPoint
Expand Down
132 changes: 132 additions & 0 deletions tests/test_picture.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,66 @@ def test_Picture_MakePlaceholder():
skia.Picture.MakePlaceholder(skia.Rect(100, 100)), skia.Picture)


def test_RTreeFactory_init():
HinTak marked this conversation as resolved.
Show resolved Hide resolved
assert isinstance(skia.RTreeFactory(), skia.RTreeFactory)


@pytest.fixture
def factory():
return skia.RTreeFactory()


def test_RTreeFactory_call(factory):
bbh = factory()
assert isinstance(bbh, skia.BBoxHierarchy)


def test_BBoxHierarchy_init():
assert isinstance(skia.BBoxHierarchy(), skia.BBoxHierarchy)


def test_BBoxHierarchy_insert(factory):
bbh = factory()
bbh.insert([skia.Rect(100, 100)])


def test_BBoxHierarchy_search(factory):
bbh = factory()
bbh.insert([skia.Rect(100, 100)])
results = bbh.search(skia.Rect(100, 100))
assert results[0] == 0


def test_inherit_BBoxHierarchy():
class TestBBH(skia.BBoxHierarchy):
def __init__(self):
self.rects = []
super().__init__()

def search(self, query):
return [i for i, rect in enumerate(self.rects) if rect.intersects(query)]

def insert(self, rects, metadata=[]):
self.rects.extend(rects)

def bytesUsed(self):
return 0

bbh = TestBBH()
bbh.insert([skia.Rect(100, 100)])
assert len(bbh.rects) == 1
results = bbh.search(skia.Rect(100, 100))
assert results[0] == 0


def test_PictureRecorder_init():
assert isinstance(skia.PictureRecorder(), skia.PictureRecorder)


@pytest.mark.parametrize('args', [
(skia.Rect(100, 100),),
(100, 100),
(skia.Rect(100, 100), skia.RTreeFactory()()),
])
def test_PictureRecorder_beginRecording(recorder, args):
canvas = recorder.beginRecording(*args)
Expand Down Expand Up @@ -126,3 +179,82 @@ def test_Drawable_getBounds(drawable):

def test_Drawable_notifyDrawingChanged(drawable):
drawable.notifyDrawingChanged()


# https://github.com/google/skia/blob/ad08229fd0163a784c60a8bac2c0c5a6a13877c9/tests/PictureTest.cpp#L869-L893
def test_Picture_fillsBBH(factory, recorder):
rects = [
skia.Rect(0, 0, 20, 20),
skia.Rect(20, 20, 40, 40),
]

for n in range(len(rects) + 1):
bbh = factory()

canvas = recorder.beginRecording(skia.Rect(0, 0, 100, 100), bbh)
for i in range(n):
canvas.drawRect(rects[i], skia.Paint())
recorder.finishRecordingAsPicture()

results = bbh.search(skia.Rect(0, 0, 100, 100))
assert len(results) == n


# https://github.com/google/skia/blob/64148dd7cfe0a3f104d93f58ec42592a0252d378/tests/PictureBBHTest.cpp#L99-L127
def test_PictureNegativeSpace(factory, recorder):
cull = skia.Rect(-200, -200, 200, 200)

bbh = factory()
canvas = recorder.beginRecording(cull, bbh)
canvas.save()
canvas.clipRect(cull)
canvas.drawRect(skia.Rect(-20, -20, -10, -10), skia.Paint())
canvas.drawRect(skia.Rect(-20, -20, -10, -10), skia.Paint())
canvas.restore()
picture = recorder.finishRecordingAsPicture()
assert picture.approximateOpCount() == 5
assert picture.cullRect() == skia.Rect(-20, -20, -10, -10)

bbh = factory()
canvas = recorder.beginRecording(cull, bbh)
canvas.clipRect(cull)
canvas.drawRect(skia.Rect(-20, -20, -10, -10), skia.Paint())
canvas.drawRect(skia.Rect(-20, -20, -10, -10), skia.Paint())
picture = recorder.finishRecordingAsPicture()
assert picture.approximateOpCount() == 3
assert picture.cullRect() == skia.Rect(-20, -20, -10, -10)


# https://github.com/google/skia/blob/64148dd7cfe0a3f104d93f58ec42592a0252d378/tests/PictureTest.cpp#L613-L657
def test_Picture_SkipBBH(recorder):
class CountingBBH(skia.BBoxHierarchy):
def __init__(self):
self.search_calls: int = 0
super().__init__()

def search(self, query):
self.search_calls += 1

def insert(self, rects, metadata=[]):
pass

def bytesUsed(self):
return 0

bound = skia.Rect(320, 240)

bbh = CountingBBH()

canvas = recorder.beginRecording(bound, bbh)
canvas.drawRect(bound, skia.Paint())
canvas.drawRect(bound, skia.Paint())
picture = recorder.finishRecordingAsPicture()

big = skia.Canvas(640, 480)
small = skia.Canvas(300, 200)

picture.playback(big)
assert bbh.search_calls == 0

picture.playback(small)
assert bbh.search_calls == 1
7 changes: 7 additions & 0 deletions tests/test_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ def test_Point_init(args):
assert isinstance(skia.Point(*args), skia.Point)


def test_Point_Offset():
points = [skia.Point(1, 2), skia.Point(3, 4)]
points = skia.Point.Offset(points, 1, 1)
assert points[0].equals(2, 3)
assert points[1].equals(4, 5)


def test_Point_x(point):
assert point.x() == 4

Expand Down
Loading