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