use crate::Blender;
use crate::{
prelude::*, scalar, BlendMode, Color, Color4f, ColorFilter, ColorSpace, ImageFilter,
MaskFilter, PathEffect, Shader,
};
use core::fmt;
use skia_bindings::{self as sb, SkPaint};
pub use sb::SkPaint_Style as Style;
variant_name!(Style::Fill);
pub use sb::SkPaint_Cap as Cap;
variant_name!(Cap::Butt);
pub use sb::SkPaint_Join as Join;
variant_name!(Join::Miter);
pub type Paint = Handle<SkPaint>;
unsafe_send_sync!(Paint);
impl NativeDrop for SkPaint {
fn drop(&mut self) {
unsafe { sb::C_SkPaint_destruct(self) }
}
}
impl NativeClone for SkPaint {
fn clone(&self) -> Self {
unsafe { SkPaint::new2(self) }
}
}
impl NativePartialEq for SkPaint {
fn eq(&self, rhs: &Self) -> bool {
unsafe { sb::C_SkPaint_Equals(self, rhs) }
}
}
impl Default for Handle<SkPaint> {
fn default() -> Self {
Paint::from_native_c(unsafe { SkPaint::new() })
}
}
impl fmt::Debug for Paint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Paint")
.field("is_anti_alias", &self.is_anti_alias())
.field("is_dither", &self.is_dither())
.field("style", &self.style())
.field("color", &self.color4f())
.field("stroke_width", &self.stroke_width())
.field("stroke_miter", &self.stroke_miter())
.field("stroke_cap", &self.stroke_cap())
.field("stroke_join", &self.stroke_join())
.field("color_filter", &self.color_filter())
.field("blend_mode", &self.as_blend_mode())
.field("path_effect", &self.path_effect())
.field("mask_filter", &self.mask_filter())
.field("image_filter", &self.image_filter())
.finish()
}
}
impl Paint {
pub fn new<'a>(
color: impl AsRef<Color4f>,
color_space: impl Into<Option<&'a ColorSpace>>,
) -> Paint {
let color_space = color_space.into();
Paint::from_native_c(unsafe {
SkPaint::new1(
color.as_ref().native(),
color_space.native_ptr_or_null_mut_force(),
)
})
}
pub fn reset(&mut self) -> &mut Self {
unsafe { self.native_mut().reset() }
self
}
pub fn is_anti_alias(&self) -> bool {
unsafe { self.native().__bindgen_anon_1.fBitfields.fAntiAlias() != 0 }
}
pub fn set_anti_alias(&mut self, anti_alias: bool) -> &mut Self {
unsafe {
self.native_mut()
.__bindgen_anon_1
.fBitfields
.set_fAntiAlias(anti_alias as _);
}
self
}
pub fn is_dither(&self) -> bool {
unsafe { self.native().__bindgen_anon_1.fBitfields.fDither() != 0 }
}
pub fn set_dither(&mut self, dither: bool) -> &mut Self {
unsafe {
self.native_mut()
.__bindgen_anon_1
.fBitfields
.set_fDither(dither as _);
}
self
}
pub fn style(&self) -> Style {
unsafe { sb::C_SkPaint_getStyle(self.native()) }
}
pub fn set_style(&mut self, style: Style) -> &mut Self {
unsafe { self.native_mut().setStyle(style) }
self
}
pub fn set_stroke(&mut self, stroke: bool) -> &mut Self {
unsafe { self.native_mut().setStroke(stroke) }
self
}
pub fn color(&self) -> Color {
self.color4f().to_color()
}
pub fn color4f(&self) -> Color4f {
Color4f::from_native_c(self.native().fColor4f)
}
pub fn set_color(&mut self, color: impl Into<Color>) -> &mut Self {
let color = color.into();
unsafe { self.native_mut().setColor(color.into_native()) }
self
}
pub fn set_color4f<'a>(
&mut self,
color: impl AsRef<Color4f>,
color_space: impl Into<Option<&'a ColorSpace>>,
) -> &mut Self {
let color_space: Option<&'a ColorSpace> = color_space.into();
unsafe {
self.native_mut().setColor1(
color.as_ref().native(),
color_space.native_ptr_or_null_mut_force(),
)
}
self
}
pub fn alpha_f(&self) -> f32 {
self.color4f().a
}
pub fn alpha(&self) -> u8 {
unsafe { sb::C_SkPaint_getAlpha(self.native()) }
}
pub fn set_alpha_f(&mut self, alpha: f32) -> &mut Self {
unsafe { self.native_mut().setAlphaf(alpha) }
self
}
pub fn set_alpha(&mut self, alpha: u8) -> &mut Self {
self.set_alpha_f(f32::from(alpha) * (1.0 / 255.0))
}
pub fn set_argb(&mut self, a: u8, r: u8, g: u8, b: u8) -> &mut Self {
unsafe {
self.native_mut()
.setARGB(a.into(), r.into(), g.into(), b.into())
}
self
}
pub fn stroke_width(&self) -> scalar {
self.native().fWidth
}
pub fn set_stroke_width(&mut self, width: scalar) -> &mut Self {
unsafe { self.native_mut().setStrokeWidth(width) }
self
}
pub fn stroke_miter(&self) -> scalar {
self.native().fMiterLimit
}
pub fn set_stroke_miter(&mut self, miter: scalar) -> &mut Self {
unsafe { self.native_mut().setStrokeMiter(miter) }
self
}
pub fn stroke_cap(&self) -> Cap {
unsafe { sb::C_SkPaint_getStrokeCap(self.native()) }
}
pub fn set_stroke_cap(&mut self, cap: Cap) -> &mut Self {
unsafe { self.native_mut().setStrokeCap(cap) }
self
}
pub fn stroke_join(&self) -> Join {
unsafe { sb::C_SkPaint_getStrokeJoin(self.native()) }
}
pub fn set_stroke_join(&mut self, join: Join) -> &mut Self {
unsafe { self.native_mut().setStrokeJoin(join) }
self
}
pub fn shader(&self) -> Option<Shader> {
Shader::from_unshared_ptr(self.native().fShader.fPtr)
}
pub fn set_shader(&mut self, shader: impl Into<Option<Shader>>) -> &mut Self {
unsafe { sb::C_SkPaint_setShader(self.native_mut(), shader.into().into_ptr_or_null()) }
self
}
pub fn color_filter(&self) -> Option<ColorFilter> {
ColorFilter::from_unshared_ptr(self.native().fColorFilter.fPtr)
}
pub fn set_color_filter(&mut self, color_filter: impl Into<Option<ColorFilter>>) -> &mut Self {
unsafe {
sb::C_SkPaint_setColorFilter(self.native_mut(), color_filter.into().into_ptr_or_null())
}
self
}
pub fn as_blend_mode(&self) -> Option<BlendMode> {
let mut bm = BlendMode::default();
unsafe { sb::C_SkPaint_asBlendMode(self.native(), &mut bm) }.if_true_some(bm)
}
pub fn blend_mode_or(&self, default_mode: BlendMode) -> BlendMode {
unsafe { self.native().getBlendMode_or(default_mode) }
}
#[deprecated(
since = "0.42.0",
note = "Use as_blend_mode() or blend_mode_or() instead."
)]
pub fn blend_mode(&self) -> BlendMode {
self.blend_mode_or(BlendMode::SrcOver)
}
pub fn is_src_over(&self) -> bool {
unsafe { self.native().isSrcOver() }
}
pub fn set_blend_mode(&mut self, mode: BlendMode) -> &mut Self {
unsafe { self.native_mut().setBlendMode(mode) }
self
}
pub fn blender(&self) -> Option<Blender> {
Blender::from_unshared_ptr(self.native().fBlender.fPtr)
}
pub fn set_blender(&mut self, blender: impl Into<Option<Blender>>) -> &mut Self {
unsafe { sb::C_SkPaint_setBlender(self.native_mut(), blender.into().into_ptr_or_null()) }
self
}
pub fn path_effect(&self) -> Option<PathEffect> {
PathEffect::from_unshared_ptr(self.native().fPathEffect.fPtr)
}
pub fn set_path_effect(&mut self, path_effect: impl Into<Option<PathEffect>>) -> &mut Self {
unsafe {
sb::C_SkPaint_setPathEffect(self.native_mut(), path_effect.into().into_ptr_or_null())
}
self
}
pub fn mask_filter(&self) -> Option<MaskFilter> {
MaskFilter::from_unshared_ptr(self.native().fMaskFilter.fPtr)
}
pub fn set_mask_filter(&mut self, mask_filter: impl Into<Option<MaskFilter>>) -> &mut Self {
unsafe {
sb::C_SkPaint_setMaskFilter(self.native_mut(), mask_filter.into().into_ptr_or_null())
}
self
}
pub fn image_filter(&self) -> Option<ImageFilter> {
ImageFilter::from_unshared_ptr(self.native().fImageFilter.fPtr)
}
pub fn set_image_filter(&mut self, image_filter: impl Into<Option<ImageFilter>>) -> &mut Self {
unsafe {
sb::C_SkPaint_setImageFilter(self.native_mut(), image_filter.into().into_ptr_or_null())
}
self
}
pub fn nothing_to_draw(&self) -> bool {
unsafe { self.native().nothingToDraw() }
}
}
#[test]
fn default_creation() {
let paint = Paint::default();
drop(paint)
}
#[test]
fn method_chaining_compiles() {
let mut paint = Paint::default();
let _paint = paint.reset().reset();
}
#[test]
fn union_flags() {
let mut paint = Paint::default();
assert!(!paint.is_anti_alias());
assert!(!paint.is_dither());
assert_eq!(paint.style(), Style::Fill);
{
paint.set_anti_alias(true);
assert!(paint.is_anti_alias());
assert!(!paint.is_dither());
assert_eq!(paint.style(), Style::Fill);
paint.set_anti_alias(false);
}
{
paint.set_style(Style::StrokeAndFill);
assert!(!paint.is_anti_alias());
assert!(!paint.is_dither());
assert_eq!(paint.style(), Style::StrokeAndFill);
paint.set_style(Style::Fill);
}
}
#[test]
fn set_color4f_color_space() {
let mut paint = Paint::default();
let color = Color4f::from(Color::DARK_GRAY);
let color_space = ColorSpace::new_srgb();
paint.set_color4f(color, None);
paint.set_color4f(color, &color_space);
let color2 = Color4f::from(Color::DARK_GRAY);
paint.set_color4f(color2, Some(&color_space));
}