[librsvg: 1/3] (#618) Implement context-fill and context-stroke




commit 1c1125829cde019804b85e6f39cbf37339e6eeaf
Author: Madds H <madds hollandart io>
Date:   Fri Jun 25 16:59:00 2021 -0500

    (#618) Implement context-fill and context-stroke
    
    Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/556>

 src/drawing_ctx.rs  | 14 ++++++++++++--
 src/layout.rs       | 12 +++++++++---
 src/marker.rs       | 26 +++++++++++++++++---------
 src/node.rs         | 16 ++++++++++++++++
 src/paint_server.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++
 src/shapes.rs       | 41 +++++++++++++++++++++++++++++++----------
 src/text.rs         |  2 ++
 7 files changed, 132 insertions(+), 24 deletions(-)
---
diff --git a/src/drawing_ctx.rs b/src/drawing_ctx.rs
index 573d33ce..5ea9e9a9 100644
--- a/src/drawing_ctx.rs
+++ b/src/drawing_ctx.rs
@@ -752,7 +752,12 @@ impl DrawingCtx {
                             values
                                 .stroke()
                                 .0
-                                .resolve(acquired_nodes, values.stroke_opacity().0, current_color)
+                                .resolve(
+                                    acquired_nodes,
+                                    values.stroke_opacity().0,
+                                    current_color,
+                                    None,
+                                )
                                 .to_user_space(&bbox, &params, values),
                         );
 
@@ -760,7 +765,12 @@ impl DrawingCtx {
                             values
                                 .fill()
                                 .0
-                                .resolve(acquired_nodes, values.fill_opacity().0, current_color)
+                                .resolve(
+                                    acquired_nodes,
+                                    values.fill_opacity().0,
+                                    current_color,
+                                    None,
+                                )
                                 .to_user_space(&bbox, &params, values),
                         );
 
diff --git a/src/layout.rs b/src/layout.rs
index 8d8088bc..189f0e00 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -73,9 +73,15 @@ pub struct Shape {
     pub fill_rule: FillRule,
     pub clip_rule: ClipRule,
     pub shape_rendering: ShapeRendering,
-    pub marker_start: Option<Node>,
-    pub marker_mid: Option<Node>,
-    pub marker_end: Option<Node>,
+    pub marker_start: Marker,
+    pub marker_mid: Marker,
+    pub marker_end: Marker,
+}
+
+pub struct Marker {
+    pub node_ref: Option<Node>,
+    pub context_stroke: PaintSource,
+    pub context_fill: PaintSource,
 }
 
 /// Image in user-space coordinates.
diff --git a/src/marker.rs b/src/marker.rs
index e06ff413..a27dad80 100644
--- a/src/marker.rs
+++ b/src/marker.rs
@@ -14,7 +14,7 @@ use crate::drawing_ctx::DrawingCtx;
 use crate::element::{Draw, ElementResult, SetAttributes};
 use crate::error::*;
 use crate::float_eq_cairo::ApproxEqCairo;
-use crate::layout::{Shape, StackingContext};
+use crate::layout::{self, Shape, StackingContext};
 use crate::length::*;
 use crate::node::{CascadedValues, Node, NodeBorrow, NodeDraw};
 use crate::parsers::{Parse, ParseValue};
@@ -112,8 +112,12 @@ impl Marker {
         line_width: f64,
         clipping: bool,
         marker_type: MarkerType,
+        marker: &layout::Marker,
     ) -> Result<BoundingBox, RenderingError> {
-        let cascaded = CascadedValues::new_from_node(&node);
+        let mut cascaded = CascadedValues::new_from_node(&node);
+        cascaded.context_fill = Some(marker.context_fill.clone());
+        cascaded.context_stroke = Some(marker.context_stroke.clone());
+
         let values = cascaded.get();
 
         let view_params = draw_ctx.get_view_params();
@@ -569,7 +573,7 @@ enum MarkerType {
 fn emit_marker_by_node(
     draw_ctx: &mut DrawingCtx,
     acquired_nodes: &mut AcquiredNodes<'_>,
-    marker_node: &Node,
+    marker: &layout::Marker,
     xpos: f64,
     ypos: f64,
     computed_angle: Angle,
@@ -577,13 +581,13 @@ fn emit_marker_by_node(
     clipping: bool,
     marker_type: MarkerType,
 ) -> Result<BoundingBox, RenderingError> {
-    match acquired_nodes.acquire_ref(marker_node) {
+    match acquired_nodes.acquire_ref(marker.node_ref.as_ref().unwrap()) {
         Ok(acquired) => {
             let node = acquired.get();
 
-            let marker = borrow_element_as!(marker_node, Marker);
+            let marker_elt = borrow_element_as!(node, Marker);
 
-            marker.render(
+            marker_elt.render(
                 &node,
                 acquired_nodes,
                 draw_ctx,
@@ -593,6 +597,7 @@ fn emit_marker_by_node(
                 line_width,
                 clipping,
                 marker_type,
+                marker,
             )
         }
 
@@ -641,7 +646,10 @@ pub fn render_markers_for_shape(
         return Ok(draw_ctx.empty_bbox());
     }
 
-    if shape.marker_start.is_none() && shape.marker_mid.is_none() && shape.marker_end.is_none() {
+    if shape.marker_start.node_ref.is_none()
+        && shape.marker_mid.node_ref.is_none()
+        && shape.marker_end.node_ref.is_none()
+    {
         return Ok(draw_ctx.empty_bbox());
     }
 
@@ -649,13 +657,13 @@ pub fn render_markers_for_shape(
         &shape.path,
         draw_ctx.empty_bbox(),
         &mut |marker_type: MarkerType, x: f64, y: f64, computed_angle: Angle| {
-            let marker_node = match marker_type {
+            let marker = match marker_type {
                 MarkerType::Start => &shape.marker_start,
                 MarkerType::Middle => &shape.marker_mid,
                 MarkerType::End => &shape.marker_end,
             };
 
-            if let Some(ref marker) = *marker_node {
+            if marker.node_ref.is_some() {
                 emit_marker_by_node(
                     draw_ctx,
                     acquired_nodes,
diff --git a/src/node.rs b/src/node.rs
index 0c61778b..c93fd714 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -16,6 +16,7 @@ use crate::document::AcquiredNodes;
 use crate::drawing_ctx::DrawingCtx;
 use crate::element::*;
 use crate::error::*;
+use crate::paint_server::PaintSource;
 use crate::properties::ComputedValues;
 use crate::text::Chars;
 use crate::xml::Attributes;
@@ -100,6 +101,8 @@ impl fmt::Display for NodeData {
 /// `&ComputedValues` whose fields you can access.
 pub struct CascadedValues<'a> {
     inner: CascadedInner<'a>,
+    pub context_stroke: Option<PaintSource>,
+    pub context_fill: Option<PaintSource>,
 }
 
 enum CascadedInner<'a> {
@@ -117,6 +120,8 @@ impl<'a> CascadedValues<'a> {
         match self.inner {
             CascadedInner::FromNode(_) => CascadedValues {
                 inner: CascadedInner::FromNode(node.borrow_element()),
+                context_fill: self.context_fill.clone(),
+                context_stroke: self.context_stroke.clone(),
             },
 
             CascadedInner::FromValues(ref v) => CascadedValues::new_from_values(node, &*v),
@@ -131,6 +136,8 @@ impl<'a> CascadedValues<'a> {
     pub fn new_from_node(node: &Node) -> CascadedValues<'_> {
         CascadedValues {
             inner: CascadedInner::FromNode(node.borrow_element()),
+            context_fill: None,
+            context_stroke: None,
         }
     }
 
@@ -147,6 +154,8 @@ impl<'a> CascadedValues<'a> {
 
         CascadedValues {
             inner: CascadedInner::FromValues(v),
+            context_fill: None,
+            context_stroke: None,
         }
     }
 
@@ -159,6 +168,13 @@ impl<'a> CascadedValues<'a> {
             CascadedInner::FromNode(ref e) => e.get_computed_values(),
             CascadedInner::FromValues(ref v) => &*v,
         }
+
+        // if values.fill == "context-fill" {
+        //     values.fill=self.context_fill
+        // }
+        // if values.stroke == "context-stroke" {
+        //     values.stroke=self.context_stroke
+        // }
     }
 }
 
diff --git a/src/paint_server.rs b/src/paint_server.rs
index 3fe8805a..5ead5e6c 100644
--- a/src/paint_server.rs
+++ b/src/paint_server.rs
@@ -35,12 +35,19 @@ pub enum PaintServer {
 
     /// For example, `fill="blue"`.
     SolidColor(cssparser::Color),
+
+    /// For example, `fill="context-fill"`
+    ContextFill,
+
+    /// For example, `fill="context-stroke"`
+    ContextStroke,
 }
 
 /// Paint server with resolved references, with unnormalized lengths.
 ///
 /// Use [`PaintSource.to_user_space`](#method.to_user_space) to turn this into a
 /// [`UserSpacePaintSource`].
+#[derive(Clone)]
 pub enum PaintSource {
     None,
     Gradient(ResolvedGradient, Option<cssparser::RGBA>),
@@ -65,6 +72,16 @@ impl Parse for PaintServer {
             .is_ok()
         {
             Ok(PaintServer::None)
+        } else if parser
+            .try_parse(|i| i.expect_ident_matching("context-fill"))
+            .is_ok()
+        {
+            Ok(PaintServer::ContextFill)
+        } else if parser
+            .try_parse(|i| i.expect_ident_matching("context-stroke"))
+            .is_ok()
+        {
+            Ok(PaintServer::ContextStroke)
         } else if let Ok(url) = parser.try_parse(|i| i.expect_url()) {
             let loc = parser.current_source_location();
 
@@ -107,6 +124,7 @@ impl PaintServer {
         acquired_nodes: &mut AcquiredNodes<'_>,
         opacity: UnitInterval,
         current_color: cssparser::RGBA,
+        context: Option<PaintSource>,
     ) -> PaintSource {
         match self {
             PaintServer::Iri {
@@ -182,6 +200,22 @@ impl PaintServer {
                 PaintSource::SolidColor(resolve_color(color, opacity, current_color))
             }
 
+            PaintServer::ContextFill => {
+                if let Some(paint) = context {
+                    paint
+                } else {
+                    PaintSource::None
+                }
+            }
+
+            PaintServer::ContextStroke => {
+                if let Some(paint) = context {
+                    paint
+                } else {
+                    PaintSource::None
+                }
+            }
+
             PaintServer::None => PaintSource::None,
         }
     }
@@ -246,6 +280,17 @@ pub fn resolve_color(
     cssparser::RGBA { alpha, ..rgba }
 }
 
+impl std::fmt::Debug for PaintSource {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+        match *self {
+            PaintSource::None => f.write_str("PaintSource::None"),
+            PaintSource::Gradient(_, _) => f.write_str("PaintSource::Gradient"),
+            PaintSource::Pattern(_, _) => f.write_str("PaintSource::Pattern"),
+            PaintSource::SolidColor(_) => f.write_str("PaintSource::SolidColor"),
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/shapes.rs b/src/shapes.rs
index 5ac8a51e..bb6bf302 100644
--- a/src/shapes.rs
+++ b/src/shapes.rs
@@ -12,7 +12,7 @@ use crate::drawing_ctx::DrawingCtx;
 use crate::element::{Draw, ElementResult, SetAttributes};
 use crate::error::*;
 use crate::iri::Iri;
-use crate::layout::{Shape, StackingContext, Stroke};
+use crate::layout::{Marker, Shape, StackingContext, Stroke};
 use crate::length::*;
 use crate::node::{CascadedValues, Node, NodeBorrow};
 use crate::parsers::{optional_comma, Parse, ParseValue};
@@ -50,6 +50,7 @@ macro_rules! impl_draw {
                 cascaded: &CascadedValues<'_>,
                 draw_ctx: &mut DrawingCtx,
                 clipping: bool,
+                //context: &CascadedValues<'_>.inner::FromNode,
             ) -> Result<BoundingBox, RenderingError> {
                 let values = cascaded.get();
                 let view_params = draw_ctx.get_view_params();
@@ -65,32 +66,52 @@ macro_rules! impl_draw {
                     acquired_nodes,
                     values.stroke_opacity().0,
                     values.color().0,
+                    cascaded.context_stroke.clone(),
                 );
 
                 let fill_paint = values.fill().0.resolve(
                     acquired_nodes,
                     values.fill_opacity().0,
                     values.color().0,
+                    cascaded.context_fill.clone(),
                 );
 
                 let fill_rule = values.fill_rule();
                 let clip_rule = values.clip_rule();
                 let shape_rendering = values.shape_rendering();
 
-                let marker_start;
-                let marker_mid;
-                let marker_end;
+                let marker_start_node;
+                let marker_mid_node;
+                let marker_end_node;
 
                 if shape_def.markers == Markers::Yes {
-                    marker_start = acquire_marker(acquired_nodes, &values.marker_start().0);
-                    marker_mid = acquire_marker(acquired_nodes, &values.marker_mid().0);
-                    marker_end = acquire_marker(acquired_nodes, &values.marker_end().0);
+                    marker_start_node = acquire_marker(acquired_nodes, &values.marker_start().0);
+                    marker_mid_node = acquire_marker(acquired_nodes, &values.marker_mid().0);
+                    marker_end_node = acquire_marker(acquired_nodes, &values.marker_end().0);
                 } else {
-                    marker_start = None;
-                    marker_mid = None;
-                    marker_end = None;
+                    marker_start_node = None;
+                    marker_mid_node = None;
+                    marker_end_node = None;
                 }
 
+                let marker_start = Marker {
+                    node_ref: marker_start_node,
+                    context_stroke: stroke_paint.clone(),
+                    context_fill: fill_paint.clone(),
+                };
+
+                let marker_mid = Marker {
+                    node_ref: marker_mid_node,
+                    context_stroke: stroke_paint.clone(),
+                    context_fill: fill_paint.clone(),
+                };
+
+                let marker_end = Marker {
+                    node_ref: marker_end_node,
+                    context_stroke: stroke_paint.clone(),
+                    context_fill: fill_paint.clone(),
+                };
+
                 let shape = Shape {
                     path: shape_def.path,
                     is_visible,
diff --git a/src/text.rs b/src/text.rs
index 83b4daa1..f243587e 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -270,12 +270,14 @@ impl PositionedSpan {
             acquired_nodes,
             self.values.stroke_opacity().0,
             self.values.color().0,
+            None,
         );
 
         let fill_paint = self.values.fill().0.resolve(
             acquired_nodes,
             self.values.fill_opacity().0,
             self.values.color().0,
+            None,
         );
 
         let text_rendering = self.values.text_rendering();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]