nona/
context.rs

1use crate::cache::PathCache;
2use crate::fonts::{FontId, Fonts, LayoutChar};
3use crate::renderer::{Renderer, Scissor, TextureType};
4use crate::{Color, Extent, NonaError, Point, Rect, Transform};
5use clamped::Clamp;
6use std::f32::consts::PI;
7
8pub type ImageId = usize;
9
10const KAPPA90: f32 = 0.5522847493;
11
12#[derive(Debug, Copy, Clone)]
13pub struct Paint {
14    pub xform: Transform,
15    pub extent: Extent,
16    pub radius: f32,
17    pub feather: f32,
18    pub inner_color: Color,
19    pub outer_color: Color,
20    pub image: Option<ImageId>,
21}
22
23#[derive(Debug, Copy, Clone)]
24pub enum Gradient {
25    Linear {
26        start: Point,
27        end: Point,
28        start_color: Color,
29        end_color: Color,
30    },
31    Radial {
32        center: Point,
33        in_radius: f32,
34        out_radius: f32,
35        inner_color: Color,
36        outer_color: Color,
37    },
38    Box {
39        rect: Rect,
40        radius: f32,
41        feather: f32,
42        inner_color: Color,
43        outer_color: Color,
44    },
45}
46
47#[derive(Debug, Copy, Clone)]
48pub struct ImagePattern {
49    pub center: Point,
50    pub size: Extent,
51    pub angle: f32,
52    pub img: ImageId,
53    pub alpha: f32,
54}
55
56impl From<Gradient> for Paint {
57    fn from(grad: Gradient) -> Self {
58        match grad {
59            Gradient::Linear {
60                start,
61                end,
62                start_color: inner_color,
63                end_color: outer_color,
64            } => {
65                const LARGE: f32 = 1e5;
66
67                let mut dx = end.x - start.x;
68                let mut dy = end.y - start.y;
69                let d = (dx * dx + dy * dy).sqrt();
70
71                if d > 0.0001 {
72                    dx /= d;
73                    dy /= d;
74                } else {
75                    dx = 0.0;
76                    dy = 1.0;
77                }
78
79                Paint {
80                    xform: Transform([dy, -dx, dx, dy, start.x - dx * LARGE, start.y - dy * LARGE]),
81                    extent: Extent {
82                        width: LARGE,
83                        height: LARGE + d * 0.5,
84                    },
85                    radius: 0.0,
86                    feather: d.max(1.0),
87                    inner_color,
88                    outer_color,
89                    image: None,
90                }
91            }
92            Gradient::Radial {
93                center,
94                in_radius,
95                out_radius,
96                inner_color,
97                outer_color,
98            } => {
99                let r = (in_radius + out_radius) * 0.5;
100                let f = out_radius - in_radius;
101                Paint {
102                    xform: Transform([1.0, 0.0, 0.0, 1.0, center.x, center.y]),
103                    extent: Extent {
104                        width: r,
105                        height: r,
106                    },
107                    radius: r,
108                    feather: f.max(1.0),
109                    inner_color,
110                    outer_color,
111                    image: None,
112                }
113            }
114            Gradient::Box {
115                rect,
116                radius,
117                feather,
118                inner_color,
119                outer_color,
120            } => {
121                let Rect { xy, size } = rect;
122                Paint {
123                    xform: Transform([
124                        1.0,
125                        0.0,
126                        0.0,
127                        1.0,
128                        xy.x + size.width * 0.5,
129                        xy.y + size.height * 0.5,
130                    ]),
131                    extent: Extent::new(size.width * 0.5, size.height * 0.5),
132                    radius,
133                    feather: feather.max(1.0),
134                    inner_color,
135                    outer_color,
136                    image: None,
137                }
138            }
139        }
140    }
141}
142
143impl From<ImagePattern> for Paint {
144    fn from(pat: ImagePattern) -> Self {
145        let mut xform = Transform::rotate(pat.angle);
146        xform.0[4] = pat.center.x;
147        xform.0[5] = pat.center.y;
148        Paint {
149            xform,
150            extent: pat.size,
151            radius: 0.0,
152            feather: 0.0,
153            inner_color: Color::rgba(1.0, 1.0, 1.0, pat.alpha),
154            outer_color: Color::rgba(1.0, 1.0, 1.0, pat.alpha),
155            image: Some(pat.img),
156        }
157    }
158}
159
160impl<T: Into<Color> + Clone> From<T> for Paint {
161    fn from(color: T) -> Self {
162        Paint {
163            xform: Transform::identity(),
164            extent: Default::default(),
165            radius: 0.0,
166            feather: 1.0,
167            inner_color: color.clone().into(),
168            outer_color: color.into(),
169            image: None,
170        }
171    }
172}
173
174#[derive(Debug, Copy, Clone, Eq, PartialEq)]
175pub enum Solidity {
176    Solid,
177    Hole,
178}
179
180#[derive(Debug, Copy, Clone, Eq, PartialEq)]
181pub enum LineJoin {
182    Miter,
183    Round,
184    Bevel,
185}
186
187#[derive(Debug, Copy, Clone, Eq, PartialEq)]
188pub enum LineCap {
189    Butt,
190    Round,
191    Square,
192}
193
194bitflags! {
195    pub struct Align: u32 {
196        const LEFT = 0x1;
197        const CENTER = 0x2;
198        const RIGHT = 0x4;
199        const TOP = 0x8;
200        const MIDDLE = 0x10;
201        const BOTTOM = 0x20;
202        const BASELINE = 0x40;
203    }
204}
205
206#[derive(Debug, Copy, Clone)]
207pub enum BlendFactor {
208    Zero,
209    One,
210    SrcColor,
211    OneMinusSrcColor,
212    DstColor,
213    OneMinusDstColor,
214    SrcAlpha,
215    OneMinusSrcAlpha,
216    DstAlpha,
217    OneMinusDstAlpha,
218    SrcAlphaSaturate,
219}
220
221#[derive(Debug, Copy, Clone)]
222pub enum BasicCompositeOperation {
223    SrcOver,
224    SrcIn,
225    SrcOut,
226    Atop,
227    DstOver,
228    DstIn,
229    DstOut,
230    DstAtop,
231    Lighter,
232    Copy,
233    Xor,
234}
235
236#[derive(Debug, Copy, Clone)]
237pub enum CompositeOperation {
238    Basic(BasicCompositeOperation),
239    BlendFunc {
240        src: BlendFactor,
241        dst: BlendFactor,
242    },
243    BlendFuncSeparate {
244        src_rgb: BlendFactor,
245        dst_rgb: BlendFactor,
246        src_alpha: BlendFactor,
247        dst_alpha: BlendFactor,
248    },
249}
250
251impl Into<CompositeOperationState> for CompositeOperation {
252    fn into(self) -> CompositeOperationState {
253        match self {
254            CompositeOperation::Basic(op) => {
255                let (src_factor, dst_factor) = match op {
256                    BasicCompositeOperation::SrcOver => {
257                        (BlendFactor::One, BlendFactor::OneMinusSrcAlpha)
258                    }
259                    BasicCompositeOperation::SrcIn => (BlendFactor::DstAlpha, BlendFactor::Zero),
260                    BasicCompositeOperation::SrcOut => {
261                        (BlendFactor::OneMinusDstAlpha, BlendFactor::Zero)
262                    }
263                    BasicCompositeOperation::Atop => {
264                        (BlendFactor::DstAlpha, BlendFactor::OneMinusSrcAlpha)
265                    }
266                    BasicCompositeOperation::DstOver => {
267                        (BlendFactor::OneMinusDstAlpha, BlendFactor::One)
268                    }
269                    BasicCompositeOperation::DstIn => (BlendFactor::Zero, BlendFactor::SrcAlpha),
270                    BasicCompositeOperation::DstOut => {
271                        (BlendFactor::Zero, BlendFactor::OneMinusSrcAlpha)
272                    }
273                    BasicCompositeOperation::DstAtop => {
274                        (BlendFactor::OneMinusDstAlpha, BlendFactor::SrcAlpha)
275                    }
276                    BasicCompositeOperation::Lighter => (BlendFactor::One, BlendFactor::One),
277                    BasicCompositeOperation::Copy => (BlendFactor::One, BlendFactor::Zero),
278                    BasicCompositeOperation::Xor => {
279                        (BlendFactor::OneMinusDstAlpha, BlendFactor::OneMinusSrcAlpha)
280                    }
281                };
282
283                CompositeOperationState {
284                    src_rgb: src_factor,
285                    dst_rgb: dst_factor,
286                    src_alpha: src_factor,
287                    dst_alpha: dst_factor,
288                }
289            }
290            CompositeOperation::BlendFunc { src, dst } => CompositeOperationState {
291                src_rgb: src,
292                dst_rgb: dst,
293                src_alpha: src,
294                dst_alpha: dst,
295            },
296            CompositeOperation::BlendFuncSeparate {
297                src_rgb,
298                dst_rgb,
299                src_alpha,
300                dst_alpha,
301            } => CompositeOperationState {
302                src_rgb,
303                dst_rgb,
304                src_alpha,
305                dst_alpha,
306            },
307        }
308    }
309}
310
311#[derive(Debug, Copy, Clone)]
312pub struct CompositeOperationState {
313    pub src_rgb: BlendFactor,
314    pub dst_rgb: BlendFactor,
315    pub src_alpha: BlendFactor,
316    pub dst_alpha: BlendFactor,
317}
318
319bitflags! {
320    pub struct ImageFlags: u32 {
321        const GENERATE_MIPMAPS = 0x1;
322        const REPEATX = 0x2;
323        const REPEATY = 0x4;
324        const FLIPY	= 0x8;
325        const PREMULTIPLIED = 0x10;
326        const NEAREST = 0x20;
327    }
328}
329
330#[derive(Debug, Copy, Clone, Default)]
331pub struct Vertex {
332    pub x: f32,
333    pub y: f32,
334    pub u: f32,
335    pub v: f32,
336}
337
338impl Vertex {
339    pub fn new(x: f32, y: f32, u: f32, v: f32) -> Vertex {
340        Vertex { x, y, u, v }
341    }
342}
343
344#[derive(Debug, Copy, Clone)]
345pub struct Path {
346    pub(crate) first: usize,
347    pub(crate) count: usize,
348    pub(crate) closed: bool,
349    pub(crate) num_bevel: usize,
350    pub(crate) solidity: Solidity,
351    pub(crate) fill: *mut Vertex,
352    pub(crate) num_fill: usize,
353    pub(crate) stroke: *mut Vertex,
354    pub(crate) num_stroke: usize,
355    pub convex: bool,
356}
357
358impl Path {
359    pub fn get_fill(&self) -> &[Vertex] {
360        if self.fill.is_null() {
361            &[]
362        } else {
363            unsafe { std::slice::from_raw_parts_mut(self.fill, self.num_fill) }
364        }
365    }
366
367    pub fn get_stroke(&self) -> &[Vertex] {
368        if self.stroke.is_null() {
369            &[]
370        } else {
371            unsafe { std::slice::from_raw_parts_mut(self.stroke, self.num_stroke) }
372        }
373    }
374}
375
376#[derive(Copy, Clone)]
377pub struct TextMetrics {
378    pub ascender: f32,
379    pub descender: f32,
380    pub line_gap: f32,
381}
382
383impl TextMetrics {
384    pub fn line_height(&self) -> f32 {
385        self.ascender - self.descender + self.line_gap
386    }
387}
388
389#[derive(Clone)]
390struct State {
391    composite_operation: CompositeOperationState,
392    shape_antialias: bool,
393    fill: Paint,
394    stroke: Paint,
395    stroke_width: f32,
396    miter_limit: f32,
397    line_join: LineJoin,
398    line_cap: LineCap,
399    alpha: f32,
400    xform: Transform,
401    scissor: Scissor,
402    font_size: f32,
403    letter_spacing: f32,
404    line_height: f32,
405    text_align: Align,
406    font_id: FontId,
407}
408
409impl Default for State {
410    fn default() -> Self {
411        State {
412            composite_operation: CompositeOperation::Basic(BasicCompositeOperation::SrcOver).into(),
413            shape_antialias: true,
414            fill: Color::rgb(1.0, 1.0, 1.0).into(),
415            stroke: Color::rgb(0.0, 0.0, 0.0).into(),
416            stroke_width: 1.0,
417            miter_limit: 10.0,
418            line_join: LineJoin::Miter,
419            line_cap: LineCap::Butt,
420            alpha: 1.0,
421            xform: Transform::identity(),
422            scissor: Scissor {
423                xform: Default::default(),
424                extent: Extent {
425                    width: -1.0,
426                    height: -1.0,
427                },
428            },
429            font_size: 16.0,
430            letter_spacing: 0.0,
431            line_height: 1.0,
432            text_align: Align::LEFT | Align::BASELINE,
433            font_id: 0,
434        }
435    }
436}
437
438#[derive(Debug)]
439pub(crate) enum Command {
440    MoveTo(Point),
441    LineTo(Point),
442    BezierTo(Point, Point, Point),
443    Close,
444    Solidity(Solidity),
445}
446
447pub struct Context {
448    commands: Vec<Command>,
449    last_position: Point,
450    states: Vec<State>,
451    cache: PathCache,
452    tess_tol: f32,
453    dist_tol: f32,
454    fringe_width: f32,
455    device_pixel_ratio: f32,
456    fonts: Fonts,
457    layout_chars: Vec<LayoutChar>,
458    draw_call_count: usize,
459    fill_triangles_count: usize,
460    stroke_triangles_count: usize,
461    text_triangles_count: usize,
462}
463
464pub struct Canvas<'a, R: Renderer> {
465    context: &'a mut Context,
466    renderer: &'a mut R,
467}
468
469impl<'a, R: Renderer> std::ops::Deref for Canvas<'a, R> {
470    type Target = Context;
471
472    fn deref(&self) -> &Self::Target {
473        self.context
474    }
475}
476impl<R: Renderer> std::ops::DerefMut for Canvas<'_, R> {
477    fn deref_mut(&mut self) -> &mut Self::Target {
478        self.context
479    }
480}
481
482impl<'a, R: Renderer> Canvas<'a, R> {
483    pub fn begin_frame(&mut self, clear_color: Option<Color>) -> Result<(), NonaError> {
484        self.context.begin_frame(self.renderer, clear_color)
485    }
486
487    pub fn end_frame(&mut self) -> Result<(), NonaError> {
488        self.context.end_frame(self.renderer)
489    }
490
491    pub fn create_image<D: AsRef<[u8]>>(
492        &mut self,
493        flags: ImageFlags,
494        data: D,
495    ) -> Result<ImageId, NonaError> {
496        self.context.create_image(self.renderer, flags, data)
497    }
498
499    pub fn update_image(&mut self, img: ImageId, data: &[u8]) -> Result<(), NonaError> {
500        self.context.update_image(self.renderer, img, data)
501    }
502
503    pub fn image_size(&self, img: ImageId) -> Result<(usize, usize), NonaError> {
504        self.context.image_size(self.renderer, img)
505    }
506
507    pub fn delete_image(&mut self, img: ImageId) -> Result<(), NonaError> {
508        self.context.delete_image(self.renderer, img)
509    }
510
511    pub fn fill(&mut self) -> Result<(), NonaError> {
512        self.context.fill(self.renderer)
513    }
514
515    pub fn stroke(&mut self) -> Result<(), NonaError> {
516        self.context.stroke(self.renderer)
517    }
518
519    pub fn text<S: AsRef<str>, P: Into<Point>>(&mut self, pt: P, text: S) -> Result<(), NonaError> {
520        self.context.text(self.renderer, pt, text)
521    }
522}
523
524impl Context {
525    pub fn create<R: Renderer>(renderer: &mut R) -> Result<Context, NonaError> {
526        let fonts = Fonts::new(renderer)?;
527        Ok(Context {
528            commands: Default::default(),
529            last_position: Default::default(),
530            states: vec![Default::default()],
531            cache: Default::default(),
532            tess_tol: 0.0,
533            dist_tol: 0.0,
534            fringe_width: 0.0,
535            device_pixel_ratio: 0.0,
536            fonts,
537            layout_chars: Default::default(),
538            draw_call_count: 0,
539            fill_triangles_count: 0,
540            stroke_triangles_count: 0,
541            text_triangles_count: 0,
542        })
543    }
544
545    fn set_device_pixel_ratio(&mut self, ratio: f32) {
546        self.tess_tol = 0.25 / ratio;
547        self.dist_tol = 0.01 / ratio;
548        self.fringe_width = 1.0 / ratio;
549        self.device_pixel_ratio = ratio;
550    }
551
552    pub fn attach_renderer<R: Renderer>(
553        &mut self,
554        renderer: &mut R,
555        call: impl Fn(&mut Canvas<R>),
556    ) {
557        let mut canvas = Canvas {
558            context: self,
559            renderer,
560        };
561        call(&mut canvas)
562    }
563
564    pub fn begin_frame<R: Renderer>(
565        &mut self,
566        renderer: &mut R,
567        clear_color: Option<Color>,
568    ) -> Result<(), NonaError> {
569        let device_pixel_ratio = {
570            renderer.viewport(renderer.view_size().into(), renderer.device_pixel_ratio())?;
571            if let Some(color) = clear_color {
572                renderer.clear_screen(color)
573            }
574            renderer.device_pixel_ratio()
575        };
576        self.set_device_pixel_ratio(device_pixel_ratio);
577        self.states.clear();
578        self.states.push(Default::default());
579        self.draw_call_count = 0;
580        self.fill_triangles_count = 0;
581        self.stroke_triangles_count = 0;
582        self.text_triangles_count = 0;
583        Ok(())
584    }
585
586    pub fn end_frame<R: Renderer>(&mut self, renderer: &mut R) -> Result<(), NonaError> {
587        renderer.flush()
588    }
589
590    pub fn save(&mut self) {
591        if let Some(last) = self.states.last() {
592            let last = last.clone();
593            self.states.push(last);
594        }
595    }
596
597    pub fn restore(&mut self) {
598        if self.states.len() <= 1 {
599            return;
600        }
601        self.states.pop();
602    }
603
604    fn state(&mut self) -> &State {
605        self.states.last().unwrap()
606    }
607
608    fn state_mut(&mut self) -> &mut State {
609        self.states.last_mut().unwrap()
610    }
611
612    pub fn reset(&mut self) {
613        *self.state_mut() = Default::default();
614    }
615
616    pub fn shape_antialias(&mut self, enabled: bool) {
617        self.state_mut().shape_antialias = enabled;
618    }
619
620    pub fn stroke_width(&mut self, width: f32) {
621        self.state_mut().stroke_width = width;
622    }
623
624    pub fn miter_limit(&mut self, limit: f32) {
625        self.state_mut().miter_limit = limit;
626    }
627
628    pub fn line_cap(&mut self, cap: LineCap) {
629        self.state_mut().line_cap = cap;
630    }
631
632    pub fn line_join(&mut self, join: LineJoin) {
633        self.state_mut().line_join = join;
634    }
635
636    pub fn global_alpha(&mut self, alpha: f32) {
637        self.state_mut().alpha = alpha;
638    }
639
640    pub fn transform(&mut self, xform: Transform) {
641        let state = self.state_mut();
642        state.xform = xform * state.xform;
643    }
644
645    pub fn reset_transform(&mut self) {
646        self.state_mut().xform = Transform::identity();
647    }
648
649    pub fn translate(&mut self, tx: f32, ty: f32) {
650        self.transform(Transform::translate(tx, ty));
651    }
652
653    pub fn rotate(&mut self, angle: f32) {
654        self.transform(Transform::rotate(angle));
655    }
656
657    pub fn skew_x(&mut self, angle: f32) {
658        self.transform(Transform::skew_x(angle));
659    }
660
661    pub fn skew_y(&mut self, angle: f32) {
662        self.transform(Transform::skew_y(angle));
663    }
664
665    pub fn scale(&mut self, sx: f32, sy: f32) {
666        self.transform(Transform::scale(sx, sy));
667    }
668
669    pub fn current_transform(&mut self) -> Transform {
670        self.state().xform
671    }
672
673    pub fn stroke_paint<T: Into<Paint>>(&mut self, paint: T) {
674        let mut paint = paint.into();
675        paint.xform *= self.state().xform;
676        self.state_mut().stroke = paint;
677    }
678
679    pub fn fill_paint<T: Into<Paint>>(&mut self, paint: T) {
680        let mut paint = paint.into();
681        paint.xform *= self.state().xform;
682        self.state_mut().fill = paint;
683    }
684
685    pub fn create_image<D: AsRef<[u8]>, R: Renderer>(
686        &mut self,
687        renderer: &mut R,
688        flags: ImageFlags,
689        data: D,
690    ) -> Result<ImageId, NonaError> {
691        let img = image::load_from_memory(data.as_ref())
692            .map_err(|err| NonaError::Texture(err.to_string()))?;
693        let img = img.to_rgba8();
694        let dimensions = img.dimensions();
695        let img = renderer.create_texture(
696            TextureType::RGBA,
697            dimensions.0 as usize,
698            dimensions.1 as usize,
699            flags,
700            Some(&img.into_raw()),
701        )?;
702        Ok(img)
703    }
704
705    pub fn create_image_from_file<P: AsRef<std::path::Path>, R: Renderer>(
706        &mut self,
707        renderer: &mut R,
708        flags: ImageFlags,
709        path: P,
710    ) -> Result<ImageId, NonaError> {
711        self.create_image(
712            renderer,
713            flags,
714            std::fs::read(path)
715                .map_err(|err| NonaError::Texture(format!("Error loading image: {}", err)))?,
716        )
717    }
718
719    pub fn update_image<R: Renderer>(
720        &mut self,
721        renderer: &mut R,
722        img: ImageId,
723        data: &[u8],
724    ) -> Result<(), NonaError> {
725        let (w, h) = renderer.texture_size(img.clone())?;
726        renderer.update_texture(img, 0, 0, w, h, data)?;
727        Ok(())
728    }
729
730    pub fn image_size<R: Renderer>(
731        &self,
732        renderer: &R,
733        img: ImageId,
734    ) -> Result<(usize, usize), NonaError> {
735        let res = renderer.texture_size(img)?;
736        Ok(res)
737    }
738
739    pub fn delete_image<R: Renderer>(
740        &mut self,
741        renderer: &mut R,
742        img: ImageId,
743    ) -> Result<(), NonaError> {
744        renderer.delete_texture(img)?;
745        Ok(())
746    }
747
748    pub fn scissor<T: Into<Rect>>(&mut self, rect: T) {
749        let rect = rect.into();
750        let state = self.state_mut();
751        let x = rect.xy.x;
752        let y = rect.xy.y;
753        let width = rect.size.width.max(0.0);
754        let height = rect.size.height.max(0.0);
755        state.scissor.xform = Transform::identity();
756        state.scissor.xform.0[4] = x + width * 0.5;
757        state.scissor.xform.0[5] = y + height * 0.5;
758        state.scissor.xform *= state.xform;
759        state.scissor.extent.width = width * 0.5;
760        state.scissor.extent.height = height * 0.5;
761    }
762
763    pub fn intersect_scissor<T: Into<Rect>>(&mut self, rect: T) {
764        let rect = rect.into();
765        let state = self.state_mut();
766
767        if state.scissor.extent.width < 0.0 {
768            self.scissor(rect);
769            return;
770        }
771
772        let Extent {
773            width: ex,
774            height: ey,
775        } = state.scissor.extent;
776        let invxorm = state.xform.inverse();
777        let pxform = state.scissor.xform * invxorm;
778        let tex = ex * pxform.0[0].abs() + ey * pxform.0[2].abs();
779        let tey = ex * pxform.0[1].abs() + ey * pxform.0[3].abs();
780        self.scissor(
781            Rect::new(
782                Point::new(pxform.0[4] - tex, pxform.0[5] - tey),
783                Extent::new(tex * 2.0, tey * 2.0),
784            )
785            .intersect(rect),
786        );
787    }
788
789    pub fn reset_scissor(&mut self) {
790        let state = self.state_mut();
791        state.scissor.xform = Transform::default();
792        state.scissor.extent.width = -1.0;
793        state.scissor.extent.height = -1.0;
794    }
795
796    pub fn global_composite_operation(&mut self, op: CompositeOperation) {
797        self.state_mut().composite_operation = op.into();
798    }
799
800    fn append_command(&mut self, cmd: Command) {
801        let state = self.states.last().unwrap();
802        let xform = &state.xform;
803        match cmd {
804            Command::MoveTo(pt) => {
805                self.commands
806                    .push(Command::MoveTo(xform.transform_point(pt)));
807                self.last_position = pt;
808            }
809            Command::LineTo(pt) => {
810                self.commands
811                    .push(Command::LineTo(xform.transform_point(pt)));
812                self.last_position = pt;
813            }
814            Command::BezierTo(pt1, pt2, pt3) => {
815                self.last_position = pt3;
816                self.commands.push(Command::BezierTo(
817                    xform.transform_point(pt1),
818                    xform.transform_point(pt2),
819                    xform.transform_point(pt3),
820                ));
821            }
822            _ => {
823                self.commands.push(cmd);
824            }
825        }
826    }
827
828    pub fn begin_path(&mut self) {
829        self.commands.clear();
830        self.cache.clear();
831    }
832
833    pub fn move_to<P: Into<Point>>(&mut self, pt: P) {
834        self.append_command(Command::MoveTo(pt.into()));
835    }
836
837    pub fn line_to<P: Into<Point>>(&mut self, pt: P) {
838        self.append_command(Command::LineTo(pt.into()));
839    }
840
841    pub fn bezier_to<P: Into<Point>>(&mut self, cp1: P, cp2: P, pt: P) {
842        self.append_command(Command::BezierTo(cp1.into(), cp2.into(), pt.into()));
843    }
844
845    pub fn quad_to<P: Into<Point>>(&mut self, cp: P, pt: P) {
846        let x0 = self.last_position.x;
847        let y0 = self.last_position.y;
848        let cp = cp.into();
849        let pt = pt.into();
850        self.append_command(Command::BezierTo(
851            Point::new(x0 + 2.0 / 3.0 * (cp.x - x0), y0 + 2.0 / 3.0 * (cp.y - y0)),
852            Point::new(
853                pt.x + 2.0 / 3.0 * (cp.x - pt.x),
854                pt.y + 2.0 / 3.0 * (cp.y - pt.y),
855            ),
856            pt,
857        ));
858    }
859
860    pub fn arc_to<P: Into<Point>>(&mut self, pt1: P, pt2: P, radius: f32) {
861        let pt0 = self.last_position;
862
863        if self.commands.is_empty() {
864            return;
865        }
866
867        let pt1 = pt1.into();
868        let pt2 = pt2.into();
869        if pt0.equals(pt1, self.dist_tol)
870            || pt1.equals(pt2, self.dist_tol)
871            || pt1.dist_pt_seg(pt0, pt2) < self.dist_tol * self.dist_tol
872            || radius < self.dist_tol
873        {
874            self.line_to(pt1);
875            return;
876        }
877
878        let d0 = Point::new(pt0.x - pt1.x, pt0.y - pt1.y);
879        let d1 = Point::new(pt2.x - pt1.x, pt2.y - pt1.y);
880        let a = (d0.x * d1.x + d0.y * d1.y).cos();
881        let d = radius / (a / 2.0).tan();
882
883        if d > 10000.0 {
884            self.line_to(pt1);
885            return;
886        }
887
888        let (cx, cy, a0, a1, dir) = if Point::cross(d0, d1) > 0.0 {
889            (
890                pt1.x + d0.x * d + d0.y * radius,
891                pt1.y + d0.y * d + -d0.x * radius,
892                d0.x.atan2(-d0.y),
893                -d1.x.atan2(d1.y),
894                Solidity::Hole,
895            )
896        } else {
897            (
898                pt1.x + d0.x * d + -d0.y * radius,
899                pt1.y + d0.y * d + d0.x * radius,
900                -d0.x.atan2(d0.y),
901                d1.x.atan2(-d1.y),
902                Solidity::Solid,
903            )
904        };
905
906        self.arc(Point::new(cx, cy), radius, a0, a1, dir);
907    }
908
909    pub fn close_path(&mut self) {
910        self.commands.push(Command::Close);
911    }
912
913    pub fn path_solidity(&mut self, dir: Solidity) {
914        self.commands.push(Command::Solidity(dir));
915    }
916
917    pub fn arc<P: Into<Point>>(&mut self, cp: P, radius: f32, a0: f32, a1: f32, dir: Solidity) {
918        let cp = cp.into();
919        let move_ = self.commands.is_empty();
920
921        let mut da = a1 - a0;
922        if dir == Solidity::Hole {
923            if da.abs() >= PI * 2.0 {
924                da = PI * 2.0;
925            } else {
926                while da < 0.0 {
927                    da += PI * 2.0;
928                }
929            }
930        } else {
931            if da.abs() >= PI * 2.0 {
932                da = -PI * 2.0;
933            } else {
934                while da > 0.0 {
935                    da -= PI * 2.0;
936                }
937            }
938        }
939
940        let ndivs = ((da.abs() / (PI * 0.5) + 0.5) as i32).min(5).max(1);
941        let hda = (da / (ndivs as f32)) / 2.0;
942        let mut kappa = (4.0 / 3.0 * (1.0 - hda.cos()) / hda.sin()).abs();
943
944        if dir == Solidity::Solid {
945            kappa = -kappa;
946        }
947
948        let mut px = 0.0;
949        let mut py = 0.0;
950        let mut ptanx = 0.0;
951        let mut ptany = 0.0;
952
953        for i in 0..=ndivs {
954            let a = a0 + da * ((i as f32) / (ndivs as f32));
955            let dx = a.cos();
956            let dy = a.sin();
957            let x = cp.x + dx * radius;
958            let y = cp.y + dy * radius;
959            let tanx = -dy * radius * kappa;
960            let tany = dx * radius * kappa;
961
962            if i == 0 {
963                if move_ {
964                    self.append_command(Command::MoveTo(Point::new(x, y)));
965                } else {
966                    self.append_command(Command::LineTo(Point::new(x, y)));
967                }
968            } else {
969                self.append_command(Command::BezierTo(
970                    Point::new(px + ptanx, py + ptany),
971                    Point::new(x - tanx, y - tany),
972                    Point::new(x, y),
973                ));
974            }
975            px = x;
976            py = y;
977            ptanx = tanx;
978            ptany = tany;
979        }
980    }
981
982    pub fn rect<T: Into<Rect>>(&mut self, rect: T) {
983        let rect = rect.into();
984        self.append_command(Command::MoveTo(Point::new(rect.xy.x, rect.xy.y)));
985        self.append_command(Command::LineTo(Point::new(
986            rect.xy.x,
987            rect.xy.y + rect.size.height,
988        )));
989        self.append_command(Command::LineTo(Point::new(
990            rect.xy.x + rect.size.width,
991            rect.xy.y + rect.size.height,
992        )));
993        self.append_command(Command::LineTo(Point::new(
994            rect.xy.x + rect.size.width,
995            rect.xy.y,
996        )));
997        self.append_command(Command::Close);
998    }
999
1000    pub fn rounded_rect<T: Into<Rect>>(&mut self, rect: T, radius: f32) {
1001        let rect = rect.into();
1002        self.rounded_rect_varying(rect, radius, radius, radius, radius);
1003    }
1004
1005    pub fn rounded_rect_varying<T: Into<Rect>>(
1006        &mut self,
1007        rect: T,
1008        lt: f32,
1009        rt: f32,
1010        rb: f32,
1011        lb: f32,
1012    ) {
1013        let rect = rect.into();
1014        if lt < 0.1 && rt < 0.1 && lb < 0.1 && rb < 0.1 {
1015            self.rect(rect);
1016        } else {
1017            let halfw = rect.size.width.abs() * 0.5;
1018            let halfh = rect.size.height.abs() * 0.5;
1019            let rxlb = lb.min(halfw) * rect.size.width.signum();
1020            let rylb = lb.min(halfh) * rect.size.height.signum();
1021            let rxrb = rb.min(halfw) * rect.size.width.signum();
1022            let ryrb = rb.min(halfh) * rect.size.height.signum();
1023            let rxrt = rt.min(halfw) * rect.size.width.signum();
1024            let ryrt = rt.min(halfh) * rect.size.height.signum();
1025            let rxlt = lt.min(halfw) * rect.size.width.signum();
1026            let rylt = lt.min(halfh) * rect.size.height.signum();
1027
1028            self.append_command(Command::MoveTo(Point::new(rect.xy.x, rect.xy.y + rylt)));
1029            self.append_command(Command::LineTo(Point::new(
1030                rect.xy.x,
1031                rect.xy.y + rect.size.height - rylb,
1032            )));
1033            self.append_command(Command::BezierTo(
1034                Point::new(
1035                    rect.xy.x,
1036                    rect.xy.y + rect.size.height - rylb * (1.0 - KAPPA90),
1037                ),
1038                Point::new(
1039                    rect.xy.x + rxlb * (1.0 - KAPPA90),
1040                    rect.xy.y + rect.size.height,
1041                ),
1042                Point::new(rect.xy.x + rxlb, rect.xy.y + rect.size.height),
1043            ));
1044            self.append_command(Command::LineTo(Point::new(
1045                rect.xy.x + rect.size.width - rxrb,
1046                rect.xy.y + rect.size.height,
1047            )));
1048            self.append_command(Command::BezierTo(
1049                Point::new(
1050                    rect.xy.x + rect.size.width - rxrb * (1.0 - KAPPA90),
1051                    rect.xy.y + rect.size.height,
1052                ),
1053                Point::new(
1054                    rect.xy.x + rect.size.width,
1055                    rect.xy.y + rect.size.height - ryrb * (1.0 - KAPPA90),
1056                ),
1057                Point::new(
1058                    rect.xy.x + rect.size.width,
1059                    rect.xy.y + rect.size.height - ryrb,
1060                ),
1061            ));
1062            self.append_command(Command::LineTo(Point::new(
1063                rect.xy.x + rect.size.width,
1064                rect.xy.y + ryrt,
1065            )));
1066            self.append_command(Command::BezierTo(
1067                Point::new(
1068                    rect.xy.x + rect.size.width,
1069                    rect.xy.y + ryrt * (1.0 - KAPPA90),
1070                ),
1071                Point::new(
1072                    rect.xy.x + rect.size.width - rxrt * (1.0 - KAPPA90),
1073                    rect.xy.y,
1074                ),
1075                Point::new(rect.xy.x + rect.size.width - rxrt, rect.xy.y),
1076            ));
1077            self.append_command(Command::LineTo(Point::new(rect.xy.x + rxlt, rect.xy.y)));
1078            self.append_command(Command::BezierTo(
1079                Point::new(rect.xy.x + rxlt * (1.0 - KAPPA90), rect.xy.y),
1080                Point::new(rect.xy.x, rect.xy.y + rylt * (1.0 - KAPPA90)),
1081                Point::new(rect.xy.x, rect.xy.y + rylt),
1082            ));
1083            self.append_command(Command::Close);
1084        }
1085    }
1086
1087    pub fn ellipse<P: Into<Point>>(&mut self, center: P, radius_x: f32, radius_y: f32) {
1088        let center = center.into();
1089        self.append_command(Command::MoveTo(Point::new(center.x - radius_x, center.y)));
1090        self.append_command(Command::BezierTo(
1091            Point::new(center.x - radius_x, center.y + radius_y * KAPPA90),
1092            Point::new(center.x - radius_x * KAPPA90, center.y + radius_y),
1093            Point::new(center.x, center.y + radius_y),
1094        ));
1095        self.append_command(Command::BezierTo(
1096            Point::new(center.x + radius_x * KAPPA90, center.y + radius_y),
1097            Point::new(center.x + radius_x, center.y + radius_y * KAPPA90),
1098            Point::new(center.x + radius_x, center.y),
1099        ));
1100        self.append_command(Command::BezierTo(
1101            Point::new(center.x + radius_x, center.y - radius_y * KAPPA90),
1102            Point::new(center.x + radius_x * KAPPA90, center.y - radius_y),
1103            Point::new(center.x, center.y - radius_y),
1104        ));
1105        self.append_command(Command::BezierTo(
1106            Point::new(center.x - radius_x * KAPPA90, center.y - radius_y),
1107            Point::new(center.x - radius_x, center.y - radius_y * KAPPA90),
1108            Point::new(center.x - radius_x, center.y),
1109        ));
1110        self.append_command(Command::Close);
1111    }
1112
1113    pub fn circle<P: Into<Point>>(&mut self, center: P, radius: f32) {
1114        self.ellipse(center.into(), radius, radius);
1115    }
1116
1117    pub fn fill<R: Renderer>(&mut self, renderer: &mut R) -> Result<(), NonaError> {
1118        let state = self.states.last_mut().unwrap();
1119        let mut fill_paint = state.fill.clone();
1120
1121        self.cache
1122            .flatten_paths(&self.commands, self.dist_tol, self.tess_tol);
1123        if renderer.edge_antialias() && state.shape_antialias {
1124            self.cache
1125                .expand_fill(self.fringe_width, LineJoin::Miter, 2.4, self.fringe_width);
1126        } else {
1127            self.cache
1128                .expand_fill(0.0, LineJoin::Miter, 2.4, self.fringe_width);
1129        }
1130
1131        fill_paint.inner_color.a *= state.alpha;
1132        fill_paint.outer_color.a *= state.alpha;
1133
1134        renderer.fill(
1135            &fill_paint,
1136            state.composite_operation,
1137            &state.scissor,
1138            self.fringe_width,
1139            self.cache.bounds,
1140            &self.cache.paths,
1141        )?;
1142
1143        for path in &self.cache.paths {
1144            if path.num_fill > 2 {
1145                self.fill_triangles_count += path.num_fill - 2;
1146            }
1147            if path.num_stroke > 2 {
1148                self.fill_triangles_count += path.num_stroke - 2;
1149            }
1150            self.draw_call_count += 2;
1151        }
1152
1153        Ok(())
1154    }
1155
1156    pub fn stroke<R: Renderer>(&mut self, renderer: &mut R) -> Result<(), NonaError> {
1157        let state = self.states.last_mut().unwrap();
1158        let scale = state.xform.average_scale();
1159        let mut stroke_width = (state.stroke_width * scale).clamped(0.0, 200.0);
1160        let mut stroke_paint = state.stroke.clone();
1161
1162        if stroke_width < self.fringe_width {
1163            let alpha = (stroke_width / self.fringe_width).clamped(0.0, 1.0);
1164            stroke_paint.inner_color.a *= alpha * alpha;
1165            stroke_paint.outer_color.a *= alpha * alpha;
1166            stroke_width = self.fringe_width;
1167        }
1168
1169        stroke_paint.inner_color.a *= state.alpha;
1170        stroke_paint.outer_color.a *= state.alpha;
1171
1172        self.cache
1173            .flatten_paths(&self.commands, self.dist_tol, self.tess_tol);
1174
1175        if renderer.edge_antialias() && state.shape_antialias {
1176            self.cache.expand_stroke(
1177                stroke_width * 0.5,
1178                self.fringe_width,
1179                state.line_cap,
1180                state.line_join,
1181                state.miter_limit,
1182                self.tess_tol,
1183            );
1184        } else {
1185            self.cache.expand_stroke(
1186                stroke_width * 0.5,
1187                0.0,
1188                state.line_cap,
1189                state.line_join,
1190                state.miter_limit,
1191                self.tess_tol,
1192            );
1193        }
1194
1195        renderer.stroke(
1196            &stroke_paint,
1197            state.composite_operation,
1198            &state.scissor,
1199            self.fringe_width,
1200            stroke_width,
1201            &self.cache.paths,
1202        )?;
1203
1204        for path in &self.cache.paths {
1205            self.fill_triangles_count += path.num_stroke - 2;
1206            self.draw_call_count += 1;
1207        }
1208
1209        Ok(())
1210    }
1211
1212    pub fn create_font_from_file<N: Into<String>, P: AsRef<std::path::Path>>(
1213        &mut self,
1214        name: N,
1215        path: P,
1216    ) -> Result<FontId, NonaError> {
1217        self.create_font(
1218            name,
1219            std::fs::read(path)
1220                .map_err(|err| NonaError::Texture(format!("Error loading image: {}", err)))?,
1221        )
1222    }
1223
1224    pub fn create_font<N: Into<String>, D: Into<Vec<u8>>>(
1225        &mut self,
1226        name: N,
1227        data: D,
1228    ) -> Result<FontId, NonaError> {
1229        self.fonts.add_font(name, data)
1230    }
1231
1232    pub fn find_font<N: AsRef<str>>(&self, name: N) -> Option<FontId> {
1233        self.fonts.find(name.as_ref())
1234    }
1235
1236    pub fn add_fallback_fontid(&mut self, base: FontId, fallback: FontId) {
1237        self.fonts.add_fallback(base, fallback);
1238    }
1239
1240    pub fn add_fallback_font<N1: AsRef<str>, N2: AsRef<str>>(&mut self, base: N1, fallback: N2) {
1241        if let (Some(base), Some(fallback)) = (self.find_font(base), self.find_font(fallback)) {
1242            self.fonts.add_fallback(base, fallback);
1243        }
1244    }
1245
1246    pub fn font_size(&mut self, size: f32) {
1247        self.state_mut().font_size = size;
1248    }
1249
1250    pub fn text_letter_spacing(&mut self, spacing: f32) {
1251        self.state_mut().letter_spacing = spacing;
1252    }
1253
1254    pub fn text_line_height(&mut self, line_height: f32) {
1255        self.state_mut().line_height = line_height;
1256    }
1257
1258    pub fn text_align(&mut self, align: Align) {
1259        self.state_mut().text_align = align;
1260    }
1261
1262    pub fn fontid(&mut self, id: FontId) {
1263        self.state_mut().font_id = id;
1264    }
1265
1266    pub fn font<N: AsRef<str>>(&mut self, name: N) {
1267        if let Some(id) = self.find_font(name) {
1268            self.state_mut().font_id = id;
1269        }
1270    }
1271
1272    pub fn text<S: AsRef<str>, P: Into<Point>, R: Renderer>(
1273        &mut self,
1274        renderer: &mut R,
1275        pt: P,
1276        text: S,
1277    ) -> Result<(), NonaError> {
1278        let state = self.states.last().unwrap();
1279        let scale = state.xform.font_scale() * self.device_pixel_ratio;
1280        let invscale = 1.0 / scale;
1281        let pt = pt.into();
1282
1283        self.fonts.layout_text(
1284            renderer,
1285            text.as_ref(),
1286            state.font_id,
1287            (pt.x * scale, pt.y * scale).into(),
1288            state.font_size * scale,
1289            state.text_align,
1290            state.letter_spacing * scale,
1291            true,
1292            &mut self.layout_chars,
1293        )?;
1294
1295        self.cache.vertexes.clear();
1296
1297        for lc in &self.layout_chars {
1298            let lt = Point::new(lc.bounds.min.x * invscale, lc.bounds.min.y * invscale);
1299            let rt = Point::new(lc.bounds.max.x * invscale, lc.bounds.min.y * invscale);
1300            let lb = Point::new(lc.bounds.min.x * invscale, lc.bounds.max.y * invscale);
1301            let rb = Point::new(lc.bounds.max.x * invscale, lc.bounds.max.y * invscale);
1302
1303            self.cache
1304                .vertexes
1305                .push(Vertex::new(lt.x, lt.y, lc.uv.min.x, lc.uv.min.y));
1306            self.cache
1307                .vertexes
1308                .push(Vertex::new(rb.x, rb.y, lc.uv.max.x, lc.uv.max.y));
1309            self.cache
1310                .vertexes
1311                .push(Vertex::new(rt.x, rt.y, lc.uv.max.x, lc.uv.min.y));
1312
1313            self.cache
1314                .vertexes
1315                .push(Vertex::new(lt.x, lt.y, lc.uv.min.x, lc.uv.min.y));
1316            self.cache
1317                .vertexes
1318                .push(Vertex::new(lb.x, lb.y, lc.uv.min.x, lc.uv.max.y));
1319            self.cache
1320                .vertexes
1321                .push(Vertex::new(rb.x, rb.y, lc.uv.max.x, lc.uv.max.y));
1322        }
1323
1324        let mut paint = state.fill.clone();
1325        paint.image = Some(self.fonts.img.clone());
1326        paint.inner_color.a *= state.alpha;
1327        paint.outer_color.a *= state.alpha;
1328
1329        renderer.triangles(
1330            &paint,
1331            state.composite_operation,
1332            &state.scissor,
1333            &self.cache.vertexes,
1334        )?;
1335        Ok(())
1336    }
1337
1338    pub fn text_metrics(&self) -> TextMetrics {
1339        let state = self.states.last().unwrap();
1340        let scale = state.xform.font_scale() * self.device_pixel_ratio;
1341        self.fonts
1342            .text_metrics(state.font_id, state.font_size * scale)
1343    }
1344
1345    pub fn text_size<S: AsRef<str>>(&self, text: S) -> Extent {
1346        let state = self.states.last().unwrap();
1347        let scale = state.xform.font_scale() * self.device_pixel_ratio;
1348        self.fonts.text_size(
1349            text.as_ref(),
1350            state.font_id,
1351            state.font_size * scale,
1352            state.letter_spacing * scale,
1353        )
1354    }
1355}