<commit_before>extern crate glib;
extern crate cairo;
extern crate libc;

use self::glib::translate::*;

use std::cell::Cell;
use std::ptr;

use aspect_ratio::*;
use drawing_ctx::RsvgDrawingCtx;
use drawing_ctx;
use handle::RsvgHandle;
use length::*;
use node::*;
use property_bag;
use property_bag::*;
use util::*;
use viewbox::*;

use self::cairo::MatrixTrait;


/***** NodeGroup *****/

struct NodeGroup ();

impl NodeGroup {
    fn new () -> NodeGroup {
        NodeGroup ()
    }
}

impl NodeTrait for NodeGroup {
    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, _: *const RsvgPropertyBag) -> NodeResult {
        Ok (())
    }

    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        node.draw_children (draw_ctx, dominate);
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        unreachable! ();
    }
}

/***** NodeDefs *****/

struct NodeDefs ();

impl NodeDefs {
    fn new () -> NodeDefs {
        NodeDefs ()
    }
}

impl NodeTrait for NodeDefs {
    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, _: *const RsvgPropertyBag) -> NodeResult {
        Ok (())
    }

    fn draw (&self, _: &RsvgNode, _: *const RsvgDrawingCtx, _: i32) {
        // nothing
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        unreachable! ();
    }
}

/***** NodeSwitch *****/

struct NodeSwitch ();

impl NodeSwitch {
    fn new () -> NodeSwitch {
        NodeSwitch ()
    }
}

impl NodeTrait for NodeSwitch {
    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, _: *const RsvgPropertyBag) -> NodeResult {
        Ok (())
    }

    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        drawing_ctx::state_reinherit_top (draw_ctx, node.get_state (), dominate);

        drawing_ctx::push_discrete_layer (draw_ctx);

        for child in &*node.children.borrow () {
            if drawing_ctx::state_get_cond_true (child.get_state ()) {
                let boxed_child = box_node (child.clone ());

                drawing_ctx::draw_node_from_stack (draw_ctx, boxed_child, 0);

                rsvg_node_unref (boxed_child);

                break;
            }
        }

        drawing_ctx::pop_discrete_layer (draw_ctx);
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        unreachable! ();
    }
}

/***** NodeSvg *****/

struct NodeSvg {
    preserve_aspect_ratio: Cell<AspectRatio>,
    x:                     Cell<RsvgLength>,
    y:                     Cell<RsvgLength>,
    w:                     Cell<RsvgLength>,
    h:                     Cell<RsvgLength>,
    vbox:                  Cell<RsvgViewBox>,
    atts:                  Cell<*mut RsvgPropertyBag>
}

impl NodeSvg {
    fn new () -> NodeSvg {
        NodeSvg {
            preserve_aspect_ratio: Cell::new (AspectRatio::default ()),
            x:                     Cell::new (RsvgLength::parse ("0", LengthDir::Horizontal).unwrap ()),
            y:                     Cell::new (RsvgLength::parse ("0", LengthDir::Vertical).unwrap ()),
            w:                     Cell::new (RsvgLength::parse ("100%", LengthDir::Horizontal).unwrap ()),
            h:                     Cell::new (RsvgLength::parse ("100%", LengthDir::Vertical).unwrap ()),
            vbox:                  Cell::new (RsvgViewBox::default ()),
            atts:                  Cell::new (ptr::null_mut ())
        }
    }
}

impl NodeTrait for NodeSvg {
    fn set_atts (&self, node: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) -> NodeResult {
        self.preserve_aspect_ratio.set (property_bag::parse_or_default (pbag, "preserveAspectRatio")?);

        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        if node.get_parent ().is_some () {
            self.x.set (property_bag::length_or_default (pbag, "x", LengthDir::Horizontal)?);
            self.y.set (property_bag::length_or_default (pbag, "y", LengthDir::Vertical)?);
        }

        self.w.set (property_bag::length_or_value (pbag, "width", LengthDir::Horizontal, "100%")?);
        self.h.set (property_bag::length_or_value (pbag, "height", LengthDir::Vertical, "100%")?);

        self.vbox.set (property_bag::parse_or_default (pbag, "viewBox")?);

        // The "style" sub-element is not loaded yet here, so we need
        // to store other attributes to be applied later.
        self.atts.set (property_bag::dup (pbag));

        Ok (())
    }

    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        let nx = self.x.get ().normalize (draw_ctx);
        let ny = self.y.get ().normalize (draw_ctx);
        let nw = self.w.get ().normalize (draw_ctx);
        let nh = self.h.get ().normalize (draw_ctx);

        drawing_ctx::state_reinherit_top (draw_ctx, node.get_state (), dominate);

