<commit_before>/* vim: set sw=4 sts=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* 
   rsvg-paint-server.c: Implement the SVG paint server abstraction.
 
   Copyright (C) 2000 Eazel, Inc.
  
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
  
   You should have received a copy of the GNU Library General Public
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
  
   Author: <NAME> <<EMAIL>>
*/

#include "config.h"
#include "rsvg-private.h"
#include "rsvg-defs.h"
#include "rsvg-paint-server.h"
#include "rsvg-styles.h"
#include "rsvg-image.h"

#include <glib.h>
#include <string.h>
#include <math.h>

#include "rsvg-css.h"

static RsvgPaintServer *
rsvg_paint_server_solid (guint32 rgb)
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_SOLID;
    result->core.colour = g_new (RsvgSolidColour, 1);
    result->core.colour->rgb = rgb;
    result->core.colour->currentcolour = FALSE;

    return result;
}

static RsvgPaintServer *
rsvg_paint_server_solid_current_colour ()
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_SOLID;
    result->core.colour = g_new (RsvgSolidColour, 1);
    result->core.colour->currentcolour = TRUE;

    return result;
}

static RsvgPaintServer *
rsvg_paint_server_lin_grad (RsvgLinearGradient * gradient)
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_LIN_GRAD;
    result->core.lingrad = gradient;

    return result;
}

static RsvgPaintServer *
rsvg_paint_server_rad_grad (RsvgRadialGradient * gradient)
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_RAD_GRAD;
    result->core.radgrad = gradient;

    return result;
}

static RsvgPaintServer *
rsvg_paint_server_pattern (RsvgPattern * pattern)
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_PATTERN;
    rsvg_pattern_fix_fallback (pattern);
    result->core.pattern = pattern;

    return result;
}

/**
 * rsvg_paint_server_parse: Parse an SVG paint specification.
 * @defs: Defs for looking up gradients.
 * @str: The SVG paint specification string to parse.
 *
 * Parses the paint specification @str, creating a new paint server
 * object.
 *
 * Return value: The newly created paint server, or NULL on error.
 **/
RsvgPaintServer *
rsvg_paint_server_parse (gboolean * inherit, const RsvgDefs * defs, const char *str,
                         guint32 current_color)
{
    char *name;
    guint32 rgb;
    if (inherit != NULL)
        *inherit = 1;
    if (!strcmp (str, "none"))
        return NULL;

    name = rsvg_get_url_string (str);
    if (name) {
        RsvgNode *val;
        val = rsvg_defs_lookup (defs, name);
        g_free (name);

        if (val == NULL)
            return NULL;
        if (!strcmp (val->type->str, "linearGradient"))
            return rsvg_paint_server_lin_grad ((RsvgLinearGradient *) val);
        else if (!strcmp (val->type->str, "radialGradient"))
            return rsvg_paint_server_rad_grad ((RsvgRadialGradient *) val);
        else if (!strcmp (val->type->str, "pattern"))
            return rsvg_paint_server_pattern ((RsvgPattern *) val);
        else
            return NULL;
    } else if (!strcmp (str, "inherit")) {
        if (inherit != NULL)
            *inherit = 0;
        return rsvg_paint_server_solid (0);
    } else if (!strcmp (str, "currentColor")) {
        RsvgPaintServer *ps;
        ps = rsvg_paint_server_solid_current_colour ();
        return ps;
    } else {
        rgb = rsvg_css_parse_color (str, inherit);
        return rsvg_paint_server_solid (rgb);
    }
}

/**
 * rsvg_paint_server_ref: Reference a paint server object.
 * @ps: The paint server object to reference.
 **/
void
rsvg_paint_server_ref (RsvgPaintServer * ps)
{
    if (ps == NULL)
        return;
    ps->refcnt++;
}

/**
 * rsvg_paint_server_unref: Unreference a paint server object.
 * @ps: The paint server object to unreference.
 **/
