#[cfg(not(target_arch = "wasm32"))]
use crate::backend::paint::PaintCache;
use crate::{
brush::BrushBackend,
font::{FontStyle, FontWeight, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE},
text::TextAlignment,
Float,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BlendMode {
SourceOver,
DestinationOver,
Source,
SourceIn,
DestinationIn,
SourceOut,
DestinationOut,
SourceAtop,
DestinationAtop,
Clear,
Xor,
Multiply,
Screen,
Overlay,
Darken,
Lighten,
ColorDodge,
ColorBurn,
HardLight,
SoftLight,
Difference,
Exclusion,
Hue,
Saturation,
Color,
Luminosity,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Color {
RGB(u8, u8, u8),
BGR(u8, u8, u8),
RGBA(u8, u8, u8, u8),
BGRA(u8, u8, u8, u8),
ARGB(u8, u8, u8, u8),
ABGR(u8, u8, u8, u8),
}
pub const BLACK: Color = Color::RGBA(0, 0, 0, 255);
pub const WHITE: Color = Color::RGBA(255, 255, 255, 255);
pub const RED: Color = Color::RGBA(255, 0, 0, 255);
pub const GREEN: Color = Color::RGBA(0, 255, 0, 255);
pub const BLUE: Color = Color::RGBA(0, 0, 255, 255);
pub const YELLOW: Color = Color::RGBA(255, 255, 0, 255);
pub const CYAN: Color = Color::RGBA(0, 255, 255, 255);
pub const MAGENTA: Color = Color::RGBA(255, 0, 255, 255);
pub const TRANSPARENT: Color = Color::RGBA(0, 0, 0, 0);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Cap {
Butt,
Round,
Square,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Join {
Miter,
Round,
Bevel,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DrawMode {
Fill,
Stroke,
FillStroke,
}
impl Color {
pub fn get_alpha(&self) -> u8 {
match self {
Color::RGB(_, _, _) => 255,
Color::BGR(_, _, _) => 255,
Color::RGBA(_, _, _, alpha) => *alpha,
Color::BGRA(_, _, _, alpha) => *alpha,
Color::ARGB(alpha, _, _, _) => *alpha,
Color::ABGR(alpha, _, _, _) => *alpha,
}
}
pub fn get_byte_value(&self) -> (u8, u8, u8, u8) {
match self {
Color::RGB(r, g, b) => (*r, *g, *b, 255),
Color::BGR(b, g, r) => (*r, *g, *b, 255),
Color::RGBA(r, g, b, a) => (*r, *g, *b, *a),
Color::BGRA(b, g, r, a) => (*r, *g, *b, *a),
Color::ARGB(a, r, g, b) => (*r, *g, *b, *a),
Color::ABGR(a, b, g, r) => (*r, *g, *b, *a),
}
}
pub fn get_float_value(&self) -> (Float, Float, Float, Float) {
let (r, g, b, a) = self.get_byte_value();
(r as Float / 255.0, g as Float / 255.0, b as Float / 255.0, a as Float / 255.0)
}
pub fn set_alpha(&mut self, alpha: u8) {
match self {
Color::RGB(r, g, b) => {
*self = Color::RGBA(*r, *g, *b, alpha);
}
Color::BGR(b, g, r) => {
*self = Color::BGRA(*b, *g, *r, alpha);
}
Color::RGBA(r, g, b, _) => {
*self = Color::RGBA(*r, *g, *b, alpha);
}
Color::BGRA(b, g, r, _) => {
*self = Color::BGRA(*b, *g, *r, alpha);
}
Color::ARGB(_, r, g, b) => {
*self = Color::ARGB(alpha, *r, *g, *b);
}
Color::ABGR(_, b, g, r) => {
*self = Color::ABGR(alpha, *b, *g, *r);
}
}
}
pub fn set_byte_value(&mut self, r: u8, g: u8, b: u8) {
match self {
Color::RGB(..) => {
*self = Color::RGB(r, g, b);
}
Color::BGR(..) => {
*self = Color::BGR(b, g, r);
}
Color::RGBA(_, _, _, a) => {
*self = Color::RGBA(r, g, b, *a);
}
Color::BGRA(_, _, _, a) => {
*self = Color::BGRA(b, g, r, *a);
}
Color::ARGB(a, _, _, _) => {
*self = Color::ARGB(*a, r, g, b);
}
Color::ABGR(a, _, _, _) => {
*self = Color::ABGR(*a, b, g, r);
}
}
}
pub fn set_color(&mut self, color: Color) {
let (r, g, b) = match color {
Color::RGB(r, g, b) => (r, g, b),
Color::BGR(b, g, r) => (r, g, b),
Color::RGBA(r, g, b, _) => (r, g, b),
Color::BGRA(b, g, r, _) => (r, g, b),
Color::ARGB(_, r, g, b) => (r, g, b),
Color::ABGR(_, b, g, r) => (r, g, b),
};
self.set_byte_value(r, g, b);
}
}
#[derive(Clone, Debug)]
pub(crate) struct Paint<TBrush: BrushBackend> {
#[cfg(not(target_arch = "wasm32"))]
opacity: Float,
blend_mode: BlendMode,
draw_mode: DrawMode,
#[cfg(not(target_arch = "wasm32"))]
line_dash: Option<Vec<Float>>,
#[cfg(not(target_arch = "wasm32"))]
line_dash_offset: Float,
#[cfg(not(target_arch = "wasm32"))]
miter_limit: Float,
smooth: bool,
stroke_cap: Cap,
stroke_join: Join,
#[cfg(not(target_arch = "wasm32"))]
stroke_width: Float,
brush: TBrush,
font_family: String,
font_size: Float,
font_style: FontStyle,
font_weight: FontWeight,
text_alignment: TextAlignment,
text_color: Color,
#[cfg(not(target_arch = "wasm32"))]
cache: PaintCache,
}
impl<TBrush: BrushBackend> Paint<TBrush> {
pub(crate) fn new() -> Self {
Paint {
#[cfg(not(target_arch = "wasm32"))]
opacity: 1.0,
blend_mode: BlendMode::SourceOver,
draw_mode: DrawMode::Fill,
#[cfg(not(target_arch = "wasm32"))]
line_dash: None,
#[cfg(not(target_arch = "wasm32"))]
line_dash_offset: 0.0,
#[cfg(not(target_arch = "wasm32"))]
miter_limit: 10.0,
smooth: true,
stroke_cap: Cap::Butt,
stroke_join: Join::Miter,
#[cfg(not(target_arch = "wasm32"))]
stroke_width: 1.0,
brush: TBrush::default(),
font_family: DEFAULT_FONT_FAMILY.to_string(),
font_size: DEFAULT_FONT_SIZE,
font_style: FontStyle::Normal,
font_weight: FontWeight::Normal,
text_alignment: TextAlignment::Left,
text_color: BLACK,
#[cfg(not(target_arch = "wasm32"))]
cache: PaintCache::default(),
}
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn get_opacity(&self) -> Float {
self.opacity
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn set_opacity(&mut self, opacity: Float) {
self.opacity = opacity.clamp(0.0, 1.0);
}
pub(crate) fn get_blend_mode(&self) -> BlendMode {
self.blend_mode
}
pub(crate) fn set_blend_mode(&mut self, mode: BlendMode) {
self.blend_mode = mode;
}
pub(crate) fn get_draw_mode(&self) -> DrawMode {
self.draw_mode
}
pub(crate) fn set_draw_mode(&mut self, mode: DrawMode) {
self.draw_mode = mode;
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn get_line_dash(&self) -> Option<&[Float]> {
self.line_dash.as_deref()
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn set_line_dash(&mut self, dashes: &[Float]) {
self.line_dash = Some(dashes.to_vec());
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn get_line_dash_offset(&self) -> Float {
self.line_dash_offset
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn set_line_dash_offset(&mut self, offset: Float) {
self.line_dash_offset = offset;
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn get_miter_limit(&self) -> Float {
self.miter_limit
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn set_miter_limit(&mut self, miter_limit: Float) {
self.miter_limit = miter_limit;
}
pub(crate) fn get_smooth(&self) -> bool {
self.smooth
}
pub(crate) fn set_smooth(&mut self, smooth: bool) {
self.smooth = smooth;
}
pub(crate) fn get_stroke_cap(&self) -> Cap {
self.stroke_cap
}
pub(crate) fn set_stroke_cap(&mut self, cap: Cap) {
self.stroke_cap = cap;
}
pub(crate) fn get_stroke_join(&self) -> Join {
self.stroke_join
}
pub(crate) fn set_stroke_join(&mut self, join: Join) {
self.stroke_join = join;
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn get_stroke_width(&self) -> Float {
self.stroke_width
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn set_stroke_width(&mut self, width: Float) {
self.stroke_width = width;
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn get_brush(&self) -> &TBrush {
&self.brush
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn get_brush_mut(&mut self) -> &mut TBrush {
&mut self.brush
}
pub(crate) fn set_brush(&mut self, brush: &TBrush) {
self.brush = brush.clone();
}
pub(crate) fn get_font_family(&self) -> &str {
&self.font_family
}
pub(crate) fn set_font_family(&mut self, font_family: &str) {
if self.font_family != font_family {
self.font_family = font_family.to_string();
#[cfg(not(target_arch = "wasm32"))]
self.cache.clear_font();
}
}
pub(crate) fn get_font_size(&self) -> Float {
self.font_size
}
pub(crate) fn set_font_size(&mut self, font_size: Float) {
if self.font_size != font_size {
self.font_size = font_size;
#[cfg(not(target_arch = "wasm32"))]
self.cache.clear_font();
}
}
pub(crate) fn get_font_style(&self) -> FontStyle {
self.font_style
}
pub(crate) fn set_font_style(&mut self, font_style: FontStyle) {
if self.font_style != font_style {
self.font_style = font_style;
#[cfg(not(target_arch = "wasm32"))]
self.cache.clear_font();
}
}
pub(crate) fn get_font_weight(&self) -> FontWeight {
self.font_weight
}
pub(crate) fn set_font_weight(&mut self, font_weight: FontWeight) {
if self.font_weight != font_weight {
self.font_weight = font_weight;
#[cfg(not(target_arch = "wasm32"))]
self.cache.clear_font();
}
}
pub(crate) fn get_text_alignment(&self) -> TextAlignment {
self.text_alignment
}
pub(crate) fn set_text_alignment(&mut self, text_alignment: TextAlignment) {
self.text_alignment = text_alignment;
}
pub(crate) fn get_text_color(&self) -> Color {
self.text_color
}
pub(crate) fn set_text_color(&mut self, color: Color) {
self.text_color = color;
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn cache(&self) -> &PaintCache {
&self.cache
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn cache_mut(&mut self) -> &mut PaintCache {
&mut self.cache
}
}