1use crate::{prelude::*, scalar, Matrix, NativeFlattenable, Path, Rect, StrokeRec};
2use sb::SkPathEffect_INHERITED;
3use skia_bindings::{self as sb, SkFlattenable, SkPathEffect, SkPathEffect_DashType, SkRefCntBase};
4use std::fmt;
5
6#[derive(Clone, PartialEq, Debug)]
7pub struct DashInfo {
8 pub intervals: Vec<scalar>,
9 pub phase: scalar,
10}
11
12pub type PathEffect = RCHandle<SkPathEffect>;
13unsafe_send_sync!(PathEffect);
14require_type_equality!(SkPathEffect_INHERITED, SkFlattenable);
15
16impl NativeBase<SkRefCntBase> for SkPathEffect {}
17impl NativeBase<SkFlattenable> for SkPathEffect {}
18
19impl NativeRefCountedBase for SkPathEffect {
20 type Base = SkRefCntBase;
21}
22
23impl NativeFlattenable for SkPathEffect {
24 fn native_flattenable(&self) -> &SkFlattenable {
25 self.base()
26 }
27
28 fn native_deserialize(data: &[u8]) -> *mut Self {
29 unsafe { sb::C_SkPathEffect_Deserialize(data:data.as_ptr() as _, length:data.len()) }
30 }
31}
32
33impl fmt::Debug for PathEffect {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 f&mut DebugStruct<'_, '_>.debug_struct("PathEffect")
36 .field("as_a_dash", &self.as_a_dash())
37 .field(name:"needs_ctm", &self.needs_ctm())
38 .finish()
39 }
40}
41
42impl PathEffect {
43 pub fn sum(first: impl Into<PathEffect>, second: impl Into<PathEffect>) -> PathEffect {
44 PathEffect::from_ptr(unsafe {
45 sb::C_SkPathEffect_MakeSum(first.into().into_ptr(), second.into().into_ptr())
46 })
47 .unwrap()
48 }
49
50 pub fn compose(first: impl Into<PathEffect>, second: impl Into<PathEffect>) -> PathEffect {
51 PathEffect::from_ptr(unsafe {
52 sb::C_SkPathEffect_MakeCompose(first.into().into_ptr(), second.into().into_ptr())
53 })
54 .unwrap()
55 }
56
57 // TODO: rename to to_a_dash()?
58 pub fn as_a_dash(&self) -> Option<DashInfo> {
59 let mut dash_info = construct(|di| unsafe { sb::C_SkPathEffect_DashInfo_Construct(di) });
60
61 let dash_type = unsafe { self.native().asADash(&mut dash_info) };
62
63 match dash_type {
64 SkPathEffect_DashType::kDash_DashType => {
65 let mut v: Vec<scalar> = vec![0.0; dash_info.fCount.try_into().unwrap()];
66 dash_info.fIntervals = v.as_mut_ptr();
67 unsafe {
68 assert_eq!(dash_type, self.native().asADash(&mut dash_info));
69 }
70 Some(DashInfo {
71 intervals: v,
72 phase: dash_info.fPhase,
73 })
74 }
75 SkPathEffect_DashType::kNone_DashType => None,
76 }
77 }
78
79 pub fn filter_path(
80 &self,
81 src: &Path,
82 stroke_rec: &StrokeRec,
83 cull_rect: impl AsRef<Rect>,
84 ) -> Option<(Path, StrokeRec)> {
85 let mut dst = Path::default();
86 let mut stroke_rec_r = stroke_rec.clone();
87 self.filter_path_inplace(&mut dst, src, &mut stroke_rec_r, cull_rect)
88 .if_true_some((dst, stroke_rec_r))
89 }
90
91 pub fn filter_path_inplace(
92 &self,
93 dst: &mut Path,
94 src: &Path,
95 stroke_rec: &mut StrokeRec,
96 cull_rect: impl AsRef<Rect>,
97 ) -> bool {
98 unsafe {
99 self.native().filterPath(
100 dst.native_mut(),
101 src.native(),
102 stroke_rec.native_mut(),
103 cull_rect.as_ref().native(),
104 )
105 }
106 }
107
108 pub fn filter_path_inplace_with_matrix(
109 &self,
110 dst: &mut Path,
111 src: &Path,
112 stroke_rec: &mut StrokeRec,
113 cull_rect: impl AsRef<Rect>,
114 ctm: &Matrix,
115 ) -> bool {
116 unsafe {
117 self.native().filterPath1(
118 dst.native_mut(),
119 src.native(),
120 stroke_rec.native_mut(),
121 cull_rect.as_ref().native(),
122 ctm.native(),
123 )
124 }
125 }
126
127 pub fn needs_ctm(&self) -> bool {
128 unsafe { self.native().needsCTM() }
129 }
130}
131