void
rsvg_paint_server_unref (RsvgPaintServer * ps)
{
    if (ps == NULL)
        return;
    if (--ps->refcnt == 0) {
        if (ps->type == RSVG_PAINT_SERVER_SOLID)
            g_free (ps->core.colour);
        g_free (ps);
    }
}

static void
rsvg_stop_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    double offset = 0;
    gboolean is_current_color = FALSE;
    const char *value;
    RsvgGradientStop *stop;
    RsvgState state;

    stop = (RsvgGradientStop *) self;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "offset"))) {
            /* either a number [0,1] or a percentage */
            RsvgLength length = _rsvg_css_parse_length (value);
            offset = _rsvg_css_hand_normalize_length (&length, rsvg_dpi_percentage (ctx), 1., 0.);

            if (offset < 0.)
                offset = 0.;
            else if (offset > 1.)
                offset = 1.;
            stop->offset = offset;
        }
        if ((value = rsvg_property_bag_lookup (atts, "style")))
            rsvg_parse_style (ctx, self->state, value);

        if ((value = rsvg_property_bag_lookup (atts, "stop-color")))
            if (!strcmp (value, "currentColor"))
                is_current_color = TRUE;

        rsvg_parse_style_pairs (ctx, self->state, atts);
    }
    self->parent = ctx->priv->currentnode;
    rsvg_state_init (&state);
    rsvg_state_reconstruct (&state, self);
    if (is_current_color)
        state.stop_color = state.current_color;
    stop->rgba = (state.stop_color << 8) | state.stop_opacity;
    rsvg_state_finalize (&state);
}

RsvgNode *
rsvg_new_stop (void)
{
    RsvgGradientStop *stop = g_new (RsvgGradientStop, 1);
    _rsvg_node_init (&stop->super);
    stop->super.set_atts = rsvg_stop_set_atts;
    stop->offset = 0;
    stop->rgba = 0;
    return &stop->super;
}

static void
rsvg_linear_gradient_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    RsvgLinearGradient *grad = (RsvgLinearGradient *) self;
    const char *value;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "id")))
            rsvg_defs_register_name (ctx->priv->defs, value, self);
        if ((value = rsvg_property_bag_lookup (atts, "x1"))) {
            grad->x1 = _rsvg_css_parse_length (value);
            grad->hasx1 = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "y1"))) {
            grad->y1 = _rsvg_css_parse_length (value);
            grad->hasy1 = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "x2"))) {
            grad->x2 = _rsvg_css_parse_length (value);
            grad->hasx2 = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "y2"))) {
            grad->y2 = _rsvg_css_parse_length (value);
            grad->hasy2 = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "spreadMethod"))) {
            if (!strcmp (value, "pad")) {
                grad->spread = RSVG_GRADIENT_PAD;
            } else if (!strcmp (value, "reflect")) {
                grad->spread = RSVG_GRADIENT_REFLECT;
            } else if (!strcmp (value, "repeat")) {
                grad->spread = RSVG_GRADIENT_REPEAT;
            }
            grad->hasspread = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "xlink:href")))
            rsvg_defs_add_resolver (ctx->priv->defs, &grad->fallback, value);
        if ((value = rsvg_property_bag_lookup (atts, "gradientTransform"))) {
            rsvg_parse_transform (grad->affine, value);
            grad->hastransform = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "color")))
            grad->current_color = rsvg_css_parse_color (value, 0);
        if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                grad->obj_bbox = FALSE;
            else if (!strcmp (value, "objectBoundingBox"))
                grad->obj_bbox = TRUE;
            grad->hasbbox = TRUE;
        }
        rsvg_parse_style_attrs (ctx, self->state, "linearGradient", NULL, NULL, atts);
    }
}


