1use cssparser::{Parser, Token};
5use markup5ever::{expanded_name, local_name, ns};
6use std::ops::Deref;
7use std::rc::Rc;
8
9use crate::cairo_path::{ValidatedPath, validate_path};
10use crate::document::AcquiredNodes;
11use crate::drawing_ctx::{DrawingCtx, Viewport};
12use crate::element::{DrawResult, ElementTrait, set_attribute};
13use crate::error::*;
14use crate::iri::Iri;
15use crate::is_element_of_type;
16use crate::layout::{Layer, LayerKind, Marker, Shape, StackingContext, Stroke};
17use crate::length::*;
18use crate::node::{CascadedValues, Node, NodeBorrow};
19use crate::parsers::{Parse, ParseValue, optional_comma};
20use crate::path_builder::{LargeArc, Path as SvgPath, PathBuilder, Sweep};
21use crate::properties::ComputedValues;
22use crate::rsvg_log;
23use crate::session::Session;
24use crate::xml::Attributes;
25
26#[derive(PartialEq)]
27enum Markers {
28 No,
29 Yes,
30}
31
32struct ShapeDef {
33 path: Rc<SvgPath>,
34 markers: Markers,
35}
36
37impl ShapeDef {
38 fn new(path: Rc<SvgPath>, markers: Markers) -> ShapeDef {
39 ShapeDef { path, markers }
40 }
41}
42
43trait BasicShape {
44 fn make_shape(&self, params: &NormalizeParams, values: &ComputedValues) -> ShapeDef;
50}
51
52fn draw_basic_shape(
53 basic_shape: &dyn BasicShape,
54 node: &Node,
55 acquired_nodes: &mut AcquiredNodes<'_>,
56 cascaded: &CascadedValues<'_>,
57 viewport: &Viewport,
58 draw_ctx: &DrawingCtx,
59) -> Result<Option<Layer>, Box<InternalRenderingError>> {
60 let session = draw_ctx.session();
61
62 let values = cascaded.get();
63 let params = NormalizeParams::new(values, viewport);
64 let shape_def = basic_shape.make_shape(¶ms, values);
65
66 let stroke = Stroke::new(values, ¶ms);
67 let path = match validate_path(&shape_def.path, &stroke, viewport)? {
68 ValidatedPath::Invalid(ref reason) => {
69 rsvg_log!(session, "will not render {node}: {reason}");
70 return Ok(None);
71 }
72
73 ValidatedPath::Validated(path) => path,
74 };
75
76 let paint_order = values.paint_order();
77 let shape_element_name = format!("{node}");
78
79 let stroke_paint = values.stroke().0.resolve(
80 acquired_nodes,
81 &shape_element_name,
82 values.stroke_opacity().0,
83 values.color().0,
84 cascaded.context_fill.clone(),
85 cascaded.context_stroke.clone(),
86 session,
87 );
88
89 let fill_paint = values.fill().0.resolve(
90 acquired_nodes,
91 &shape_element_name,
92 values.fill_opacity().0,
93 values.color().0,
94 cascaded.context_fill.clone(),
95 cascaded.context_stroke.clone(),
96 session,
97 );
98
99 let fill_rule = values.fill_rule();
100 let clip_rule = values.clip_rule();
101 let shape_rendering = values.shape_rendering();
102
103 let marker_start_node;
104 let marker_mid_node;
105 let marker_end_node;
106
107 if shape_def.markers == Markers::Yes {
108 marker_start_node = acquire_marker(
109 session,
110 &shape_element_name,
111 acquired_nodes,
112 &values.marker_start().0,
113 );
114 marker_mid_node = acquire_marker(
115 session,
116 &shape_element_name,
117 acquired_nodes,
118 &values.marker_mid().0,
119 );
120 marker_end_node = acquire_marker(
121 session,
122 &shape_element_name,
123 acquired_nodes,
124 &values.marker_end().0,
125 );
126 } else {
127 marker_start_node = None;
128 marker_mid_node = None;
129 marker_end_node = None;
130 }
131
132 let marker_start = Marker {
133 node_ref: marker_start_node,
134 context_stroke: stroke_paint.clone(),
135 context_fill: fill_paint.clone(),
136 };
137
138 let marker_mid = Marker {
139 node_ref: marker_mid_node,
140 context_stroke: stroke_paint.clone(),
141 context_fill: fill_paint.clone(),
142 };
143
144 let marker_end = Marker {
145 node_ref: marker_end_node,
146 context_stroke: stroke_paint.clone(),
147 context_fill: fill_paint.clone(),
148 };
149
150 let normalize_values = NormalizeValues::new(values);
151
152 let stroke_paint_source =
153 stroke_paint.to_user_space(&path.extents, viewport, &normalize_values);
154 let fill_paint_source = fill_paint.to_user_space(&path.extents, viewport, &normalize_values);
155
156 let shape = Box::new(Shape {
157 path,
158 paint_order,
159 stroke_paint: stroke_paint_source,
160 fill_paint: fill_paint_source,
161 stroke,
162 fill_rule,
163 clip_rule,
164 shape_rendering,
165 marker_start,
166 marker_mid,
167 marker_end,
168 });
169
170 let elt = node.borrow_element();
171 let stacking_ctx = StackingContext::new(
172 draw_ctx,
173 acquired_nodes,
174 &elt,
175 values.transform(),
176 None,
177 values,
178 viewport,
179 );
180
181 Ok(Some(Layer {
182 kind: LayerKind::Shape(shape),
183 stacking_ctx,
184 }))
185}
186
187macro_rules! impl_draw {
188 () => {
189 fn layout(
190 &self,
191 node: &Node,
192 acquired_nodes: &mut AcquiredNodes<'_>,
193 cascaded: &CascadedValues<'_>,
194 viewport: &Viewport,
195 draw_ctx: &mut DrawingCtx,
196 ) -> Result<Option<Layer>, Box<InternalRenderingError>> {
197 draw_basic_shape(self, node, acquired_nodes, cascaded, viewport, draw_ctx)
198 }
199
200 fn draw(
201 &self,
202 node: &Node,
203 acquired_nodes: &mut AcquiredNodes<'_>,
204 cascaded: &CascadedValues<'_>,
205 viewport: &Viewport,
206 draw_ctx: &mut DrawingCtx,
207 clipping: bool,
208 ) -> DrawResult {
209 self.layout(node, acquired_nodes, cascaded, viewport, draw_ctx)
210 .and_then(|layer| {
211 if let Some(layer) = layer {
212 draw_ctx.draw_layer(&layer, acquired_nodes, clipping, viewport)
213 } else {
214 Ok(viewport.empty_bbox())
215 }
216 })
217 }
218 };
219}
220
221fn acquire_marker(
222 session: &Session,
223 referencing_element_name: &str,
224 acquired_nodes: &mut AcquiredNodes<'_>,
225 iri: &Iri,
226) -> Option<Node> {
227 iri.get().and_then(|id| {
228 acquired_nodes
229 .acquire(referencing_element_name, id)
230 .map_err(|e| {
231 rsvg_log!(session, "cannot render marker: {}", e);
232 })
233 .ok()
234 .and_then(|acquired| {
235 let node = acquired.get();
236
237 if is_element_of_type!(node, Marker) {
238 Some(node.clone())
239 } else {
240 rsvg_log!(session, "{} is not a marker element", id);
241 None
242 }
243 })
244 })
245}
246
247fn make_ellipse(cx: f64, cy: f64, rx: f64, ry: f64) -> SvgPath {
248 let mut builder = PathBuilder::default();
249
250 if rx <= 0.0 || ry <= 0.0 {
252 return builder.into_path();
253 }
254
255 let arc_magic: f64 = 0.5522847498;
257
258 builder.move_to(cx + rx, cy);
261
262 builder.curve_to(
263 cx + rx,
264 cy + arc_magic * ry,
265 cx + arc_magic * rx,
266 cy + ry,
267 cx,
268 cy + ry,
269 );
270
271 builder.curve_to(
272 cx - arc_magic * rx,
273 cy + ry,
274 cx - rx,
275 cy + arc_magic * ry,
276 cx - rx,
277 cy,
278 );
279
280 builder.curve_to(
281 cx - rx,
282 cy - arc_magic * ry,
283 cx - arc_magic * rx,
284 cy - ry,
285 cx,
286 cy - ry,
287 );
288
289 builder.curve_to(
290 cx + arc_magic * rx,
291 cy - ry,
292 cx + rx,
293 cy - arc_magic * ry,
294 cx + rx,
295 cy,
296 );
297
298 builder.close_path();
299
300 builder.into_path()
301}
302
303#[derive(Default)]
304pub struct Path {
305 path: Rc<SvgPath>,
306}
307
308impl ElementTrait for Path {
309 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
310 for (attr, value) in attrs.iter() {
311 if attr.expanded() == expanded_name!("", "d") {
312 let mut builder = PathBuilder::default();
313 if let Err(e) = builder.parse(value) {
314 rsvg_log!(session, "could not parse path: {}", e);
318 }
319 self.path = Rc::new(builder.into_path());
320 }
321 }
322 }
323
324 impl_draw!();
325}
326
327impl BasicShape for Path {
328 fn make_shape(&self, params: &NormalizeParams, values: &ComputedValues) -> ShapeDef {
329 ShapeDef::new(self.make_path(params, values), Markers::Yes)
330 }
331}
332
333impl Path {
334 pub fn make_path(&self, _params: &NormalizeParams, _values: &ComputedValues) -> Rc<SvgPath> {
335 self.path.clone()
336 }
337}
338
339#[derive(Debug, Default, PartialEq)]
345struct Points(Vec<(f64, f64)>);
346
347impl Deref for Points {
348 type Target = [(f64, f64)];
349
350 fn deref(&self) -> &[(f64, f64)] {
351 &self.0
352 }
353}
354
355impl Parse for Points {
356 fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Points, ParseError<'i>> {
357 let mut v = Vec::new();
358
359 loop {
360 let x = f64::parse(parser)?;
361 optional_comma(parser);
362 let y = f64::parse(parser)?;
363
364 v.push((x, y));
365
366 if parser.is_exhausted() {
367 break;
368 }
369
370 match parser.next_including_whitespace() {
371 Ok(&Token::WhiteSpace(_)) => (),
372 _ => optional_comma(parser),
373 }
374 }
375
376 Ok(Points(v))
377 }
378}
379
380fn make_poly(points: &Points, closed: bool) -> SvgPath {
381 let mut builder = PathBuilder::default();
382
383 for (i, &(x, y)) in points.iter().enumerate() {
384 if i == 0 {
385 builder.move_to(x, y);
386 } else {
387 builder.line_to(x, y);
388 }
389 }
390
391 if closed && !points.is_empty() {
392 builder.close_path();
393 }
394
395 builder.into_path()
396}
397
398#[derive(Default)]
399pub struct Polygon {
400 points: Points,
401}
402
403impl ElementTrait for Polygon {
404 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
405 for (attr, value) in attrs.iter() {
406 if attr.expanded() == expanded_name!("", "points") {
407 set_attribute(&mut self.points, attr.parse(value), session);
408 }
409 }
410 }
411
412 impl_draw!();
413}
414
415impl BasicShape for Polygon {
416 fn make_shape(&self, params: &NormalizeParams, values: &ComputedValues) -> ShapeDef {
417 ShapeDef::new(self.make_path(params, values), Markers::Yes)
418 }
419}
420
421impl Polygon {
422 pub fn make_path(&self, _params: &NormalizeParams, _values: &ComputedValues) -> Rc<SvgPath> {
423 Rc::new(make_poly(&self.points, true))
424 }
425}
426
427#[derive(Default)]
428pub struct Polyline {
429 points: Points,
430}
431
432impl ElementTrait for Polyline {
433 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
434 for (attr, value) in attrs.iter() {
435 if attr.expanded() == expanded_name!("", "points") {
436 set_attribute(&mut self.points, attr.parse(value), session);
437 }
438 }
439 }
440
441 impl_draw!();
442}
443
444impl BasicShape for Polyline {
445 fn make_shape(&self, params: &NormalizeParams, values: &ComputedValues) -> ShapeDef {
446 ShapeDef::new(self.make_path(params, values), Markers::Yes)
447 }
448}
449
450impl Polyline {
451 pub fn make_path(&self, _params: &NormalizeParams, _values: &ComputedValues) -> Rc<SvgPath> {
452 Rc::new(make_poly(&self.points, false))
453 }
454}
455
456#[derive(Default)]
457pub struct Line {
458 x1: Length<Horizontal>,
459 y1: Length<Vertical>,
460 x2: Length<Horizontal>,
461 y2: Length<Vertical>,
462}
463
464impl ElementTrait for Line {
465 fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
466 for (attr, value) in attrs.iter() {
467 match attr.expanded() {
468 expanded_name!("", "x1") => set_attribute(&mut self.x1, attr.parse(value), session),
469 expanded_name!("", "y1") => set_attribute(&mut self.y1, attr.parse(value), session),
470 expanded_name!("", "x2") => set_attribute(&mut self.x2, attr.parse(value), session),
471 expanded_name!("", "y2") => set_attribute(&mut self.y2, attr.parse(value), session),
472 _ => (),
473 }
474 }
475 }
476
477 impl_draw!();
478}
479
480impl BasicShape for Line {
481 fn make_shape(&self, params: &NormalizeParams, values: &ComputedValues) -> ShapeDef {
482 ShapeDef::new(self.make_path(params, values), Markers::Yes)
483 }
484}
485
486impl Line {
487 pub fn make_path(&self, params: &NormalizeParams, _values: &ComputedValues) -> Rc<SvgPath> {
488 let mut builder = PathBuilder::default();
489
490 let x1 = self.x1.to_user(params);
491 let y1 = self.y1.to_user(params);
492 let x2 = self.x2.to_user(params);
493 let y2 = self.y2.to_user(params);
494
495 builder.move_to(x1, y1);
496 builder.line_to(x2, y2);
497
498 Rc::new(builder.into_path())
499 }
500}
501
502#[derive(Default)]
507pub struct Rect {}
508
509impl ElementTrait for Rect {
510 impl_draw!();
511}
512
513impl BasicShape for Rect {
514 fn make_shape(&self, params: &NormalizeParams, values: &ComputedValues) -> ShapeDef {
515 ShapeDef::new(self.make_path(params, values), Markers::No)
516 }
517}
518
519impl Rect {
520 #[allow(clippy::many_single_char_names)]
521 pub fn make_path(&self, params: &NormalizeParams, values: &ComputedValues) -> Rc<SvgPath> {
522 let x = values.x().0.to_user(params);
523 let y = values.y().0.to_user(params);
524
525 let w = match values.width().0 {
526 LengthOrAuto::Length(l) => l.to_user(params),
527 LengthOrAuto::Auto => 0.0,
528 };
529 let h = match values.height().0 {
530 LengthOrAuto::Length(l) => l.to_user(params),
531 LengthOrAuto::Auto => 0.0,
532 };
533
534 let norm_rx = match values.rx().0 {
535 LengthOrAuto::Length(l) => Some(l.to_user(params)),
536 LengthOrAuto::Auto => None,
537 };
538 let norm_ry = match values.ry().0 {
539 LengthOrAuto::Length(l) => Some(l.to_user(params)),
540 LengthOrAuto::Auto => None,
541 };
542
543 let mut rx;
544 let mut ry;
545
546 match (norm_rx, norm_ry) {
547 (None, None) => {
548 rx = 0.0;
549 ry = 0.0;
550 }
551
552 (Some(_rx), None) => {
553 rx = _rx;
554 ry = _rx;
555 }
556
557 (None, Some(_ry)) => {
558 rx = _ry;
559 ry = _ry;
560 }
561
562 (Some(_rx), Some(_ry)) => {
563 rx = _rx;
564 ry = _ry;
565 }
566 }
567
568 let mut builder = PathBuilder::default();
569
570 if w <= 0.0 || h <= 0.0 {
572 return Rc::new(builder.into_path());
573 }
574
575 let half_w = w / 2.0;
576 let half_h = h / 2.0;
577
578 if rx > half_w {
579 rx = half_w;
580 }
581
582 if ry > half_h {
583 ry = half_h;
584 }
585
586 if rx == 0.0 {
587 ry = 0.0;
588 } else if ry == 0.0 {
589 rx = 0.0;
590 }
591
592 if rx == 0.0 {
593 builder.move_to(x, y);
595 builder.line_to(x + w, y);
596 builder.line_to(x + w, y + h);
597 builder.line_to(x, y + h);
598 builder.line_to(x, y);
599 } else {
600 let top_x1 = x + rx;
622 let top_x2 = x + w - rx;
623 let top_y = y;
624
625 let bottom_x1 = top_x1;
626 let bottom_x2 = top_x2;
627 let bottom_y = y + h;
628
629 let left_x = x;
630 let left_y1 = y + ry;
631 let left_y2 = y + h - ry;
632
633 let right_x = x + w;
634 let right_y1 = left_y1;
635 let right_y2 = left_y2;
636
637 builder.move_to(top_x1, top_y);
638 builder.line_to(top_x2, top_y);
639
640 builder.arc(
641 top_x2,
642 top_y,
643 rx,
644 ry,
645 0.0,
646 LargeArc(false),
647 Sweep::Positive,
648 right_x,
649 right_y1,
650 );
651
652 builder.line_to(right_x, right_y2);
653
654 builder.arc(
655 right_x,
656 right_y2,
657 rx,
658 ry,
659 0.0,
660 LargeArc(false),
661 Sweep::Positive,
662 bottom_x2,
663 bottom_y,
664 );
665
666 builder.line_to(bottom_x1, bottom_y);
667
668 builder.arc(
669 bottom_x1,
670 bottom_y,
671 rx,
672 ry,
673 0.0,
674 LargeArc(false),
675 Sweep::Positive,
676 left_x,
677 left_y2,
678 );
679
680 builder.line_to(left_x, left_y1);
681
682 builder.arc(
683 left_x,
684 left_y1,
685 rx,
686 ry,
687 0.0,
688 LargeArc(false),
689 Sweep::Positive,
690 top_x1,
691 top_y,
692 );
693 }
694
695 builder.close_path();
696
697 Rc::new(builder.into_path())
698 }
699}
700
701#[derive(Default)]
706pub struct Circle {}
707
708impl ElementTrait for Circle {
709 impl_draw!();
710}
711
712impl BasicShape for Circle {
713 fn make_shape(&self, params: &NormalizeParams, values: &ComputedValues) -> ShapeDef {
714 ShapeDef::new(self.make_path(params, values), Markers::No)
715 }
716}
717
718impl Circle {
719 pub fn make_path(&self, params: &NormalizeParams, values: &ComputedValues) -> Rc<SvgPath> {
720 let cx = values.cx().0.to_user(params);
721 let cy = values.cy().0.to_user(params);
722 let r = values.r().0.to_user(params);
723
724 Rc::new(make_ellipse(cx, cy, r, r))
725 }
726}
727
728#[derive(Default)]
733pub struct Ellipse {}
734
735impl ElementTrait for Ellipse {
736 impl_draw!();
737}
738
739impl BasicShape for Ellipse {
740 fn make_shape(&self, params: &NormalizeParams, values: &ComputedValues) -> ShapeDef {
741 ShapeDef::new(self.make_path(params, values), Markers::No)
742 }
743}
744
745impl Ellipse {
746 pub fn make_path(&self, params: &NormalizeParams, values: &ComputedValues) -> Rc<SvgPath> {
747 let cx = values.cx().0.to_user(params);
748 let cy = values.cy().0.to_user(params);
749 let norm_rx = match values.rx().0 {
750 LengthOrAuto::Length(l) => Some(l.to_user(params)),
751 LengthOrAuto::Auto => None,
752 };
753 let norm_ry = match values.ry().0 {
754 LengthOrAuto::Length(l) => Some(l.to_user(params)),
755 LengthOrAuto::Auto => None,
756 };
757
758 let rx;
759 let ry;
760
761 match (norm_rx, norm_ry) {
762 (None, None) => {
763 rx = 0.0;
764 ry = 0.0;
765 }
766
767 (Some(_rx), None) => {
768 rx = _rx;
769 ry = _rx;
770 }
771
772 (None, Some(_ry)) => {
773 rx = _ry;
774 ry = _ry;
775 }
776
777 (Some(_rx), Some(_ry)) => {
778 rx = _rx;
779 ry = _ry;
780 }
781 }
782
783 Rc::new(make_ellipse(cx, cy, rx, ry))
784 }
785}
786
787#[cfg(test)]
788mod tests {
789 use super::*;
790
791 #[test]
792 fn parses_points() {
793 assert_eq!(
794 Points::parse_str(" 1 2 ").unwrap(),
795 Points(vec![(1.0, 2.0)])
796 );
797 assert_eq!(
798 Points::parse_str("1 2 3 4").unwrap(),
799 Points(vec![(1.0, 2.0), (3.0, 4.0)])
800 );
801 assert_eq!(
802 Points::parse_str("1,2,3,4").unwrap(),
803 Points(vec![(1.0, 2.0), (3.0, 4.0)])
804 );
805 assert_eq!(
806 Points::parse_str("1,2 3,4").unwrap(),
807 Points(vec![(1.0, 2.0), (3.0, 4.0)])
808 );
809 assert_eq!(
810 Points::parse_str("1,2 -3,4").unwrap(),
811 Points(vec![(1.0, 2.0), (-3.0, 4.0)])
812 );
813 assert_eq!(
814 Points::parse_str("1,2,-3,4").unwrap(),
815 Points(vec![(1.0, 2.0), (-3.0, 4.0)])
816 );
817 }
818
819 #[test]
820 fn errors_on_invalid_points() {
821 assert!(Points::parse_str("-1-2-3-4").is_err());
822 assert!(Points::parse_str("1 2-3,-4").is_err());
823 }
824}