1#![warn(missing_docs)]
4#![allow(
5 clippy::too_many_arguments,
6 clippy::large_enum_variant,
7 clippy::comparison_chain,
8 clippy::derive_ord_xor_partial_ord,
9 clippy::search_is_some,
10 clippy::unnecessary_to_owned,
11 clippy::needless_range_loop,
12 clippy::manual_map,
13 clippy::map_entry
14)]
15#[cfg(feature = "serde")]
31#[macro_use]
32extern crate serde;
33
34use std::cell::RefCell;
35use std::ops::Range;
36use std::path::Path as FilePath;
37use std::rc::Rc;
38
39use imgref::ImgVec;
40use rgb::RGBA8;
41
42mod utils;
43
44mod text;
45
46mod error;
47pub use error::ErrorKind;
48
49pub use text::{
50 Align,
51 Baseline,
52 FontId,
53 FontMetrics,
54 TextContext,
55 TextMetrics,
56};
57
58use text::{
59 GlyphAtlas,
60 RenderMode,
61 TextContextImpl,
62};
63
64mod image;
65
66pub use crate::image::{
67 ImageFilter,
68 ImageFlags,
69 ImageId,
70 ImageInfo,
71 ImageSource,
72 ImageStore,
73 PixelFormat,
74};
75
76mod color;
77pub use color::Color;
78
79pub mod renderer;
80pub use renderer::{
81 RenderTarget,
82 Renderer,
83};
84
85pub use renderer::{
86 Command,
87 CommandType,
88 Drawable,
89 Params,
90 ShaderType,
91 Vertex,
92};
93
94pub(crate) mod geometry;
95pub use geometry::Transform2D;
96use geometry::*;
97
98mod paint;
99use paint::PaintFlavor;
100pub use paint::{
101 GlyphTexture,
102 Paint,
103};
104
105mod path;
106use path::Convexity;
107pub use path::{
108 Path,
109 Solidity,
110};
111
112mod gradient_store;
113use gradient_store::GradientStore;
114
115#[derive(Copy, Clone, Debug, Eq, PartialEq)]
117#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
118pub enum FillRule {
119 EvenOdd,
121 NonZero,
123}
124
125impl Default for FillRule {
126 fn default() -> Self {
127 Self::NonZero
128 }
129}
130
131#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
133pub enum BlendFactor {
134 Zero,
136 One,
138 SrcColor,
140 OneMinusSrcColor,
142 DstColor,
144 OneMinusDstColor,
146 SrcAlpha,
148 OneMinusSrcAlpha,
150 DstAlpha,
152 OneMinusDstAlpha,
154 SrcAlphaSaturate,
156}
157
158#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
160pub enum CompositeOperation {
161 SourceOver,
163 SourceIn,
165 SourceOut,
167 Atop,
169 DestinationOver,
171 DestinationIn,
173 DestinationOut,
175 DestinationAtop,
177 Lighter,
179 Copy,
181 Xor,
183}
184
185#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
187pub struct CompositeOperationState {
188 pub src_rgb: BlendFactor,
190 pub src_alpha: BlendFactor,
192 pub dst_rgb: BlendFactor,
194 pub dst_alpha: BlendFactor,
196}
197
198impl CompositeOperationState {
199 pub fn new(op: CompositeOperation) -> Self {
201 let (sfactor, dfactor) = match op {
202 CompositeOperation::SourceOver => (BlendFactor::One, BlendFactor::OneMinusSrcAlpha),
203 CompositeOperation::SourceIn => (BlendFactor::DstAlpha, BlendFactor::Zero),
204 CompositeOperation::SourceOut => (BlendFactor::OneMinusDstAlpha, BlendFactor::Zero),
205 CompositeOperation::Atop => (BlendFactor::DstAlpha, BlendFactor::OneMinusSrcAlpha),
206 CompositeOperation::DestinationOver => (BlendFactor::OneMinusDstAlpha, BlendFactor::One),
207 CompositeOperation::DestinationIn => (BlendFactor::Zero, BlendFactor::SrcAlpha),
208 CompositeOperation::DestinationOut => (BlendFactor::Zero, BlendFactor::OneMinusSrcAlpha),
209 CompositeOperation::DestinationAtop => (BlendFactor::OneMinusDstAlpha, BlendFactor::SrcAlpha),
210 CompositeOperation::Lighter => (BlendFactor::One, BlendFactor::One),
211 CompositeOperation::Copy => (BlendFactor::One, BlendFactor::Zero),
212 CompositeOperation::Xor => (BlendFactor::OneMinusDstAlpha, BlendFactor::OneMinusSrcAlpha),
213 };
214
215 Self {
216 src_rgb: sfactor,
217 src_alpha: sfactor,
218 dst_rgb: dfactor,
219 dst_alpha: dfactor,
220 }
221 }
222
223 pub fn with_blend_factors(src_factor: BlendFactor, dst_factor: BlendFactor) -> Self {
225 Self {
226 src_rgb: src_factor,
227 src_alpha: src_factor,
228 dst_rgb: dst_factor,
229 dst_alpha: dst_factor,
230 }
231 }
232}
233
234impl Default for CompositeOperationState {
235 fn default() -> Self {
236 Self::new(CompositeOperation::SourceOver)
237 }
238}
239
240#[derive(Default, Copy, Clone, Debug)]
242pub struct Scissor {
243 transform: Transform2D,
244 extent: Option<[f32; 2]>,
245}
246
247#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
249#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
250pub enum LineCap {
251 Butt,
253 Round,
255 Square,
258}
259
260impl Default for LineCap {
261 fn default() -> Self {
262 Self::Butt
263 }
264}
265
266#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
268#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
269pub enum LineJoin {
270 Miter,
275 Round,
279 Bevel,
283}
284
285impl Default for LineJoin {
286 fn default() -> Self {
287 Self::Miter
288 }
289}
290
291#[derive(Copy, Clone, Debug)]
292struct State {
293 composite_operation: CompositeOperationState,
294 transform: Transform2D,
295 scissor: Scissor,
296 alpha: f32,
297}
298
299impl Default for State {
300 fn default() -> Self {
301 Self {
302 composite_operation: Default::default(),
303 transform: Transform2D::identity(),
304 scissor: Default::default(),
305 alpha: 1.0,
306 }
307 }
308}
309
310pub struct Canvas<T: Renderer> {
312 width: u32,
313 height: u32,
314 renderer: T,
315 text_context: Rc<RefCell<TextContextImpl>>,
316 glyph_atlas: Rc<GlyphAtlas>,
317 emphemeral_glyph_atlas: Option<Rc<GlyphAtlas>>,
319 current_render_target: RenderTarget,
320 state_stack: Vec<State>,
321 commands: Vec<Command>,
322 verts: Vec<Vertex>,
323 images: ImageStore<T::Image>,
324 fringe_width: f32,
325 device_px_ratio: f32,
326 tess_tol: f32,
327 dist_tol: f32,
328 gradients: GradientStore,
329}
330
331impl<T> Canvas<T>
332where
333 T: Renderer,
334{
335 pub fn new(renderer: T) -> Result<Self, ErrorKind> {
337 let mut canvas = Self {
338 width: 0,
339 height: 0,
340 renderer,
341 text_context: Default::default(),
342 glyph_atlas: Default::default(),
343 emphemeral_glyph_atlas: Default::default(),
344 current_render_target: RenderTarget::Screen,
345 state_stack: Default::default(),
346 commands: Default::default(),
347 verts: Default::default(),
348 images: ImageStore::new(),
349 fringe_width: 1.0,
350 device_px_ratio: 1.0,
351 tess_tol: 0.25,
352 dist_tol: 0.01,
353 gradients: GradientStore::new(),
354 };
355
356 canvas.save();
357
358 Ok(canvas)
359 }
360
361 pub fn new_with_text_context(renderer: T, text_context: TextContext) -> Result<Self, ErrorKind> {
365 let mut canvas = Self {
366 width: 0,
367 height: 0,
368 renderer,
369 text_context: text_context.0,
370 glyph_atlas: Default::default(),
371 emphemeral_glyph_atlas: Default::default(),
372 current_render_target: RenderTarget::Screen,
373 state_stack: Default::default(),
374 commands: Default::default(),
375 verts: Default::default(),
376 images: ImageStore::new(),
377 fringe_width: 1.0,
378 device_px_ratio: 1.0,
379 tess_tol: 0.25,
380 dist_tol: 0.01,
381 gradients: GradientStore::new(),
382 };
383
384 canvas.save();
385
386 Ok(canvas)
387 }
388
389 pub fn set_size(&mut self, width: u32, height: u32, dpi: f32) {
391 self.width = width;
392 self.height = height;
393 self.fringe_width = 1.0 / dpi;
394 self.tess_tol = 0.25 / dpi;
395 self.dist_tol = 0.01 / dpi;
396 self.device_px_ratio = dpi;
397
398 self.renderer.set_size(width, height, dpi);
399
400 self.append_cmd(Command::new(CommandType::SetRenderTarget(RenderTarget::Screen)));
401 }
402
403 pub fn clear_rect(&mut self, x: u32, y: u32, width: u32, height: u32, color: Color) {
405 let cmd = Command::new(CommandType::ClearRect {
406 x,
407 y,
408 width,
409 height,
410 color,
411 });
412
413 self.append_cmd(cmd);
414 }
415
416 pub fn width(&self) -> f32 {
418 match self.current_render_target {
419 RenderTarget::Image(id) => self.image_info(id).map(|info| info.width() as f32).unwrap_or(0.0),
420 RenderTarget::Screen => self.width as f32,
421 }
422 }
423
424 pub fn height(&self) -> f32 {
426 match self.current_render_target {
427 RenderTarget::Image(id) => self.image_info(id).map(|info| info.height() as f32).unwrap_or(0.0),
428 RenderTarget::Screen => self.height as f32,
429 }
430 }
431
432 pub fn flush(&mut self) {
436 self.renderer
437 .render(&mut self.images, &self.verts, std::mem::take(&mut self.commands));
438 self.verts.clear();
439 self.gradients
440 .release_old_gradients(&mut self.images, &mut self.renderer);
441 if let Some(atlas) = self.emphemeral_glyph_atlas.take() {
442 atlas.clear(self);
443 }
444 }
445
446 pub fn screenshot(&mut self) -> Result<ImgVec<RGBA8>, ErrorKind> {
448 self.flush();
449 self.renderer.screenshot()
450 }
451
452 pub fn save(&mut self) {
458 let state = self.state_stack.last().map_or_else(State::default, |state| *state);
459
460 self.state_stack.push(state);
461 }
462
463 pub fn restore(&mut self) {
467 if self.state_stack.len() > 1 {
468 self.state_stack.pop();
469 } else {
470 self.reset();
471 }
472 }
473
474 pub fn reset(&mut self) {
476 *self.state_mut() = Default::default();
477 }
478
479 pub fn save_with(&mut self, mut callback: impl FnMut(&mut Self)) {
483 self.save();
484
485 callback(self);
486
487 self.restore();
488 }
489
490 pub fn set_global_alpha(&mut self, alpha: f32) {
496 self.state_mut().alpha = alpha;
497 }
498
499 pub fn global_composite_operation(&mut self, op: CompositeOperation) {
501 self.state_mut().composite_operation = CompositeOperationState::new(op);
502 }
503
504 pub fn global_composite_blend_func(&mut self, src_factor: BlendFactor, dst_factor: BlendFactor) {
506 self.global_composite_blend_func_separate(src_factor, dst_factor, src_factor, dst_factor);
507 }
508
509 pub fn global_composite_blend_func_separate(
511 &mut self,
512 src_rgb: BlendFactor,
513 dst_rgb: BlendFactor,
514 src_alpha: BlendFactor,
515 dst_alpha: BlendFactor,
516 ) {
517 self.state_mut().composite_operation = CompositeOperationState {
518 src_rgb,
519 src_alpha,
520 dst_rgb,
521 dst_alpha,
522 }
523 }
524
525 pub fn set_render_target(&mut self, target: RenderTarget) {
527 if self.current_render_target != target {
528 self.append_cmd(Command::new(CommandType::SetRenderTarget(target)));
529 self.current_render_target = target;
530 }
531 }
532
533 fn append_cmd(&mut self, cmd: Command) {
534 self.commands.push(cmd);
535 }
536
537 pub fn create_image_empty(
541 &mut self,
542 width: usize,
543 height: usize,
544 format: PixelFormat,
545 flags: ImageFlags,
546 ) -> Result<ImageId, ErrorKind> {
547 let info = ImageInfo::new(flags, width, height, format);
548
549 self.images.alloc(&mut self.renderer, info)
550 }
551
552 pub fn create_image<'a, S: Into<ImageSource<'a>>>(
554 &mut self,
555 src: S,
556 flags: ImageFlags,
557 ) -> Result<ImageId, ErrorKind> {
558 let src = src.into();
559 let size = src.dimensions();
560 let id = self.create_image_empty(size.0, size.1, src.format(), flags)?;
561 self.images.update(&mut self.renderer, id, src, 0, 0)?;
562 Ok(id)
563 }
564
565 pub fn get_image(&self, id: ImageId) -> Option<&T::Image> {
567 self.images.get(id)
568 }
569
570 pub fn get_image_mut(&mut self, id: ImageId) -> Option<&mut T::Image> {
572 self.images.get_mut(id)
573 }
574
575 pub fn realloc_image(
577 &mut self,
578 id: ImageId,
579 width: usize,
580 height: usize,
581 format: PixelFormat,
582 flags: ImageFlags,
583 ) -> Result<(), ErrorKind> {
584 let info = ImageInfo::new(flags, width, height, format);
585 self.images.realloc(&mut self.renderer, id, info)
586 }
587
588 #[cfg(feature = "image-loading")]
590 pub fn load_image_file<P: AsRef<FilePath>>(
591 &mut self,
592 filename: P,
593 flags: ImageFlags,
594 ) -> Result<ImageId, ErrorKind> {
595 let image = ::image::open(filename)?;
596
597 use std::convert::TryFrom;
598
599 let src = ImageSource::try_from(&image)?;
600
601 self.create_image(src, flags)
602 }
603
604 #[cfg(feature = "image-loading")]
606 pub fn load_image_mem(&mut self, data: &[u8], flags: ImageFlags) -> Result<ImageId, ErrorKind> {
607 let image = ::image::load_from_memory(data)?;
608
609 use std::convert::TryFrom;
610
611 let src = ImageSource::try_from(&image)?;
612
613 self.create_image(src, flags)
614 }
615
616 pub fn update_image<'a, S: Into<ImageSource<'a>>>(
618 &mut self,
619 id: ImageId,
620 src: S,
621 x: usize,
622 y: usize,
623 ) -> Result<(), ErrorKind> {
624 self.images.update(&mut self.renderer, id, src.into(), x, y)
625 }
626
627 pub fn delete_image(&mut self, id: ImageId) {
629 self.images.remove(&mut self.renderer, id);
630 }
631
632 pub fn image_info(&self, id: ImageId) -> Result<ImageInfo, ErrorKind> {
634 if let Some(info) = self.images.info(id) {
635 Ok(info)
636 } else {
637 Err(ErrorKind::ImageIdNotFound)
638 }
639 }
640
641 pub fn image_size(&self, id: ImageId) -> Result<(usize, usize), ErrorKind> {
643 let info = self.image_info(id)?;
644 Ok((info.width(), info.height()))
645 }
646
647 pub fn filter_image(&mut self, target_image: ImageId, filter: ImageFilter, source_image: ImageId) {
655 let (image_width, image_height) = match self.image_size(source_image) {
656 Ok((w, h)) => (w, h),
657 Err(_) => return,
658 };
659
660 let mut cmd = Command::new(CommandType::RenderFilteredImage { target_image, filter });
663 cmd.image = Some(source_image);
664
665 let vertex_offset = self.verts.len();
666
667 let image_width = image_width as f32;
668 let image_height = image_height as f32;
669
670 let quad_x0 = 0.0;
671 let quad_y0 = -image_height;
672 let quad_x1 = image_width;
673 let quad_y1 = image_height;
674
675 let texture_x0 = -(image_width / 2.);
676 let texture_y0 = -(image_height / 2.);
677 let texture_x1 = (image_width) / 2.;
678 let texture_y1 = (image_height) / 2.;
679
680 self.verts.push(Vertex::new(quad_x0, quad_y0, texture_x0, texture_y0));
681 self.verts.push(Vertex::new(quad_x1, quad_y1, texture_x1, texture_y1));
682 self.verts.push(Vertex::new(quad_x1, quad_y0, texture_x1, texture_y0));
683 self.verts.push(Vertex::new(quad_x0, quad_y0, texture_x0, texture_y0));
684 self.verts.push(Vertex::new(quad_x0, quad_y1, texture_x0, texture_y1));
685 self.verts.push(Vertex::new(quad_x1, quad_y1, texture_x1, texture_y1));
686
687 cmd.triangles_verts = Some((vertex_offset, 6));
688
689 self.append_cmd(cmd)
690 }
691
692 pub fn reset_transform(&mut self) {
696 self.state_mut().transform = Transform2D::identity();
697 }
698
699 pub fn set_transform(&mut self, a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) {
706 let transform = Transform2D([a, b, c, d, e, f]);
707 self.state_mut().transform.premultiply(&transform);
708 }
709
710 pub fn translate(&mut self, x: f32, y: f32) {
712 let mut t = Transform2D::identity();
713 t.translate(x, y);
714 self.state_mut().transform.premultiply(&t);
715 }
716
717 pub fn rotate(&mut self, angle: f32) {
719 let mut t = Transform2D::identity();
720 t.rotate(angle);
721 self.state_mut().transform.premultiply(&t);
722 }
723
724 pub fn skew_x(&mut self, angle: f32) {
726 let mut t = Transform2D::identity();
727 t.skew_x(angle);
728 self.state_mut().transform.premultiply(&t);
729 }
730
731 pub fn skew_y(&mut self, angle: f32) {
733 let mut t = Transform2D::identity();
734 t.skew_y(angle);
735 self.state_mut().transform.premultiply(&t);
736 }
737
738 pub fn scale(&mut self, x: f32, y: f32) {
740 let mut t = Transform2D::identity();
741 t.scale(x, y);
742 self.state_mut().transform.premultiply(&t);
743 }
744
745 pub fn transform(&self) -> Transform2D {
749 self.state().transform
750 }
751
752 pub fn scissor(&mut self, x: f32, y: f32, w: f32, h: f32) {
758 let state = self.state_mut();
759
760 let w = w.max(0.0);
761 let h = h.max(0.0);
762
763 let mut transform = Transform2D::new_translation(x + w * 0.5, y + h * 0.5);
764 transform.multiply(&state.transform);
765 state.scissor.transform = transform;
766
767 state.scissor.extent = Some([w * 0.5, h * 0.5]);
768 }
769
770 pub fn intersect_scissor(&mut self, x: f32, y: f32, w: f32, h: f32) {
778 let state = self.state_mut();
779
780 if state.scissor.extent.is_none() {
782 self.scissor(x, y, w, h);
783 return;
784 }
785
786 let extent = state.scissor.extent.unwrap();
787
788 let mut pxform = state.scissor.transform;
792
793 let mut invxform = state.transform;
794 invxform.inverse();
795
796 pxform.multiply(&invxform);
797
798 let ex = extent[0];
799 let ey = extent[1];
800
801 let tex = ex * pxform[0].abs() + ey * pxform[2].abs();
802 let tey = ex * pxform[1].abs() + ey * pxform[3].abs();
803
804 let rect = Rect::new(pxform[4] - tex, pxform[5] - tey, tex * 2.0, tey * 2.0);
805 let res = rect.intersect(Rect::new(x, y, w, h));
806
807 self.scissor(res.x, res.y, res.w, res.h);
808 }
809
810 pub fn reset_scissor(&mut self) {
812 self.state_mut().scissor = Scissor::default();
813 }
814
815 pub fn contains_point(&mut self, path: &mut Path, x: f32, y: f32, fill_rule: FillRule) -> bool {
819 let transform = self.state().transform;
820
821 let path_cache = path.cache(&transform, self.tess_tol, self.dist_tol);
823
824 if path_cache.bounds.maxx < 0.0
826 || path_cache.bounds.minx > self.width()
827 || path_cache.bounds.maxy < 0.0
828 || path_cache.bounds.miny > self.height()
829 {
830 return false;
831 }
832
833 path_cache.contains_point(x, y, fill_rule)
834 }
835
836 pub fn path_bbox(&self, path: &mut Path) -> Bounds {
838 let transform = self.state().transform;
839
840 let path_cache = path.cache(&transform, self.tess_tol, self.dist_tol);
842
843 path_cache.bounds
844 }
845
846 pub fn fill_path(&mut self, path: &mut Path, mut paint: Paint) {
848 let transform = self.state().transform;
849
850 let path_cache = path.cache(&transform, self.tess_tol, self.dist_tol);
852
853 if path_cache.bounds.maxx < 0.0
855 || path_cache.bounds.minx > self.width()
856 || path_cache.bounds.maxy < 0.0
857 || path_cache.bounds.miny > self.height()
858 {
859 return;
860 }
861
862 paint.transform = transform;
864
865 paint.mul_alpha(self.state().alpha);
867
868 let scissor = self.state().scissor;
869
870 let fringe_width = if paint.anti_alias() { self.fringe_width } else { 0.0 };
874 path_cache.expand_fill(fringe_width, LineJoin::Miter, 2.4);
875
876 let flavor = if path_cache.contours.len() == 1 && path_cache.contours[0].convexity == Convexity::Convex {
878 let params = Params::new(
879 &self.images,
880 &paint,
881 &scissor,
882 self.fringe_width,
883 self.fringe_width,
884 -1.0,
885 );
886
887 CommandType::ConvexFill { params }
888 } else {
889 let stencil_params = Params {
890 stroke_thr: -1.0,
891 shader_type: ShaderType::Stencil.to_f32(),
892 ..Default::default()
893 };
894
895 let fill_params = Params::new(
896 &self.images,
897 &paint,
898 &scissor,
899 self.fringe_width,
900 self.fringe_width,
901 -1.0,
902 );
903
904 CommandType::ConcaveFill {
905 stencil_params,
906 fill_params,
907 }
908 };
909
910 let mut cmd = Command::new(flavor);
912 cmd.fill_rule = paint.fill_rule;
913 cmd.composite_operation = self.state().composite_operation;
914
915 if let PaintFlavor::Image { id, .. } = paint.flavor {
916 cmd.image = Some(id);
917 } else if let Some(paint::GradientColors::MultiStop { stops }) = paint.flavor.gradient_colors() {
918 cmd.image = self
919 .gradients
920 .lookup_or_add(*stops, &mut self.images, &mut self.renderer)
921 .ok();
922 }
923
924 let mut offset = self.verts.len();
927
928 for contour in &path_cache.contours {
929 let mut drawable = Drawable::default();
930
931 if !contour.fill.is_empty() {
935 drawable.fill_verts = Some((offset, contour.fill.len()));
936 self.verts.extend_from_slice(&contour.fill);
937 offset += contour.fill.len();
938 }
939
940 if !contour.stroke.is_empty() {
941 drawable.stroke_verts = Some((offset, contour.stroke.len()));
942 self.verts.extend_from_slice(&contour.stroke);
943 offset += contour.stroke.len();
944 }
945
946 cmd.drawables.push(drawable);
947 }
948
949 if let CommandType::ConcaveFill { .. } = cmd.cmd_type {
950 self.verts.push(Vertex::new(
954 path_cache.bounds.maxx + fringe_width,
955 path_cache.bounds.maxy + fringe_width,
956 0.5,
957 1.0,
958 ));
959 self.verts.push(Vertex::new(
960 path_cache.bounds.maxx + fringe_width,
961 path_cache.bounds.miny - fringe_width,
962 0.5,
963 1.0,
964 ));
965 self.verts.push(Vertex::new(
966 path_cache.bounds.minx - fringe_width,
967 path_cache.bounds.maxy + fringe_width,
968 0.5,
969 1.0,
970 ));
971 self.verts.push(Vertex::new(
972 path_cache.bounds.minx - fringe_width,
973 path_cache.bounds.miny,
974 0.5,
975 1.0,
976 ));
977
978 cmd.triangles_verts = Some((offset, 4));
979 }
980
981 self.append_cmd(cmd);
982 }
983
984 pub fn stroke_path(&mut self, path: &mut Path, mut paint: Paint) {
986 let transform = self.state().transform;
987
988 let path_cache = path.cache(&transform, self.tess_tol, self.dist_tol);
990
991 if path_cache.bounds.maxx < 0.0
993 || path_cache.bounds.minx > self.width()
994 || path_cache.bounds.maxy < 0.0
995 || path_cache.bounds.miny > self.height()
996 {
997 return;
998 }
999
1000 let scissor = self.state().scissor;
1001
1002 paint.transform = transform;
1004
1005 paint.line_width = (paint.line_width * transform.average_scale()).max(0.0);
1011
1012 if paint.line_width < self.fringe_width {
1013 let alpha = (paint.line_width / self.fringe_width).max(0.0).min(1.0);
1016
1017 paint.mul_alpha(alpha * alpha);
1018 paint.line_width = self.fringe_width;
1019 }
1020
1021 paint.mul_alpha(self.state().alpha);
1023
1024 let fringe_with = if paint.anti_alias() { self.fringe_width } else { 0.0 };
1027 path_cache.expand_stroke(
1028 paint.line_width * 0.5,
1029 fringe_with,
1030 paint.line_cap_start,
1031 paint.line_cap_end,
1032 paint.line_join,
1033 paint.miter_limit,
1034 self.tess_tol,
1035 );
1036
1037 let params = Params::new(
1039 &self.images,
1040 &paint,
1041 &scissor,
1042 paint.line_width,
1043 self.fringe_width,
1044 -1.0,
1045 );
1046
1047 let flavor = if paint.stencil_strokes() {
1048 let params2 = Params::new(
1049 &self.images,
1050 &paint,
1051 &scissor,
1052 paint.line_width,
1053 self.fringe_width,
1054 1.0 - 0.5 / 255.0,
1055 );
1056
1057 CommandType::StencilStroke {
1058 params1: params,
1059 params2,
1060 }
1061 } else {
1062 CommandType::Stroke { params }
1063 };
1064
1065 let mut cmd = Command::new(flavor);
1067 cmd.composite_operation = self.state().composite_operation;
1068
1069 if let PaintFlavor::Image { id, .. } = paint.flavor {
1070 cmd.image = Some(id);
1071 } else if let Some(paint::GradientColors::MultiStop { stops }) = paint.flavor.gradient_colors() {
1072 cmd.image = self
1073 .gradients
1074 .lookup_or_add(*stops, &mut self.images, &mut self.renderer)
1075 .ok();
1076 }
1077
1078 let mut offset = self.verts.len();
1081
1082 for contour in &path_cache.contours {
1083 let mut drawable = Drawable::default();
1084
1085 if !contour.stroke.is_empty() {
1086 drawable.stroke_verts = Some((offset, contour.stroke.len()));
1087 self.verts.extend_from_slice(&contour.stroke);
1088 offset += contour.stroke.len();
1089 }
1090
1091 cmd.drawables.push(drawable);
1092 }
1093
1094 self.append_cmd(cmd);
1095 }
1096
1097 pub fn add_font<P: AsRef<FilePath>>(&mut self, file_path: P) -> Result<FontId, ErrorKind> {
1101 self.text_context.as_ref().borrow_mut().add_font_file(file_path)
1102 }
1103
1104 pub fn add_font_mem(&mut self, data: &[u8]) -> Result<FontId, ErrorKind> {
1106 self.text_context.as_ref().borrow_mut().add_font_mem(data)
1107 }
1108
1109 pub fn add_font_dir<P: AsRef<FilePath>>(&mut self, dir_path: P) -> Result<Vec<FontId>, ErrorKind> {
1111 self.text_context.as_ref().borrow_mut().add_font_dir(dir_path)
1112 }
1113
1114 pub fn measure_text<S: AsRef<str>>(
1116 &mut self,
1117 x: f32,
1118 y: f32,
1119 text: S,
1120 mut paint: Paint,
1121 ) -> Result<TextMetrics, ErrorKind> {
1122 self.transform_text_paint(&mut paint);
1123
1124 let text = text.as_ref();
1125 let scale = self.font_scale() * self.device_px_ratio;
1126 let invscale = 1.0 / scale;
1127
1128 self.text_context
1129 .as_ref()
1130 .borrow_mut()
1131 .measure_text(x * scale, y * scale, text, paint)
1132 .map(|mut metrics| {
1133 metrics.scale(invscale);
1134 metrics
1135 })
1136 }
1137
1138 pub fn measure_font(&mut self, mut paint: Paint) -> Result<FontMetrics, ErrorKind> {
1140 self.transform_text_paint(&mut paint);
1141
1142 self.text_context.as_ref().borrow_mut().measure_font(paint)
1143 }
1144
1145 pub fn break_text<S: AsRef<str>>(&mut self, max_width: f32, text: S, mut paint: Paint) -> Result<usize, ErrorKind> {
1149 self.transform_text_paint(&mut paint);
1150
1151 let text = text.as_ref();
1152 let scale = self.font_scale() * self.device_px_ratio;
1153 let max_width = max_width * scale;
1154
1155 self.text_context
1156 .as_ref()
1157 .borrow_mut()
1158 .break_text(max_width, text, paint)
1159 }
1160
1161 pub fn break_text_vec<S: AsRef<str>>(
1163 &mut self,
1164 max_width: f32,
1165 text: S,
1166 mut paint: Paint,
1167 ) -> Result<Vec<Range<usize>>, ErrorKind> {
1168 self.transform_text_paint(&mut paint);
1169
1170 let text = text.as_ref();
1171 let scale = self.font_scale() * self.device_px_ratio;
1172 let max_width = max_width * scale;
1173
1174 self.text_context
1175 .as_ref()
1176 .borrow_mut()
1177 .break_text_vec(max_width, text, paint)
1178 }
1179
1180 pub fn fill_text<S: AsRef<str>>(
1182 &mut self,
1183 x: f32,
1184 y: f32,
1185 text: S,
1186 paint: Paint,
1187 ) -> Result<TextMetrics, ErrorKind> {
1188 self.draw_text(x, y, text.as_ref(), paint, RenderMode::Fill)
1189 }
1190
1191 pub fn stroke_text<S: AsRef<str>>(
1193 &mut self,
1194 x: f32,
1195 y: f32,
1196 text: S,
1197 paint: Paint,
1198 ) -> Result<TextMetrics, ErrorKind> {
1199 self.draw_text(x, y, text.as_ref(), paint, RenderMode::Stroke)
1200 }
1201
1202 fn transform_text_paint(&self, paint: &mut Paint) {
1205 let scale = self.font_scale() * self.device_px_ratio;
1206 paint.font_size *= scale;
1207 paint.letter_spacing *= scale;
1208 paint.line_width *= scale;
1209 }
1210
1211 fn draw_text(
1212 &mut self,
1213 x: f32,
1214 y: f32,
1215 text: &str,
1216 mut paint: Paint,
1217 render_mode: RenderMode,
1218 ) -> Result<TextMetrics, ErrorKind> {
1219 let transform = self.state().transform;
1220 let scale = self.font_scale() * self.device_px_ratio;
1221 let invscale = 1.0 / scale;
1222
1223 self.transform_text_paint(&mut paint);
1224
1225 let mut layout = text::shape(
1226 x * scale,
1227 y * scale,
1228 &mut self.text_context.as_ref().borrow_mut(),
1229 &paint,
1230 text,
1231 None,
1232 )?;
1233 let bitmap_glyphs = layout.has_bitmap_glyphs();
1238 let need_direct_rendering = paint.font_size > 92.0;
1239
1240 if need_direct_rendering && !bitmap_glyphs {
1241 text::render_direct(self, &layout, &paint, render_mode, invscale)?;
1242 } else {
1243 let create_vertices = |quads: &Vec<text::Quad>| {
1244 let mut verts = Vec::with_capacity(quads.len() * 6);
1245
1246 for quad in quads {
1247 let (p0, p1) = transform.transform_point(quad.x0 * invscale, quad.y0 * invscale);
1248 let (p2, p3) = transform.transform_point(quad.x1 * invscale, quad.y0 * invscale);
1249 let (p4, p5) = transform.transform_point(quad.x1 * invscale, quad.y1 * invscale);
1250 let (p6, p7) = transform.transform_point(quad.x0 * invscale, quad.y1 * invscale);
1251
1252 verts.push(Vertex::new(p0, p1, quad.s0, quad.t0));
1253 verts.push(Vertex::new(p4, p5, quad.s1, quad.t1));
1254 verts.push(Vertex::new(p2, p3, quad.s1, quad.t0));
1255 verts.push(Vertex::new(p0, p1, quad.s0, quad.t0));
1256 verts.push(Vertex::new(p6, p7, quad.s0, quad.t1));
1257 verts.push(Vertex::new(p4, p5, quad.s1, quad.t1));
1258 }
1259 verts
1260 };
1261
1262 let atlas = if bitmap_glyphs && need_direct_rendering {
1263 self.emphemeral_glyph_atlas.get_or_insert_with(Default::default).clone()
1264 } else {
1265 self.glyph_atlas.clone()
1266 };
1267
1268 let draw_commands = atlas.render_atlas(self, &layout, &paint, render_mode)?;
1269
1270 for cmd in draw_commands.alpha_glyphs {
1271 let verts = create_vertices(&cmd.quads);
1272
1273 paint.set_glyph_texture(GlyphTexture::AlphaMask(cmd.image_id));
1274
1275 paint.mul_alpha(self.state().alpha);
1277
1278 self.render_triangles(&verts, &paint);
1279 }
1280
1281 for cmd in draw_commands.color_glyphs {
1282 let verts = create_vertices(&cmd.quads);
1283
1284 paint.set_glyph_texture(GlyphTexture::ColorTexture(cmd.image_id));
1285
1286 paint.mul_alpha(self.state().alpha);
1288
1289 self.render_triangles(&verts, &paint);
1290 }
1291 }
1292
1293 layout.scale(invscale);
1294
1295 Ok(layout)
1296 }
1297
1298 fn render_triangles(&mut self, verts: &[Vertex], paint: &Paint) {
1299 let scissor = self.state().scissor;
1300
1301 let params = Params::new(&self.images, paint, &scissor, 1.0, 1.0, -1.0);
1302
1303 let mut cmd = Command::new(CommandType::Triangles { params });
1304 cmd.composite_operation = self.state().composite_operation;
1305 cmd.glyph_texture = paint.glyph_texture();
1306
1307 if let PaintFlavor::Image { id, .. } = paint.flavor {
1308 cmd.image = Some(id);
1309 } else if let Some(paint::GradientColors::MultiStop { stops }) = paint.flavor.gradient_colors() {
1310 cmd.image = self
1311 .gradients
1312 .lookup_or_add(*stops, &mut self.images, &mut self.renderer)
1313 .ok();
1314 }
1315
1316 cmd.triangles_verts = Some((self.verts.len(), verts.len()));
1317 self.append_cmd(cmd);
1318
1319 self.verts.extend_from_slice(verts);
1320 }
1321
1322 fn font_scale(&self) -> f32 {
1323 let avg_scale = self.state().transform.average_scale();
1324
1325 geometry::quantize(avg_scale, 0.1).min(7.0)
1326 }
1327
1328 fn state(&self) -> &State {
1331 self.state_stack.last().unwrap()
1332 }
1333
1334 fn state_mut(&mut self) -> &mut State {
1335 self.state_stack.last_mut().unwrap()
1336 }
1337
1338 #[cfg(feature = "debug_inspector")]
1339 pub fn debug_inspector_get_font_textures(&self) -> Vec<ImageId> {
1340 self.glyph_atlas
1341 .glyph_textures
1342 .borrow()
1343 .iter()
1344 .map(|t| t.image_id)
1345 .collect()
1346 }
1347
1348 #[cfg(feature = "debug_inspector")]
1349 pub fn debug_inspector_draw_image(&mut self, id: ImageId) {
1350 if let Ok(size) = self.image_size(id) {
1351 let width = size.0 as f32;
1352 let height = size.1 as f32;
1353 let mut path = Path::new();
1354 path.rect(0f32, 0f32, width, height);
1355 self.fill_path(&mut path, Paint::image(id, 0f32, 0f32, width, height, 0f32, 1f32));
1356 }
1357 }
1358}
1359
1360impl<T: Renderer> Drop for Canvas<T> {
1361 fn drop(&mut self) {
1362 self.images.clear(&mut self.renderer);
1363 }
1364}