RsvgNode *
rsvg_new_linear_gradient (void)
{
    RsvgLinearGradient *grad = NULL;
    grad = g_new (RsvgLinearGradient, 1);
    _rsvg_node_init (&grad->super);
    _rsvg_affine_identity (grad->affine);
    grad->has_current_color = FALSE;
    grad->x1 = grad->y1 = grad->y2 = _rsvg_css_parse_length ("0");
    grad->x2 = _rsvg_css_parse_length ("1");
    grad->fallback = NULL;
    grad->obj_bbox = TRUE;
    grad->spread = RSVG_GRADIENT_PAD;
    grad->super.set_atts = rsvg_linear_gradient_set_atts;
    grad->hasx1 = grad->hasy1 = grad->hasx2 = grad->hasy2 = grad->hasbbox = grad->hasspread =
        grad->hastransform = FALSE;
    return &grad->super;
}

static void
rsvg_radial_gradient_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    RsvgRadialGradient *grad = (RsvgRadialGradient *) self;
    const char *value;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "id")))
            rsvg_defs_register_name (ctx->priv->defs, value, self);
        if ((value = rsvg_property_bag_lookup (atts, "cx"))) {
            grad->cx = _rsvg_css_parse_length (value);
            grad->hascx = TRUE;
            if (!grad->hasfx)
                grad->fx = grad->cx;
        }
        if ((value = rsvg_property_bag_lookup (atts, "cy"))) {
            grad->cy = _rsvg_css_parse_length (value);
            grad->hascy = TRUE;
            if (!grad->hasfy)
                grad->fy = grad->cy;
        }
        if ((value = rsvg_property_bag_lookup (atts, "r"))) {
            grad->r = _rsvg_css_parse_length (value);
            grad->hasr = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "fx"))) {
            grad->fx = _rsvg_css_parse_length (value);
            grad->hasfx = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "fy"))) {
            grad->fy = _rsvg_css_parse_length (value);
            grad->hasfy = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "xlink:href")))
            rsvg_defs_add_resolver (ctx->priv->defs, &grad->fallback, value);
        if ((value = rsvg_property_bag_lookup (atts, "gradientTransform"))) {
            rsvg_parse_transform (grad->affine, value);
            grad->hastransform = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "color"))) {
            grad->current_color = rsvg_css_parse_color (value, 0);
        }
        if ((value = rsvg_property_bag_lookup (atts, "spreadMethod"))) {
            if (!strcmp (value, "pad"))
                grad->spread = RSVG_GRADIENT_PAD;
            else if (!strcmp (value, "reflect"))
                grad->spread = RSVG_GRADIENT_REFLECT;
            else if (!strcmp (value, "repeat"))
                grad->spread = RSVG_GRADIENT_REPEAT;
            grad->hasspread = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                grad->obj_bbox = FALSE;
            else if (!strcmp (value, "objectBoundingBox"))
                grad->obj_bbox = TRUE;
            grad->hasbbox = TRUE;
        }
        rsvg_parse_style_attrs (ctx, self->state, "radialGradient", NULL, NULL, atts);
    }
}

RsvgNode *
rsvg_new_radial_gradient (void)
{

    RsvgRadialGradient *grad = g_new (RsvgRadialGradient, 1);
    _rsvg_node_init (&grad->super);
    _rsvg_affine_identity (grad->affine);
    grad->has_current_color = FALSE;
    grad->obj_bbox = TRUE;
    grad->spread = RSVG_GRADIENT_PAD;
    grad->fallback = NULL;
    grad->cx = grad->cy = grad->r = grad->fx = grad->fy = _rsvg_css_parse_length ("0.5");
    grad->super.set_atts = rsvg_radial_gradient_set_atts;
    grad->hascx = grad->hascy = grad->hasfx = grad->hasfy = grad->hasr = grad->hasbbox =
        grad->hasspread = grad->hastransform = FALSE;
    return &grad->super;
}

