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