Skip to content

Commit

Permalink
Merge pull request #39 from fonttools/stroke-dash
Browse files Browse the repository at this point in the history
add support for dashed strokes
  • Loading branch information
anthrotype authored Dec 14, 2020
2 parents c5e55f1 + bbf9bfb commit c5ed7c4
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 25 deletions.
19 changes: 18 additions & 1 deletion src/python/pathops/_pathops.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,15 @@ cdef class Path:

cpdef convertConicsToQuads(self, float tolerance=*)

cpdef stroke(self, SkScalar width, LineCap cap, LineJoin join, SkScalar miter_limit)
cpdef stroke(
self,
SkScalar width,
LineCap cap,
LineJoin join,
SkScalar miter_limit,
object dash_array=*,
SkScalar dash_offset=*,
)

cdef list getVerbs(self)

Expand Down Expand Up @@ -273,6 +281,15 @@ cdef class _SkPointArray:
cdef _SkPointArray create(const SkPath& path)


cdef class _SkScalarArray:

cdef SkScalar *data
cdef int count

@staticmethod
cdef _SkScalarArray create(object values)


cdef int pts_in_verb(unsigned v) except -1


Expand Down
62 changes: 51 additions & 11 deletions src/python/pathops/_pathops.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ from ._skia.core cimport (
SkPathFillType,
SkPoint,
SkScalar,
SkStrokeRec,
SkRect,
SkLineCap,
SkLineJoin,
Expand All @@ -15,9 +14,13 @@ from ._skia.core cimport (
kCubic_Verb,
kClose_Verb,
kDone_Verb,
kFill_InitStyle,
SK_ScalarNearlyZero,
ConvertConicToQuads,
SkPaint,
SkPaintStyle,
sk_sp,
SkPathEffect,
SkDashPathEffect,
)
from ._skia.pathops cimport (
Op,
Expand Down Expand Up @@ -445,15 +448,34 @@ cdef class Path:

self.path = temp

cpdef stroke(self, SkScalar width, LineCap cap, LineJoin join, SkScalar miter_limit):
# Do stroke
stroke_rec = new SkStrokeRec(kFill_InitStyle)
try:
stroke_rec.setStrokeStyle(width, False)
stroke_rec.setStrokeParams(<SkLineCap>cap, <SkLineJoin>join, miter_limit)
stroke_rec.applyToPath(&self.path, self.path)
finally:
del stroke_rec
cpdef stroke(
self,
SkScalar width,
LineCap cap,
LineJoin join,
SkScalar miter_limit,
object dash_array=None,
SkScalar dash_offset=0.0,
):
cdef _SkScalarArray intervals
cdef sk_sp[SkPathEffect] dash
cdef SkPaint paint = SkPaint()

paint.setStyle(SkPaintStyle.kStroke_Style)
paint.setStrokeWidth(width)
paint.setStrokeCap(<SkLineCap>cap)
paint.setStrokeJoin(<SkLineJoin>join)
paint.setStrokeMiter(miter_limit)

if dash_array:
intervals = _SkScalarArray.create(dash_array)
if intervals.count % 2 != 0:
raise ValueError("Expected an even number of dash_array entries")
paint.setPathEffect(
SkDashPathEffect.Make(intervals.data, intervals.count, dash_offset)
)

paint.getFillPath(self.path, &self.path)

cdef list getVerbs(self):
cdef int i, count
Expand Down Expand Up @@ -990,6 +1012,24 @@ cdef class _SkPointArray:
PyMem_Free(self.data) # no-op if data is NULL


cdef class _SkScalarArray:

@staticmethod
cdef _SkScalarArray create(object values):
# 'values' must be a sequence (e.g. list or tuple) of floats
cdef _SkScalarArray self = _SkScalarArray.__new__(_SkScalarArray)
self.count = len(values)
self.data = <SkScalar *> PyMem_Malloc(self.count * sizeof(SkScalar))
if not self.data:
raise MemoryError()
for i, v in enumerate(values):
self.data[i] = v
return self

def __dealloc__(self):
PyMem_Free(self.data) # no-op if data is NULL


cdef inline int pts_in_verb(unsigned v) except -1:
if v >= NUM_VERBS:
raise IndexError(v)
Expand Down
44 changes: 31 additions & 13 deletions src/python/pathops/_skia/core.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,29 @@ cdef extern from "include/core/SkScalar.h":
SK_ScalarNearlyZero


# 'opaque' types used by SkDashPathEffect::Make and SkPaint::setPathEffect
cdef extern from "include/core/SkRefCnt.h":
cdef cppclass sk_sp[T]:
pass


cdef extern from "include/core/SkPathEffect.h":
cdef cppclass SkPathEffect:
pass


cdef extern from "include/effects/SkDashPathEffect.h":
cdef cppclass SkDashPathEffect:
@staticmethod
sk_sp[SkPathEffect] Make(const SkScalar intervals[], int count, SkScalar phase)


cdef extern from "include/core/SkPaint.h":
enum SkPaintStyle "SkPaint::Style":
kFill_Style "SkPaint::Style::kFill_Style",
kStroke_Style "SkPaint::Style::kStroke_Style",
kStrokeAndFill_Style "SkPaint::Style::kStrokeAndFill_Style",

enum SkLineCap "SkPaint::Cap":
kButt_Cap "SkPaint::Cap::kButt_Cap",
kRound_Cap "SkPaint::Cap::kRound_Cap",
Expand All @@ -198,16 +220,12 @@ cdef extern from "include/core/SkPaint.h":
kRound_Join "SkPaint::Join::kRound_Join",
kBevel_Join "SkPaint::Join::kBevel_Join"


cdef extern from "include/core/SkStrokeRec.h":
cdef cppclass SkStrokeRec:
SkStrokeRec(InitStyle style)
void setStrokeStyle(SkScalar width, bint strokeAndFill)
void setStrokeParams(SkLineCap cap, SkLineJoin join, SkScalar miterLimit)
bint applyToPath(SkPath* dst, const SkPath& src) const;


cdef extern from * namespace "SkStrokeRec":
enum InitStyle:
kHairline_InitStyle,
kFill_InitStyle
cdef cppclass SkPaint:
SkPaint()
void setStyle(SkPaintStyle style)
void setStrokeWidth(SkScalar width)
void setStrokeCap(SkLineCap cap)
void setStrokeJoin(SkLineJoin join)
void setStrokeMiter(SkScalar miter)
void setPathEffect(sk_sp[SkPathEffect] pathEffect)
bint getFillPath(const SkPath& src, SkPath* dst) const
50 changes: 50 additions & 0 deletions tests/pathops_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,56 @@ def test_strip_collinear_moveTo():
('closePath', ()),
),
),
(
'stroke_dash_array',
(
('moveTo', (5, 5)),
('lineTo', (10, 5)),
('stroke', (2, 0, 0, 1, (1, 1))),
),
(
('moveTo', ((5.0, 4.0),)),
('lineTo', ((6.0, 4.0),)),
('lineTo', ((6.0, 6.0),)),
('lineTo', ((5.0, 6.0),)),
('endPath', ()),
('moveTo', ((7.0, 4.0),)),
('lineTo', ((8.0, 4.0),)),
('lineTo', ((8.0, 6.0),)),
('lineTo', ((7.0, 6.0),)),
('endPath', ()),
('moveTo', ((9.0, 4.0),)),
('lineTo', ((10.0, 4.0),)),
('lineTo', ((10.0, 6.0),)),
('lineTo', ((9.0, 6.0),)),
('endPath', ()),
),
),
(
'stroke_dash_offset',
(
('moveTo', (5, 5)),
('lineTo', (10, 5)),
('stroke', (2, 0, 0, 1, (1, 1), 0.5)),
),
(
('moveTo', ((5.0, 4.0),)),
('lineTo', ((5.5, 4.0),)),
('lineTo', ((5.5, 6.0),)),
('lineTo', ((5.0, 6.0),)),
('endPath', ()),
('moveTo', ((6.5, 4.0),)),
('lineTo', ((7.5, 4.0),)),
('lineTo', ((7.5, 6.0),)),
('lineTo', ((6.5, 6.0),)),
('endPath', ()),
('moveTo', ((8.5, 4.0),)),
('lineTo', ((9.5, 4.0),)),
('lineTo', ((9.5, 6.0),)),
('lineTo', ((8.5, 6.0),)),
('endPath', ()),
),
),
(
'conic_2_quad',
(
Expand Down

0 comments on commit c5ed7c4

Please sign in to comment.