static void
rsvg_pattern_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    RsvgPattern *pattern = (RsvgPattern *) self;
    const char *value;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "id")))
            rsvg_defs_register_name (ctx->priv->defs, value, self);
        if ((value = rsvg_property_bag_lookup (atts, "viewBox"))) {
            pattern->vbox = rsvg_css_parse_vbox (value);
            pattern->hasvbox = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "x"))) {
            pattern->x = _rsvg_css_parse_length (value);
            pattern->hasx = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "y"))) {
            pattern->y = _rsvg_css_parse_length (value);
            pattern->hasy = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "width"))) {
            pattern->width = _rsvg_css_parse_length (value);
            pattern->haswidth = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "height"))) {
            pattern->height = _rsvg_css_parse_length (value);
            pattern->hasheight = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "xlink:href"))) {
            /* The (void *) cast is to avoid a GCC warning like:
             * "warning: dereferencing type-punned pointer will break strict-aliasing rules"
             * which is wrong for this code. (void *) introduces a compatible
             * intermediate type in the cast list. */
            rsvg_defs_add_resolver (ctx->priv->defs, (RsvgNode **) (void *) &pattern->fallback,
                                    value);
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternTransform"))) {
            rsvg_parse_transform (pattern->affine, value);
            pattern->hastransform = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                pattern->obj_bbox = FALSE;
            else if (!strcmp (value, "objectBoundingBox"))
                pattern->obj_bbox = TRUE;
            pattern->hasbbox = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternContentUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                pattern->obj_cbbox = FALSE;<commit_msg>Fix infinite loop caused by self-reference.<commit_after>/* vim: set sw=4 sts=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* 
   rsvg-paint-server.c: Implement the SVG paint server abstraction.
 
   Copyright (C) 2000 Eazel, Inc.
  
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
  
   You should have received a copy of the GNU Library General Public
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
  
   Author: <NAME> <<EMAIL>>
*/

#include "config.h"
#include "rsvg-private.h"
#include "rsvg-defs.h"
#include "rsvg-paint-server.h"
#include "rsvg-styles.h"
#include "rsvg-image.h"

#include <glib.h>
#include <string.h>
#include <math.h>

#include "rsvg-css.h"

static RsvgPaintServer *
rsvg_paint_server_solid (guint32 rgb)
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_SOLID;
    result->core.colour = g_new (RsvgSolidColour, 1);
    result->core.colour->rgb = rgb;
    result->core.colour->currentcolour = FALSE;

    return result;
}

static RsvgPaintServer *
rsvg_paint_server_solid_current_colour ()
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_SOLID;
    result->core.colour = g_new (RsvgSolidColour, 1);
    result->core.colour->currentcolour = TRUE;

    return result;
}

static RsvgPaintServer *
rsvg_paint_server_lin_grad (RsvgLinearGradient * gradient)
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_LIN_GRAD;
    result->core.lingrad = gradient;

    return result;
}

static RsvgPaintServer *
rsvg_paint_server_rad_grad (RsvgRadialGradient * gradient)
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_RAD_GRAD;
    result->core.radgrad = gradient;

    return result;
}

static RsvgPaintServer *
rsvg_paint_server_pattern (RsvgPattern * pattern)
{
    RsvgPaintServer *result = g_new (RsvgPaintServer, 1);

    result->refcnt = 1;
    result->type = RSVG_PAINT_SERVER_PATTERN;
    rsvg_pattern_fix_fallback (pattern);
    result->core.pattern = pattern;

    return result;
}

/**
 * rsvg_paint_server_parse: Parse an SVG paint specification.
 * @defs: Defs for looking up gradients.
 * @str: The SVG paint specification string to parse.
 *
 * Parses the paint specification @str, creating a new paint server
 * object.
 *
 * Return value: The newly created paint server, or NULL on error.
 **/
