Skip to content

Commit

Permalink
feat: support isPointInStroke
Browse files Browse the repository at this point in the history
  • Loading branch information
doodlewind committed Jan 18, 2021
1 parent 5ca9fde commit 2a14513
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 1 deletion.
23 changes: 22 additions & 1 deletion __test__/draw.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,28 @@ test('getImageData', async (t) => {

test.todo('isPointInPath')

test.todo('isPointInStroke')
test('isPointInStroke', (t) => {
const { ctx } = t.context
ctx.rect(10, 10, 100, 100)
ctx.stroke()
t.is(ctx.isPointInStroke(50, 9), false) // Outside the rect
t.is(ctx.isPointInStroke(50, 10), true) // On the edge of the rect
t.is(ctx.isPointInStroke(50, 11), false) // Inside the rect

ctx.lineWidth = 3
ctx.stroke()
// All points on the edge now
t.is(ctx.isPointInStroke(50, 9), true)
t.is(ctx.isPointInStroke(50, 10), true)
t.is(ctx.isPointInStroke(50, 11), true)

ctx.lineWidth = 1
const path = new Path2D()
path.rect(10, 10, 100, 100)
t.is(ctx.isPointInStroke(path, 50, 9), false)
t.is(ctx.isPointInStroke(path, 50, 10), true)
t.is(ctx.isPointInStroke(path, 50, 11), false)
})

test('lineTo', async (t) => {
const { ctx } = t.context
Expand Down
25 changes: 25 additions & 0 deletions skia-c/skia_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,31 @@ extern "C"
return PATH_CAST->isEmpty();
}

bool skiac_path_stroke_hit_test(skiac_path *c_path, float x, float y, float stroke_w)
{
auto path = PATH_CAST;
auto prev_fill = path->getFillType();
path->setFillType(SkPathFillType::kWinding);
SkPaint paint;
paint.setStrokeWidth(stroke_w);
paint.setStyle(SkPaint::kStroke_Style);
SkPath traced_path;

bool result;
auto precision = 0.3; // Based on config in Chromium
if (paint.getFillPath(*path, &traced_path, nullptr, precision))
{
result = traced_path.contains(x, y);
}
else
{
result = path->contains(x, y);
}

path->setFillType(prev_fill);
return result;
}

// PathEffect

skiac_path_effect *skiac_path_effect_make_dash_path(const float *intervals, int count, float phase)
Expand Down
1 change: 1 addition & 0 deletions skia-c/skia_c.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ extern "C"
void skiac_path_transform(skiac_path *c_path, skiac_transform c_transform);
void skiac_path_transform_matrix(skiac_path *c_path, skiac_matrix *c_matrix);
bool skiac_path_is_empty(skiac_path *c_path);
bool skiac_path_stroke_hit_test(skiac_path *c_path, float x, float y, float stroke_w);

// PathEffect
skiac_path_effect *skiac_path_effect_make_dash_path(const float *intervals, int count, float phase);
Expand Down
26 changes: 26 additions & 0 deletions src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ impl Context {
Property::new(&env, "closePath")?.with_method(close_path),
Property::new(&env, "createLinearGradient")?.with_method(create_linear_gradient),
Property::new(&env, "createRadialGradient")?.with_method(create_radial_gradient),
Property::new(&env, "isPointInStroke")?.with_method(is_point_in_stroke),
Property::new(&env, "ellipse")?.with_method(ellipse),
Property::new(&env, "lineTo")?.with_method(line_to),
Property::new(&env, "moveTo")?.with_method(move_to),
Expand Down Expand Up @@ -625,6 +626,31 @@ fn close_path(ctx: CallContext) -> Result<JsUndefined> {
ctx.env.get_undefined()
}

#[js_function(3)]
fn is_point_in_stroke(ctx: CallContext) -> Result<JsBoolean> {
let this = ctx.this_unchecked::<JsObject>();
let context_2d = ctx.env.unwrap::<Context>(&this)?;
let mut result = false;

if ctx.length == 2 {
let x: f64 = ctx.get::<JsNumber>(0)?.try_into()?;
let y: f64 = ctx.get::<JsNumber>(1)?.try_into()?;
let stroke_w = context_2d.states.last().unwrap().paint.get_stroke_width() as f32;
result = context_2d
.path
.stroke_hit_test(x as f32, y as f32, stroke_w);
} else if ctx.length == 3 {
let path_js = ctx.get::<JsObject>(0)?;
let path = ctx.env.unwrap::<Path>(&path_js)?;

let x: f64 = ctx.get::<JsNumber>(1)?.try_into()?;
let y: f64 = ctx.get::<JsNumber>(2)?.try_into()?;
let stroke_w = context_2d.states.last().unwrap().paint.get_stroke_width() as f32;
result = path.stroke_hit_test(x as f32, y as f32, stroke_w);
}
ctx.env.get_boolean(result)
}

#[js_function(8)]
fn ellipse(ctx: CallContext) -> Result<JsUndefined> {
let this = ctx.this_unchecked::<JsObject>();
Expand Down
8 changes: 8 additions & 0 deletions src/sk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,9 @@ mod ffi {

pub fn skiac_path_is_empty(path: *mut skiac_path) -> bool;

pub fn skiac_path_stroke_hit_test(path: *mut skiac_path, x: f32, y: f32, stroke_w: f32)
-> bool;

pub fn skiac_path_effect_make_dash_path(
intervals: *const f32,
count: i32,
Expand Down Expand Up @@ -1663,6 +1666,11 @@ impl Path {
pub fn is_empty(&self) -> bool {
unsafe { ffi::skiac_path_is_empty(self.0) }
}

#[inline]
pub fn stroke_hit_test(&self, x: f32, y: f32, stroke_w: f32) -> bool {
unsafe { ffi::skiac_path_stroke_hit_test(self.0, x, y, stroke_w) }
}
}

impl Drop for Path {
Expand Down

0 comments on commit 2a14513

Please sign in to comment.