        let state = drawing_ctx::get_current_state (draw_ctx);

        let affine_old = drawing_ctx::get_current_state_affine (draw_ctx);

        let vbox = self.vbox.get ();

        if vbox.active {
            // viewBox width==0 or height==0 disables rendering of the element
            // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
            if double_equals (vbox.rect.width, 0.0) || double_equals (vbox.rect.height, 0.0) {
                return;
            }

            let (x, y, w, h) = self.preserve_aspect_ratio.get ().compute (vbox.rect.width, vbox.rect.height,
                                                                          nx, ny, nw, nh);

            let affine = cairo::Matrix::new (w / vbox.rect.width,
                                             0.0,
                                             0.0,
                                             h / vbox.rect.height,
                                             x - vbox.rect.x * w / vbox.rect.width,
                                             y - vbox.rect.y * h / vbox.rect.height);

            drawing_ctx::set_current_state_affine (draw_ctx, cairo::Matrix::multiply (&affine, &affine_old));

            drawing_ctx::push_view_box (draw_ctx, vbox.rect.width, vbox.rect.height);
        } else {
            let mut affine = affine_old;
            affine.translate (nx, ny);

            drawing_ctx::set_current_state_affine (draw_ctx, affine);
            drawing_ctx::push_view_box (draw_ctx, nw, nh);
        }

        let affine_new = drawing_ctx::get_current_state_affine (draw_ctx);

        drawing_ctx::push_discrete_layer (draw_ctx);

        // Bounding box addition must be AFTER the discrete layer
        // push, which must be AFTER the transformation happens.

        if !drawing_ctx::state_is_overflow (state) && node.get_parent ().is_some () {
            drawing_ctx::set_current_state_affine (draw_ctx, affine_old);
            drawing_ctx::add_clipping_rect (draw_ctx, nx, ny, nw, nh);
            drawing_ctx::set_current_state_affine (draw_ctx, affine_new);
        }

        node.draw_children (draw_ctx, -1); // dominate==-1 so it won't reinherit or push a layer

        drawing_ctx::pop_discrete_layer (draw_ctx);
        drawing_ctx::pop_view_box (draw_ctx);
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {<commit_msg>NodeSvg: Don't inline the computation of the SVG's affine<commit_after>extern crate glib;
extern crate cairo;
extern crate libc;

use self::glib::translate::*;

use std::cell::Cell;
use std::ptr;

use aspect_ratio::*;
use drawing_ctx::RsvgDrawingCtx;
use drawing_ctx;
use handle::RsvgHandle;
use length::*;
use node::*;
use property_bag;
use property_bag::*;
use util::*;
use viewbox::*;

use self::cairo::MatrixTrait;


/***** NodeGroup *****/

struct NodeGroup ();

impl NodeGroup {
    fn new () -> NodeGroup {
        NodeGroup ()
    }
}

impl NodeTrait for NodeGroup {
    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, _: *const RsvgPropertyBag) -> NodeResult {
        Ok (())
    }

    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        node.draw_children (draw_ctx, dominate);
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        unreachable! ();
    }
}

/***** NodeDefs *****/

struct NodeDefs ();

impl NodeDefs {
    fn new () -> NodeDefs {
        NodeDefs ()
    }
}

impl NodeTrait for NodeDefs {
    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, _: *const RsvgPropertyBag) -> NodeResult {
        Ok (())
    }

    fn draw (&self, _: &RsvgNode, _: *const RsvgDrawingCtx, _: i32) {
        // nothing
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        unreachable! ();
    }
}

/***** NodeSwitch *****/

struct NodeSwitch ();

impl NodeSwitch {
    fn new () -> NodeSwitch {
        NodeSwitch ()
    }
}

impl NodeTrait for NodeSwitch {
    fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, _: *const RsvgPropertyBag) -> NodeResult {
        Ok (())
    }

    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        drawing_ctx::state_reinherit_top (draw_ctx, node.get_state (), dominate);

        drawing_ctx::push_discrete_layer (draw_ctx);

        for child in &*node.children.borrow () {
            if drawing_ctx::state_get_cond_true (child.get_state ()) {
                let boxed_child = box_node (child.clone ());

                drawing_ctx::draw_node_from_stack (draw_ctx, boxed_child, 0);

                rsvg_node_unref (boxed_child);

                break;
            }
        }

        drawing_ctx::pop_discrete_layer (draw_ctx);
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        unreachable! ();
    }
}

/***** NodeSvg *****/

struct NodeSvg {
    preserve_aspect_ratio: Cell<AspectRatio>,
    x:                     Cell<RsvgLength>,
    y:                     Cell<RsvgLength>,
    w:                     Cell<RsvgLength>,
    h:                     Cell<RsvgLength>,
    vbox:                  Cell<RsvgViewBox>,
    atts:                  Cell<*mut RsvgPropertyBag>
}