RsvgPaintServer *
rsvg_paint_server_parse (gboolean * inherit, const RsvgDefs * defs, const char *str,
                         guint32 current_color)
{
    char *name;
    guint32 rgb;
    if (inherit != NULL)
        *inherit = 1;
    if (!strcmp (str, "none"))
        return NULL;

    name = rsvg_get_url_string (str);
    if (name) {
        RsvgNode *val;
        val = rsvg_defs_lookup (defs, name);
        g_free (name);

        if (val == NULL)
            return NULL;
        if (!strcmp (val->type->str, "linearGradient"))
            return rsvg_paint_server_lin_grad ((RsvgLinearGradient *) val);
        else if (!strcmp (val->type->str, "radialGradient"))
            return rsvg_paint_server_rad_grad ((RsvgRadialGradient *) val);
        else if (!strcmp (val->type->str, "pattern"))
            return rsvg_paint_server_pattern ((RsvgPattern *) val);
        else
            return NULL;
    } else if (!strcmp (str, "inherit")) {
        if (inherit != NULL)
            *inherit = 0;
        return rsvg_paint_server_solid (0);
    } else if (!strcmp (str, "currentColor")) {
        RsvgPaintServer *ps;
        ps = rsvg_paint_server_solid_current_colour ();
        return ps;
    } else {
        rgb = rsvg_css_parse_color (str, inherit);
        return rsvg_paint_server_solid (rgb);
    }
}

/**
 * rsvg_paint_server_ref: Reference a paint server object.
 * @ps: The paint server object to reference.
 **/
void
rsvg_paint_server_ref (RsvgPaintServer * ps)
{
    if (ps == NULL)
        return;
    ps->refcnt++;
}

/**
 * rsvg_paint_server_unref: Unreference a paint server object.
 * @ps: The paint server object to unreference.
 **/
void
rsvg_paint_server_unref (RsvgPaintServer * ps)
{
    if (ps == NULL)
        return;
    if (--ps->refcnt == 0) {
        if (ps->type == RSVG_PAINT_SERVER_SOLID)
            g_free (ps->core.colour);
        g_free (ps);
    }
}

static void
rsvg_stop_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    double offset = 0;
    gboolean is_current_color = FALSE;
    const char *value;
    RsvgGradientStop *stop;
    RsvgState state;

    stop = (RsvgGradientStop *) self;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "offset"))) {
            /* either a number [0,1] or a percentage */
            RsvgLength length = _rsvg_css_parse_length (value);
            offset = _rsvg_css_hand_normalize_length (&length, rsvg_dpi_percentage (ctx), 1., 0.);

            if (offset < 0.)
                offset = 0.;
            else if (offset > 1.)
                offset = 1.;
            stop->offset = offset;
        }
        if ((value = rsvg_property_bag_lookup (atts, "style")))
            rsvg_parse_style (ctx, self->state, value);

        if ((value = rsvg_property_bag_lookup (atts, "stop-color")))
            if (!strcmp (value, "currentColor"))
                is_current_color = TRUE;

        rsvg_parse_style_pairs (ctx, self->state, atts);
    }
    self->parent = ctx->priv->currentnode;
    rsvg_state_init (&state);
    rsvg_state_reconstruct (&state, self);
    if (is_current_color)
        state.stop_color = state.current_color;
    stop->rgba = (state.stop_color << 8) | state.stop_opacity;
    rsvg_state_finalize (&state);
}

RsvgNode *
rsvg_new_stop (void)
{
    RsvgGradientStop *stop = g_new (RsvgGradientStop, 1);
    _rsvg_node_init (&stop->super);
    stop->super.set_atts = rsvg_stop_set_atts;
    stop->offset = 0;
    stop->rgba = 0;
    return &stop->super;
}

