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(¶ms);
58
59 let is_visible = values.is_visible();
60 let paint_order = values.paint_order();
61
62 let stroke = Stroke::new(values, ¶ms);
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