[librsvg: 2/6] Use CSS paint-order when performing fill/stroke/marker operations
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 2/6] Use CSS paint-order when performing fill/stroke/marker operations
- Date: Wed, 2 Sep 2020 00:49:38 +0000 (UTC)
commit fbeb998c9f87d21a5f710c1fffbe3ff31be91a1d
Author: John Ledbetter <john ledbetter gmail com>
Date: Wed Aug 26 14:56:40 2020 -0400
Use CSS paint-order when performing fill/stroke/marker operations
The paint-order css property allows specifying in which order
fill, stroke, and marker operations should be performed;
refactor DrawingCtx#draw_path to handle fill/stroke separately
and to perform them in the order specified by the paint-order
property.
rsvg_internals/src/drawing_ctx.rs | 148 ++++++++++++-----------
tests/fixtures/reftests/svg2/paint-order-ref.png | Bin 0 -> 9505 bytes
tests/fixtures/reftests/svg2/paint-order.svg | 6 +
3 files changed, 86 insertions(+), 68 deletions(-)
---
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index 8fbdfc58..e5cbf144 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -28,8 +28,8 @@ use crate::path_builder::*;
use crate::pattern::{PatternContentUnits, PatternUnits, ResolvedPattern};
use crate::properties::ComputedValues;
use crate::property_defs::{
- ClipRule, FillRule, MixBlendMode, Opacity, Overflow, ShapeRendering, StrokeDasharray,
- StrokeLinecap, StrokeLinejoin, TextRendering,
+ ClipRule, FillRule, MixBlendMode, Opacity, Overflow, PaintTarget, ShapeRendering,
+ StrokeDasharray, StrokeLinecap, StrokeLinejoin, TextRendering,
};
use crate::rect::Rect;
use crate::shapes::Markers;
@@ -1160,63 +1160,56 @@ impl DrawingCtx {
}
}
- pub fn stroke_and_fill(
+ pub fn stroke(
&mut self,
cr: &cairo::Context,
acquired_nodes: &mut AcquiredNodes,
values: &ComputedValues,
- ) -> Result<BoundingBox, RenderingError> {
- cr.set_antialias(cairo::Antialias::from(values.shape_rendering()));
+ bbox: &BoundingBox,
+ ) -> Result<(), RenderingError> {
+ let current_color = values.color().0;
- self.setup_cr_for_stroke(cr, values);
+ self.set_source_paint_server(
+ acquired_nodes,
+ &values.stroke().0,
+ values.stroke_opacity().0,
+ bbox,
+ current_color,
+ values,
+ )
+ .map(|had_paint_server| {
+ if had_paint_server {
+ cr.stroke();
+ }
+ })?;
- // Update the bbox in the rendering context. Below, we actually set the
- // fill/stroke patterns on the cairo_t. That process requires the
- // rendering context to have an updated bbox; for example, for the
- // coordinate system in patterns.
- let bbox = compute_stroke_and_fill_box(cr, values);
+ Ok(())
+ }
+ pub fn fill(
+ &mut self,
+ cr: &cairo::Context,
+ acquired_nodes: &mut AcquiredNodes,
+ values: &ComputedValues,
+ bbox: &BoundingBox,
+ ) -> Result<(), RenderingError> {
let current_color = values.color().0;
- let res = self
- .set_source_paint_server(
- acquired_nodes,
- &values.fill().0,
- values.fill_opacity().0,
- &bbox,
- current_color,
- values,
- )
- .map(|had_paint_server| {
- if had_paint_server {
- if values.stroke().0 == PaintServer::None {
- cr.fill();
- } else {
- cr.fill_preserve();
- }
- }
- })
- .and_then(|_| {
- self.set_source_paint_server(
- acquired_nodes,
- &values.stroke().0,
- values.stroke_opacity().0,
- &bbox,
- current_color,
- values,
- )
- .map(|had_paint_server| {
- if had_paint_server {
- cr.stroke();
- }
- })
- });
-
- // clear the path in case stroke == fill == None; otherwise
- // we leave it around from computing the bounding box
- cr.new_path();
+ self.set_source_paint_server(
+ acquired_nodes,
+ &values.fill().0,
+ values.fill_opacity().0,
+ bbox,
+ current_color,
+ values,
+ )
+ .map(|had_paint_server| {
+ if had_paint_server {
+ cr.fill();
+ }
+ })?;
- res.map(|_: ()| bbox)
+ Ok(())
}
pub fn draw_path(
@@ -1228,31 +1221,50 @@ impl DrawingCtx {
markers: Markers,
clipping: bool,
) -> Result<BoundingBox, RenderingError> {
- if !path.is_empty() {
- let bbox =
- self.with_discrete_layer(node, acquired_nodes, values, clipping, &mut |an, dc| {
- let cr = dc.cr.clone();
+ if path.is_empty() {
+ return Ok(self.empty_bbox());
+ }
+
+ self.with_discrete_layer(node, acquired_nodes, values, clipping, &mut |an, dc| {
+ let cr = dc.cr.clone();
+ let is_square_linecap = values.stroke_line_cap() == StrokeLinecap::Square;
- let is_square_linecap = values.stroke_line_cap() == StrokeLinecap::Square;
- path.to_cairo(&cr, is_square_linecap)?;
+ cr.set_antialias(cairo::Antialias::from(values.shape_rendering()));
+ dc.setup_cr_for_stroke(&cr, values);
- if clipping {
- cr.set_fill_rule(cairo::FillRule::from(values.clip_rule()));
- Ok(dc.empty_bbox())
- } else {
- cr.set_fill_rule(cairo::FillRule::from(values.fill_rule()));
- dc.stroke_and_fill(&cr, an, values)
- }
- })?;
+ let bbox = if clipping {
+ cr.set_fill_rule(cairo::FillRule::from(values.clip_rule()));
+ path.to_cairo(&cr, is_square_linecap)?;
+ dc.empty_bbox()
+ } else {
+ cr.set_fill_rule(cairo::FillRule::from(values.fill_rule()));
+ path.to_cairo(&cr, is_square_linecap)?;
+ let bbox = compute_stroke_and_fill_box(&cr, &values);
+ cr.new_path();
+ bbox
+ };
- if markers == Markers::Yes {
- marker::render_markers_for_path(path, self, acquired_nodes, values, clipping)?;
+ for &target in &values.paint_order().targets {
+ match target {
+ PaintTarget::Fill if !clipping => {
+ path.to_cairo(&cr, is_square_linecap)?;
+ dc.fill(&cr, an, values, &bbox)?;
+ cr.new_path();
+ }
+ PaintTarget::Stroke if !clipping => {
+ path.to_cairo(&cr, is_square_linecap)?;
+ dc.stroke(&cr, an, values, &bbox)?;
+ cr.new_path();
+ }
+ PaintTarget::Markers if markers == Markers::Yes => {
+ marker::render_markers_for_path(path, dc, an, values, clipping)?;
+ }
+ _ => {}
+ }
}
Ok(bbox)
- } else {
- Ok(self.empty_bbox())
- }
+ })
}
pub fn draw_image(
diff --git a/tests/fixtures/reftests/svg2/paint-order-ref.png
b/tests/fixtures/reftests/svg2/paint-order-ref.png
new file mode 100644
index 00000000..b8194522
Binary files /dev/null and b/tests/fixtures/reftests/svg2/paint-order-ref.png differ
diff --git a/tests/fixtures/reftests/svg2/paint-order.svg b/tests/fixtures/reftests/svg2/paint-order.svg
new file mode 100644
index 00000000..74193bae
--- /dev/null
+++ b/tests/fixtures/reftests/svg2/paint-order.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="750" height="450">
+<rect height="300" width="1000" fill="#98fb98"/>
+<rect height="300" width="1000" y="300" fill="#87cefa"/>
+<path d="M 200 300 H 1000" stroke="#deb887" stroke-width="37.5"/>
+<path d="M -200 -100 a 100 100 0 0 1 100 -100 h 200 a 100 100 0 0 1 100 100 v 200 a 100 100 0 0 1 -100 100 h
-200 a 100 100 0 0 1 -100 -100 z" stroke="#deb887" stroke-width="125" fill="white" paint-order="stroke fill"
transform="matrix(0.6 0 0 0.6 200 300)"/>
+</svg>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]