static void
rsvg_linear_gradient_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    RsvgLinearGradient *grad = (RsvgLinearGradient *) self;
    const char *value;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "id")))
            rsvg_defs_register_name (ctx->priv->defs, value, self);
        if ((value = rsvg_property_bag_lookup (atts, "x1"))) {
            grad->x1 = _rsvg_css_parse_length (value);
            grad->hasx1 = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "y1"))) {
            grad->y1 = _rsvg_css_parse_length (value);
            grad->hasy1 = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "x2"))) {
            grad->x2 = _rsvg_css_parse_length (value);
            grad->hasx2 = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "y2"))) {
            grad->y2 = _rsvg_css_parse_length (value);
            grad->hasy2 = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "spreadMethod"))) {
            if (!strcmp (value, "pad")) {
                grad->spread = RSVG_GRADIENT_PAD;
            } else if (!strcmp (value, "reflect")) {
                grad->spread = RSVG_GRADIENT_REFLECT;
            } else if (!strcmp (value, "repeat")) {
                grad->spread = RSVG_GRADIENT_REPEAT;
            }
            grad->hasspread = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "xlink:href"))) {
            if (self != rsvg_defs_lookup (ctx->priv->defs, value))
                rsvg_defs_add_resolver (ctx->priv->defs, &grad->fallback, value);
	}
        if ((value = rsvg_property_bag_lookup (atts, "gradientTransform"))) {
            rsvg_parse_transform (grad->affine, value);
            grad->hastransform = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "color")))
            grad->current_color = rsvg_css_parse_color (value, 0);
        if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                grad->obj_bbox = FALSE;
            else if (!strcmp (value, "objectBoundingBox"))
                grad->obj_bbox = TRUE;
            grad->hasbbox = TRUE;
        }
        rsvg_parse_style_attrs (ctx, self->state, "linearGradient", NULL, NULL, atts);
    }
}


RsvgNode *
rsvg_new_linear_gradient (void)
{
    RsvgLinearGradient *grad = NULL;
    grad = g_new (RsvgLinearGradient, 1);
    _rsvg_node_init (&grad->super);
    _rsvg_affine_identity (grad->affine);
    grad->has_current_color = FALSE;
    grad->x1 = grad->y1 = grad->y2 = _rsvg_css_parse_length ("0");
    grad->x2 = _rsvg_css_parse_length ("1");
    grad->fallback = NULL;
    grad->obj_bbox = TRUE;
    grad->spread = RSVG_GRADIENT_PAD;
    grad->super.set_atts = rsvg_linear_gradient_set_atts;
    grad->hasx1 = grad->hasy1 = grad->hasx2 = grad->hasy2 = grad->hasbbox = grad->hasspread =
        grad->hastransform = FALSE;
    return &grad->super;
}

static void
rsvg_radial_gradient_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    RsvgRadialGradient *grad = (RsvgRadialGradient *) self;
    const char *value;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "id")))
            rsvg_defs_register_name (ctx->priv->defs, value, self);
        if ((value = rsvg_property_bag_lookup (atts, "cx"))) {
            grad->cx = _rsvg_css_parse_length (value);
            grad->hascx = TRUE;
            if (!grad->hasfx)
                grad->fx = grad->cx;
        }
        if ((value = rsvg_property_bag_lookup (atts, "cy"))) {
            grad->cy = _rsvg_css_parse_length (value);
            grad->hascy = TRUE;
            if (!grad->hasfy)
                grad->fy = grad->cy;
        }
        if ((value = rsvg_property_bag_lookup (atts, "r"))) {
            grad->r = _rsvg_css_parse_length (value);
            grad->hasr = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "fx"))) {
            grad->fx = _rsvg_css_parse_length (value);
            grad->hasfx = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "fy"))) {
            grad->fy = _rsvg_css_parse_length (value);
            grad->hasfy = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "xlink:href"))) {
            if (self != rsvg_defs_lookup (ctx->priv->defs, value))
                rsvg_defs_add_resolver (ctx->priv->defs, &grad->fallback, value);
        }
        if ((value = rsvg_property_bag_lookup (atts, "gradientTransform"))) {
            rsvg_parse_transform (grad->affine, value);
            grad->hastransform = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "color"))) {
            grad->current_color = rsvg_css_parse_color (value, 0);
        }
        if ((value = rsvg_property_bag_lookup (atts, "spreadMethod"))) {
            if (!strcmp (value, "pad"))
                grad->spread = RSVG_GRADIENT_PAD;
            else if (!strcmp (value, "reflect"))
                grad->spread = RSVG_GRADIENT_REFLECT;
            else if (!strcmp (value, "repeat"))
                grad->spread = RSVG_GRADIENT_REPEAT;
            grad->hasspread = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                grad->obj_bbox = FALSE;
            else if (!strcmp (value, "objectBoundingBox"))
                grad->obj_bbox = TRUE;
            grad->hasbbox = TRUE;
        }
        rsvg_parse_style_attrs (ctx, self->state, "radialGradient", NULL, NULL, atts);
    }
}

