From 45f8c8dbe21259325c7ef511adaf440c7eb8701f Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 22 Mar 2023 19:10:16 -0600 Subject: roadmap: better explain the purpose of the render tree, hopefully Part-of: --- devel-docs/render_tree.rst | 51 ++++++++++++++++++++++++++++++++++++++++++++++ devel-docs/roadmap.rst | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/devel-docs/render_tree.rst b/devel-docs/render_tree.rst index 01e40e44..1dee8710 100644 --- a/devel-docs/render_tree.rst +++ b/devel-docs/render_tree.rst @@ -1,6 +1,57 @@ Render tree =========== +For historical reasons, librsvg's code flow during rendering is as +follows. The rendering code traverses the SVG tree of elements, and +for each one, its ``::draw()`` method is called; its signature looks +like this (some arguments omitted): + +.. code-block:: rust + + pub fn draw( + &self, + ... + draw_ctx: &mut DrawingCtx, + ) -> Result { ... } + +The draw() methods perform the actual rendering as side effects on the +``draw_ctx``, and return a ``BoundingBox``. That is, the bounding box of +an element is computed at the same time that it is rendered. This is +suboptimal for several reasons: + +- Many things that happen during rendering depend on knowing the + bounding box. For example, gradients, patterns, and filters with + units set to ``objectBoundingBox`` need to know the bounds. The + rendering code in drawing_ctx.rs is cluttered because it must + resolve bounding boxes very late. + +- This is especially problematic for filters, since a Cairo surface + needs to be created *before* rendering, and that surface should have + a size relative to the bounding box of the element being filtered! + `Bug #1 `_ is + precisely about this: librsvg instead creates a temporary surface as + big as the document's toplevel viewport and filters it, but this + doesn't work well for filters like Gaussian blur that should + actually reference pixels outside of the document's area (think of a + shape that extends past the document's area, which then gets + blurred). + +- The way for an element to signal that it is not drawable + (e.g. ```` is by returning an empty bounding box and not + rendering anything. This is awkward. + +- When rendering to a temporary surface for filtering or masking, + there is a set of affine transformations that needs to be maintained + carefully: an affine for the clipping path outside the temporary + surface, an affine for drawing inside the surface, an affine to + composite the surface into the final result. This is hard to + understand and hard to test. + +These problems can be solved by having a **render tree**. + +What is a render tree? +---------------------- + As of 2022/Oct/06, librsvg does not compute a render tree data structure prior to rendering. Instead, in a very 2000s fashion, it walks the tree of elements and calls a ``.draw()`` method for each diff --git a/devel-docs/roadmap.rst b/devel-docs/roadmap.rst index 6e3f8007..bbbd22e4 100644 --- a/devel-docs/roadmap.rst +++ b/devel-docs/roadmap.rst @@ -17,7 +17,7 @@ Short term offsetting for layers with opacity. Solving this should make it easier to fix the root cause of `issue #1 `_, where librsvg cannot compute arbitrary regions for filter effects and it only takes the user-specified - viewport into account. + viewport into account. See :doc:`render_tree` for details on this. - Continue with the revamp of :doc:`text_layout`. -- cgit v1.2.1