impl NodeSvg {
    fn new () -> NodeSvg {
        NodeSvg {
            preserve_aspect_ratio: Cell::new (AspectRatio::default ()),
            x:                     Cell::new (RsvgLength::parse ("0", LengthDir::Horizontal).unwrap ()),
            y:                     Cell::new (RsvgLength::parse ("0", LengthDir::Vertical).unwrap ()),
            w:                     Cell::new (RsvgLength::parse ("100%", LengthDir::Horizontal).unwrap ()),
            h:                     Cell::new (RsvgLength::parse ("100%", LengthDir::Vertical).unwrap ()),
            vbox:                  Cell::new (RsvgViewBox::default ()),
            atts:                  Cell::new (ptr::null_mut ())
        }
    }
}

impl NodeTrait for NodeSvg {
    fn set_atts (&self, node: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) -> NodeResult {
        self.preserve_aspect_ratio.set (property_bag::parse_or_default (pbag, "preserveAspectRatio")?);

        // x & y attributes have no effect on outermost svg
        // http://www.w3.org/TR/SVG/struct.html#SVGElement
        if node.get_parent ().is_some () {
            self.x.set (property_bag::length_or_default (pbag, "x", LengthDir::Horizontal)?);
            self.y.set (property_bag::length_or_default (pbag, "y", LengthDir::Vertical)?);
        }

        self.w.set (property_bag::length_or_value (pbag, "width", LengthDir::Horizontal, "100%")?);
        self.h.set (property_bag::length_or_value (pbag, "height", LengthDir::Vertical, "100%")?);

        self.vbox.set (property_bag::parse_or_default (pbag, "viewBox")?);

        // The "style" sub-element is not loaded yet here, so we need
        // to store other attributes to be applied later.
        self.atts.set (property_bag::dup (pbag));

        Ok (())
    }

    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        let nx = self.x.get ().normalize (draw_ctx);
        let ny = self.y.get ().normalize (draw_ctx);
        let nw = self.w.get ().normalize (draw_ctx);
        let nh = self.h.get ().normalize (draw_ctx);

        drawing_ctx::state_reinherit_top (draw_ctx, node.get_state (), dominate);

        let state = drawing_ctx::get_current_state (draw_ctx);

        let affine_old = drawing_ctx::get_current_state_affine (draw_ctx);

        let vbox = self.vbox.get ();

        if vbox.active {
            // viewBox width==0 or height==0 disables rendering of the element
            // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
            if double_equals (vbox.rect.width, 0.0) || double_equals (vbox.rect.height, 0.0) {
                return;
            }

            let (x, y, w, h) = self.preserve_aspect_ratio.get ().compute (vbox.rect.width, vbox.rect.height,
                                                                          nx, ny, nw, nh);

            let mut affine = affine_old;
            affine.translate (x, y);
            affine.scale (w / vbox.rect.width, h / vbox.rect.height);
            affine.translate (-vbox.rect.x, -vbox.rect.y);
            drawing_ctx::set_current_state_affine (draw_ctx, affine);

            drawing_ctx::push_view_box (draw_ctx, vbox.rect.width, vbox.rect.height);
        } else {
            let mut affine = affine_old;
            affine.translate (nx, ny);

            drawing_ctx::set_current_state_affine (draw_ctx, affine);
            drawing_ctx::push_view_box (draw_ctx, nw, nh);
        }

        let affine_new = drawing_ctx::get_current_state_affine (draw_ctx);

        drawing_ctx::push_discrete_layer (draw_ctx);

        // Bounding box addition must be AFTER the discrete layer
        // push, which must be AFTER the transformation happens.

        if !drawing_ctx::state_is_overflow (state) && node.get_parent ().is_some () {
            drawing_ctx::set_current_state_affine (draw_ctx, affine_old);
            drawing_ctx::add_clipping_rect (draw_ctx, nx, ny, nw, nh);
            drawing_ctx::set_current_state_affine (draw_ctx, affine_new);
        }

        node.draw_children (draw_ctx, -1); // dominate==-1 so it won't reinherit or push a layer

        drawing_ctx::pop_discrete_layer (draw_ctx);
        drawing_ctx::pop_view_box (draw_ctx);
    }

    fn get_c_impl (&self) -> *const RsvgCNodeImpl {
{'fraction_non_alphanumeric': 0.13260672116257946, 'fraction_numerical': 0.00489065884161252, 'mean_word_length': 2.210856886496187, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 41, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5964553', 'n_tokens_mistral': 4717, 'n_tokens_neox': 4524, 'n_words': 994}