RsvgNode *
rsvg_new_radial_gradient (void)
{

    RsvgRadialGradient *grad = g_new (RsvgRadialGradient, 1);
    _rsvg_node_init (&grad->super);
    _rsvg_affine_identity (grad->affine);
    grad->has_current_color = FALSE;
    grad->obj_bbox = TRUE;
    grad->spread = RSVG_GRADIENT_PAD;
    grad->fallback = NULL;
    grad->cx = grad->cy = grad->r = grad->fx = grad->fy = _rsvg_css_parse_length ("0.5");
    grad->super.set_atts = rsvg_radial_gradient_set_atts;
    grad->hascx = grad->hascy = grad->hasfx = grad->hasfy = grad->hasr = grad->hasbbox =
        grad->hasspread = grad->hastransform = FALSE;
    return &grad->super;
}

static void
rsvg_pattern_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
    RsvgPattern *pattern = (RsvgPattern *) self;
    const char *value;

    if (rsvg_property_bag_size (atts)) {
        if ((value = rsvg_property_bag_lookup (atts, "id")))
            rsvg_defs_register_name (ctx->priv->defs, value, self);
        if ((value = rsvg_property_bag_lookup (atts, "viewBox"))) {
            pattern->vbox = rsvg_css_parse_vbox (value);
            pattern->hasvbox = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "x"))) {
            pattern->x = _rsvg_css_parse_length (value);
            pattern->hasx = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "y"))) {
            pattern->y = _rsvg_css_parse_length (value);
            pattern->hasy = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "width"))) {
            pattern->width = _rsvg_css_parse_length (value);
            pattern->haswidth = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "height"))) {
            pattern->height = _rsvg_css_parse_length (value);
            pattern->hasheight = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "xlink:href"))) {
            if (self != rsvg_defs_lookup (ctx->priv->defs, value)) {
                /* The (void *) cast is to avoid a GCC warning like:
                 * "warning: dereferencing type-punned pointer will break strict-aliasing rules"
                 * which is wrong for this code. (void *) introduces a compatible
                 * intermediate type in the cast list. */
                rsvg_defs_add_resolver (ctx->priv->defs, (RsvgNode **) (void *) &pattern->fallback,
                                        value);
            }
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternTransform"))) {
            rsvg_parse_transform (pattern->affine, value);
            pattern->hastransform = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                pattern->obj_bbox = FALSE;
            else if (!strcmp (value, "objectBoundingBox"))
                pattern->obj_bbox = TRUE;
            pattern->hasbbox = TRUE;
        }
        if ((value = rsvg_property_bag_lookup (atts, "patternContentUnits"))) {
            if (!strcmp (value, "userSpaceOnUse"))
                pattern->obj_cbbox = FALSE;
{'fraction_non_alphanumeric': 0.12214611872146118, 'fraction_numerical': 0.005609915198956295, 'mean_word_length': 2.5157665405343423, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 343, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '725176', 'n_tokens_mistral': 10348, 'n_tokens_neox': 9953, 'n_words': 2323}