1 //! Basic SVG shapes: the `path`, `polygon`, `polyline`, `line`,
2 //! `rect`, `circle`, `ellipse` elements.
3 
4 use cssparser::{Parser, Token};
5 use markup5ever::{expanded_name, local_name, namespace_url, ns};
6 use std::ops::Deref;
7 use std::rc::Rc;
8 
9 use crate::bbox::BoundingBox;
10 use crate::document::AcquiredNodes;
11 use crate::drawing_ctx::DrawingCtx;
12 use crate::element::{Draw, ElementResult, SetAttributes};
13 use crate::error::*;
14 use crate::iri::Iri;
15 use crate::layout::{Marker, Shape, StackingContext, Stroke};
16 use crate::length::*;
17 use crate::node::{CascadedValues, Node, NodeBorrow};
18 use crate::parsers::{optional_comma, Parse, ParseValue};
19 use crate::path_builder::{LargeArc, Path as SvgPath, PathBuilder, Sweep};
20 use crate::xml::Attributes;
21 
22 #[derive(PartialEq)]
23 enum Markers {
24     No,
25     Yes,
26 }
27 
28 struct ShapeDef {
29     path: Rc<SvgPath>,
30     markers: Markers,
31 }
32 
33 impl ShapeDef {
new(path: Rc<SvgPath>, markers: Markers) -> ShapeDef34     fn new(path: Rc<SvgPath>, markers: Markers) -> ShapeDef {
35         ShapeDef { path, markers }
36     }
37 }
38 
39 trait BasicShape {
make_shape(&self, params: &NormalizeParams) -> ShapeDef40     fn make_shape(&self, params: &NormalizeParams) -> ShapeDef;
41 }
42 
43 macro_rules! impl_draw {
44     ($name:ident) => {
45         impl Draw for $name {
46             fn draw(
47                 &self,
48                 node: &Node,
49                 acquired_nodes: &mut AcquiredNodes<'_>,
50                 cascaded: &CascadedValues<'_>,
51                 draw_ctx: &mut DrawingCtx,
52                 clipping: bool,
53             ) -> Result<BoundingBox, RenderingError> {
54                 let values = cascaded.get();
55                 let view_params = draw_ctx.get_view_params();
56                 let params = NormalizeParams::new(values, &view_params);
57                 let shape_def = self.make_shape(&params);
58 
59                 let is_visible = values.is_visible();
60                 let paint_order = values.paint_order();
61 
62                 let stroke = Stroke::new(values, &params);
63 
64                 let stroke_paint = values.stroke().0.resolve(
65                     acquired_nodes,
66                     values.stroke_opacity().0,
67                     values.color().0,
68                     cascaded.context_fill.clone(),
69                     cascaded.context_stroke.clone(),
70                 );
71 
72                 let fill_paint = values.fill().0.resolve(
73                     acquired_nodes,
74                     values.fill_opacity().0,
75                     values.color().0,
76                     cascaded.context_fill.clone(),
77                     cascaded.context_stroke.clone(),
78                 );
79 
80                 let fill_rule = values.fill_rule();
81                 let clip_rule = values.clip_rule();
82                 let shape_rendering = values.shape_rendering();
83 
84                 let marker_start_node;
85                 let marker_mid_node;
86                 let marker_end_node;
87 
88                 if shape_def.markers == Markers::Yes {
89                     marker_start_node = acquire_marker(acquired_nodes, &values.marker_start().0);
90                     marker_mid_node = acquire_marker(acquired_nodes, &values.marker_mid().0);
91                     marker_end_node = acquire_marker(acquired_nodes, &values.marker_end().0);
92                 } else {
93                     marker_start_node = None;
94                     marker_mid_node = None;
95                     marker_end_node = None;
96                 }
97 
98                 let marker_start = Marker {
99                     node_ref: marker_start_node,
100                     context_stroke: stroke_paint.clone(),
101                     context_fill: fill_paint.clone(),
102                 };
103 
104                 let marker_mid = Marker {
105                     node_ref: marker_mid_node,
106                     context_stroke: stroke_paint.clone(),
107                     context_fill: fill_paint.clone(),
108                 };
109 
110                 let marker_end = Marker {
111                     node_ref: marker_end_node,
112                     context_stroke: stroke_paint.clone(),
113                     context_fill: fill_paint.clone(),
114                 };
115 
116                 let shape = Shape {
117                     path: shape_def.path,
118                     is_visible,
119                     paint_order,
120                     stroke,
121                     stroke_paint,
122                     fill_paint,
123                     fill_rule,
124                     clip_rule,
125                     shape_rendering,
126                     marker_start,
127                     marker_mid,
128                     marker_end,
129                 };
130 
131                 let elt = node.borrow_element();
132                 let stacking_ctx =
133                     StackingContext::new(acquired_nodes, &elt, values.transform(), values);
134 
135                 draw_ctx.draw_shape(
136                     &view_params,
137                     &shape,
138                     &stacking_ctx,
139                     acquired_nodes,
140                     values,
141                     clipping,
142                 )
143             }
144         }
145     };
146 }
147 
acquire_marker(acquired_nodes: &mut AcquiredNodes<'_>, iri: &Iri) -> Option<Node>148 fn acquire_marker(acquired_nodes: &mut AcquiredNodes<'_>, iri: &Iri) -> Option<Node> {
149     iri.get().and_then(|id| {
150         acquired_nodes
151             .acquire(id)
152             .map_err(|e| {
153                 rsvg_log!("cannot render marker: {}", e);
154             })
155             .ok()
156             .and_then(|acquired| {
157                 let node = acquired.get();
158 
159                 if is_element_of_type!(node, Marker) {
160                     Some(node.clone())
161                 } else {
162                     rsvg_log!("{} is not a marker element", id);
163                     None
164                 }
165             })
166     })
167 }
168 
make_ellipse(cx: f64, cy: f64, rx: f64, ry: f64) -> SvgPath169 fn make_ellipse(cx: f64, cy: f64, rx: f64, ry: f64) -> SvgPath {
170     let mut builder = PathBuilder::default();
171 
172     // Per the spec, rx and ry must be nonnegative
173     if rx <= 0.0 || ry <= 0.0 {
174         return builder.into_path();
175     }
176 
177     // 4/3 * (1-cos 45°)/sin 45° = 4/3 * sqrt(2) - 1
178     let arc_magic: f64 = 0.5522847498;
179 
180     // approximate an ellipse using 4 Bézier curves
181 
182     builder.move_to(cx + rx, cy);
183 
184     builder.curve_to(
185         cx + rx,
186         cy + arc_magic * ry,
187         cx + arc_magic * rx,
188         cy + ry,
189         cx,
190         cy + ry,
191     );
192 
193     builder.curve_to(
194         cx - arc_magic * rx,
195         cy + ry,
196         cx - rx,
197         cy + arc_magic * ry,
198         cx - rx,
199         cy,
200     );
201 
202     builder.curve_to(
203         cx - rx,
204         cy - arc_magic * ry,
205         cx - arc_magic * rx,
206         cy - ry,
207         cx,
208         cy - ry,
209     );
210 
211     builder.curve_to(
212         cx + arc_magic * rx,
213         cy - ry,
214         cx + rx,
215         cy - arc_magic * ry,
216         cx + rx,
217         cy,
218     );
219 
220     builder.close_path();
221 
222     builder.into_path()
223 }
224 
225 #[derive(Default)]
226 pub struct Path {
227     path: Rc<SvgPath>,
228 }
229 
230 impl_draw!(Path);
231 
232 impl SetAttributes for Path {
set_attributes(&mut self, attrs: &Attributes) -> ElementResult233     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
234         for (attr, value) in attrs.iter() {
235             if attr.expanded() == expanded_name!("", "d") {
236                 let mut builder = PathBuilder::default();
237                 if let Err(e) = builder.parse(value) {
238                     // FIXME: we don't propagate errors upstream, but creating a partial
239                     // path is OK per the spec
240 
241                     rsvg_log!("could not parse path: {}", e);
242                 }
243                 self.path = Rc::new(builder.into_path());
244             }
245         }
246 
247         Ok(())
248     }
249 }
250 
251 impl BasicShape for Path {
make_shape(&self, _params: &NormalizeParams) -> ShapeDef252     fn make_shape(&self, _params: &NormalizeParams) -> ShapeDef {
253         ShapeDef::new(self.path.clone(), Markers::Yes)
254     }
255 }
256 
257 #[derive(Debug, Default, PartialEq)]
258 struct Points(Vec<(f64, f64)>);
259 
260 impl Deref for Points {
261     type Target = [(f64, f64)];
262 
deref(&self) -> &[(f64, f64)]263     fn deref(&self) -> &[(f64, f64)] {
264         &self.0
265     }
266 }
267 
268 // Parse a list-of-points as for polyline and polygon elements
269 // https://www.w3.org/TR/SVG/shapes.html#PointsBNF
270 impl Parse for Points {
parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Points, ParseError<'i>>271     fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Points, ParseError<'i>> {
272         let mut v = Vec::new();
273 
274         loop {
275             let x = f64::parse(parser)?;
276             optional_comma(parser);
277             let y = f64::parse(parser)?;
278 
279             v.push((x, y));
280 
281             if parser.is_exhausted() {
282                 break;
283             }
284 
285             match parser.next_including_whitespace() {
286                 Ok(&Token::WhiteSpace(_)) => (),
287                 _ => optional_comma(parser),
288             }
289         }
290 
291         Ok(Points(v))
292     }
293 }
294 
make_poly(points: &Points, closed: bool) -> SvgPath295 fn make_poly(points: &Points, closed: bool) -> SvgPath {
296     let mut builder = PathBuilder::default();
297 
298     for (i, &(x, y)) in points.iter().enumerate() {
299         if i == 0 {
300             builder.move_to(x, y);
301         } else {
302             builder.line_to(x, y);
303         }
304     }
305 
306     if closed && !points.is_empty() {
307         builder.close_path();
308     }
309 
310     builder.into_path()
311 }
312 
313 #[derive(Default)]
314 pub struct Polygon {
315     points: Points,
316 }
317 
318 impl_draw!(Polygon);
319 
320 impl SetAttributes for Polygon {
set_attributes(&mut self, attrs: &Attributes) -> ElementResult321     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
322         for (attr, value) in attrs.iter() {
323             if attr.expanded() == expanded_name!("", "points") {
324                 self.points = attr.parse(value)?;
325             }
326         }
327 
328         Ok(())
329     }
330 }
331 
332 impl BasicShape for Polygon {
make_shape(&self, _params: &NormalizeParams) -> ShapeDef333     fn make_shape(&self, _params: &NormalizeParams) -> ShapeDef {
334         ShapeDef::new(Rc::new(make_poly(&self.points, true)), Markers::Yes)
335     }
336 }
337 
338 #[derive(Default)]
339 pub struct Polyline {
340     points: Points,
341 }
342 
343 impl_draw!(Polyline);
344 
345 impl SetAttributes for Polyline {
set_attributes(&mut self, attrs: &Attributes) -> ElementResult346     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
347         for (attr, value) in attrs.iter() {
348             if attr.expanded() == expanded_name!("", "points") {
349                 self.points = attr.parse(value)?;
350             }
351         }
352 
353         Ok(())
354     }
355 }
356 
357 impl BasicShape for Polyline {
make_shape(&self, _params: &NormalizeParams) -> ShapeDef358     fn make_shape(&self, _params: &NormalizeParams) -> ShapeDef {
359         ShapeDef::new(Rc::new(make_poly(&self.points, false)), Markers::Yes)
360     }
361 }
362 
363 #[derive(Default)]
364 pub struct Line {
365     x1: Length<Horizontal>,
366     y1: Length<Vertical>,
367     x2: Length<Horizontal>,
368     y2: Length<Vertical>,
369 }
370 
371 impl_draw!(Line);
372 
373 impl SetAttributes for Line {
set_attributes(&mut self, attrs: &Attributes) -> ElementResult374     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
375         for (attr, value) in attrs.iter() {
376             match attr.expanded() {
377                 expanded_name!("", "x1") => self.x1 = attr.parse(value)?,
378                 expanded_name!("", "y1") => self.y1 = attr.parse(value)?,
379                 expanded_name!("", "x2") => self.x2 = attr.parse(value)?,
380                 expanded_name!("", "y2") => self.y2 = attr.parse(value)?,
381                 _ => (),
382             }
383         }
384 
385         Ok(())
386     }
387 }
388 
389 impl BasicShape for Line {
make_shape(&self, params: &NormalizeParams) -> ShapeDef390     fn make_shape(&self, params: &NormalizeParams) -> ShapeDef {
391         let mut builder = PathBuilder::default();
392 
393         let x1 = self.x1.to_user(params);
394         let y1 = self.y1.to_user(params);
395         let x2 = self.x2.to_user(params);
396         let y2 = self.y2.to_user(params);
397 
398         builder.move_to(x1, y1);
399         builder.line_to(x2, y2);
400 
401         ShapeDef::new(Rc::new(builder.into_path()), Markers::Yes)
402     }
403 }
404 
405 #[derive(Default)]
406 pub struct Rect {
407     x: Length<Horizontal>,
408     y: Length<Vertical>,
409     width: LengthOrAuto<Horizontal>,
410     height: LengthOrAuto<Vertical>,
411 
412     // Radiuses for rounded corners
413     rx: Option<Length<Horizontal>>,
414     ry: Option<Length<Vertical>>,
415 }
416 
417 impl_draw!(Rect);
418 
419 impl SetAttributes for Rect {
set_attributes(&mut self, attrs: &Attributes) -> ElementResult420     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
421         for (attr, value) in attrs.iter() {
422             match attr.expanded() {
423                 expanded_name!("", "x") => self.x = attr.parse(value)?,
424                 expanded_name!("", "y") => self.y = attr.parse(value)?,
425                 expanded_name!("", "width") => self.width = attr.parse(value)?,
426                 expanded_name!("", "height") => self.height = attr.parse(value)?,
427                 expanded_name!("", "rx") => self.rx = attr.parse(value)?,
428                 expanded_name!("", "ry") => self.ry = attr.parse(value)?,
429                 _ => (),
430             }
431         }
432 
433         Ok(())
434     }
435 }
436 
437 impl BasicShape for Rect {
438     #[allow(clippy::many_single_char_names)]
make_shape(&self, params: &NormalizeParams) -> ShapeDef439     fn make_shape(&self, params: &NormalizeParams) -> ShapeDef {
440         let x = self.x.to_user(params);
441         let y = self.y.to_user(params);
442 
443         let w = match self.width {
444             LengthOrAuto::Length(l) => l.to_user(params),
445             LengthOrAuto::Auto => 0.0,
446         };
447         let h = match self.height {
448             LengthOrAuto::Length(l) => l.to_user(params),
449             LengthOrAuto::Auto => 0.0,
450         };
451 
452         let specified_rx = self.rx.map(|l| l.to_user(params));
453         let specified_ry = self.ry.map(|l| l.to_user(params));
454 
455         fn nonnegative_or_none(l: f64) -> Option<f64> {
456             if l < 0.0 {
457                 None
458             } else {
459                 Some(l)
460             }
461         }
462 
463         let norm_rx = specified_rx.and_then(nonnegative_or_none);
464         let norm_ry = specified_ry.and_then(nonnegative_or_none);
465 
466         let mut rx;
467         let mut ry;
468 
469         match (norm_rx, norm_ry) {
470             (None, None) => {
471                 rx = 0.0;
472                 ry = 0.0;
473             }
474 
475             (Some(_rx), None) => {
476                 rx = _rx;
477                 ry = _rx;
478             }
479 
480             (None, Some(_ry)) => {
481                 rx = _ry;
482                 ry = _ry;
483             }
484 
485             (Some(_rx), Some(_ry)) => {
486                 rx = _rx;
487                 ry = _ry;
488             }
489         }
490 
491         let mut builder = PathBuilder::default();
492 
493         // Per the spec, w,h must be >= 0
494         if w <= 0.0 || h <= 0.0 {
495             return ShapeDef::new(Rc::new(builder.into_path()), Markers::No);
496         }
497 
498         let half_w = w / 2.0;
499         let half_h = h / 2.0;
500 
501         if rx > half_w {
502             rx = half_w;
503         }
504 
505         if ry > half_h {
506             ry = half_h;
507         }
508 
509         if rx == 0.0 {
510             ry = 0.0;
511         } else if ry == 0.0 {
512             rx = 0.0;
513         }
514 
515         if rx == 0.0 {
516             // Easy case, no rounded corners
517             builder.move_to(x, y);
518             builder.line_to(x + w, y);
519             builder.line_to(x + w, y + h);
520             builder.line_to(x, y + h);
521             builder.line_to(x, y);
522         } else {
523             /* Hard case, rounded corners
524              *
525              *      (top_x1, top_y)                   (top_x2, top_y)
526              *     *--------------------------------*
527              *    /                                  \
528              *   * (left_x, left_y1)                  * (right_x, right_y1)
529              *   |                                    |
530              *   |                                    |
531              *   |                                    |
532              *   |                                    |
533              *   |                                    |
534              *   |                                    |
535              *   |                                    |
536              *   |                                    |
537              *   |                                    |
538              *   * (left_x, left_y2)                  * (right_x, right_y2)
539              *    \                                  /
540              *     *--------------------------------*
541              *      (bottom_x1, bottom_y)            (bottom_x2, bottom_y)
542              */
543 
544             let top_x1 = x + rx;
545             let top_x2 = x + w - rx;
546             let top_y = y;
547 
548             let bottom_x1 = top_x1;
549             let bottom_x2 = top_x2;
550             let bottom_y = y + h;
551 
552             let left_x = x;
553             let left_y1 = y + ry;
554             let left_y2 = y + h - ry;
555 
556             let right_x = x + w;
557             let right_y1 = left_y1;
558             let right_y2 = left_y2;
559 
560             builder.move_to(top_x1, top_y);
561             builder.line_to(top_x2, top_y);
562 
563             builder.arc(
564                 top_x2,
565                 top_y,
566                 rx,
567                 ry,
568                 0.0,
569                 LargeArc(false),
570                 Sweep::Positive,
571                 right_x,
572                 right_y1,
573             );
574 
575             builder.line_to(right_x, right_y2);
576 
577             builder.arc(
578                 right_x,
579                 right_y2,
580                 rx,
581                 ry,
582                 0.0,
583                 LargeArc(false),
584                 Sweep::Positive,
585                 bottom_x2,
586                 bottom_y,
587             );
588 
589             builder.line_to(bottom_x1, bottom_y);
590 
591             builder.arc(
592                 bottom_x1,
593                 bottom_y,
594                 rx,
595                 ry,
596                 0.0,
597                 LargeArc(false),
598                 Sweep::Positive,
599                 left_x,
600                 left_y2,
601             );
602 
603             builder.line_to(left_x, left_y1);
604 
605             builder.arc(
606                 left_x,
607                 left_y1,
608                 rx,
609                 ry,
610                 0.0,
611                 LargeArc(false),
612                 Sweep::Positive,
613                 top_x1,
614                 top_y,
615             );
616         }
617 
618         builder.close_path();
619 
620         ShapeDef::new(Rc::new(builder.into_path()), Markers::No)
621     }
622 }
623 
624 #[derive(Default)]
625 pub struct Circle {
626     cx: Length<Horizontal>,
627     cy: Length<Vertical>,
628     r: ULength<Both>,
629 }
630 
631 impl_draw!(Circle);
632 
633 impl SetAttributes for Circle {
set_attributes(&mut self, attrs: &Attributes) -> ElementResult634     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
635         for (attr, value) in attrs.iter() {
636             match attr.expanded() {
637                 expanded_name!("", "cx") => self.cx = attr.parse(value)?,
638                 expanded_name!("", "cy") => self.cy = attr.parse(value)?,
639                 expanded_name!("", "r") => self.r = attr.parse(value)?,
640                 _ => (),
641             }
642         }
643 
644         Ok(())
645     }
646 }
647 
648 impl BasicShape for Circle {
make_shape(&self, params: &NormalizeParams) -> ShapeDef649     fn make_shape(&self, params: &NormalizeParams) -> ShapeDef {
650         let cx = self.cx.to_user(params);
651         let cy = self.cy.to_user(params);
652         let r = self.r.to_user(params);
653 
654         ShapeDef::new(Rc::new(make_ellipse(cx, cy, r, r)), Markers::No)
655     }
656 }
657 
658 #[derive(Default)]
659 pub struct Ellipse {
660     cx: Length<Horizontal>,
661     cy: Length<Vertical>,
662     rx: ULength<Horizontal>,
663     ry: ULength<Vertical>,
664 }
665 
666 impl_draw!(Ellipse);
667 
668 impl SetAttributes for Ellipse {
set_attributes(&mut self, attrs: &Attributes) -> ElementResult669     fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
670         for (attr, value) in attrs.iter() {
671             match attr.expanded() {
672                 expanded_name!("", "cx") => self.cx = attr.parse(value)?,
673                 expanded_name!("", "cy") => self.cy = attr.parse(value)?,
674                 expanded_name!("", "rx") => self.rx = attr.parse(value)?,
675                 expanded_name!("", "ry") => self.ry = attr.parse(value)?,
676                 _ => (),
677             }
678         }
679 
680         Ok(())
681     }
682 }
683 
684 impl BasicShape for Ellipse {
make_shape(&self, params: &NormalizeParams) -> ShapeDef685     fn make_shape(&self, params: &NormalizeParams) -> ShapeDef {
686         let cx = self.cx.to_user(params);
687         let cy = self.cy.to_user(params);
688         let rx = self.rx.to_user(params);
689         let ry = self.ry.to_user(params);
690 
691         ShapeDef::new(Rc::new(make_ellipse(cx, cy, rx, ry)), Markers::No)
692     }
693 }
694 
695 #[cfg(test)]
696 mod tests {
697     use super::*;
698 
699     #[test]
parses_points()700     fn parses_points() {
701         assert_eq!(
702             Points::parse_str(" 1 2 ").unwrap(),
703             Points(vec![(1.0, 2.0)])
704         );
705         assert_eq!(
706             Points::parse_str("1 2 3 4").unwrap(),
707             Points(vec![(1.0, 2.0), (3.0, 4.0)])
708         );
709         assert_eq!(
710             Points::parse_str("1,2,3,4").unwrap(),
711             Points(vec![(1.0, 2.0), (3.0, 4.0)])
712         );
713         assert_eq!(
714             Points::parse_str("1,2 3,4").unwrap(),
715             Points(vec![(1.0, 2.0), (3.0, 4.0)])
716         );
717         assert_eq!(
718             Points::parse_str("1,2 -3,4").unwrap(),
719             Points(vec![(1.0, 2.0), (-3.0, 4.0)])
720         );
721         assert_eq!(
722             Points::parse_str("1,2,-3,4").unwrap(),
723             Points(vec![(1.0, 2.0), (-3.0, 4.0)])
724         );
725     }
726 
727     #[test]
errors_on_invalid_points()728     fn errors_on_invalid_points() {
729         assert!(Points::parse_str("-1-2-3-4").is_err());
730         assert!(Points::parse_str("1 2-3,-4").is_err());
731     }
732 }
733