/*
* Copyright © 2025 Red Hat , Inc
*
* SPDX - License - Identifier : LGPL - 2 . 1 - or - later
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2 . 1 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see < http : //www.gnu.org/licenses/>.
*
* Authors : Matthias Clasen < mclasen @ redhat . com >
*/
#include "config.h"
#include "gtksvgdasharrayprivate.h"
#include "gtksvgutilsprivate.h"
#include "gtksvgstringutilsprivate.h"
#include "gtksvgnumberprivate.h"
#include "gtksvgelementinternal.h"
typedef struct
{
double value;
SvgUnit unit;
} Dash;
typedef struct
{
SvgValue base;
DashArrayKind kind;
unsigned int n_dashes;
Dash dashes[2 ];
} SvgDashArray;
static size_t
svg_dash_array_size (size_t n)
{
return sizeof (SvgDashArray) + (n > 1 ? n - 2 : 0 ) * sizeof (Dash);
}
static gboolean
svg_dash_array_equal (const SvgValue *value0,
const SvgValue *value1)
{
const SvgDashArray *da0 = (const SvgDashArray *) value0;
const SvgDashArray *da1 = (const SvgDashArray *) value1;
if (da0->kind != da1->kind)
return FALSE ;
if (da0->kind == DASH_ARRAY_NONE)
return TRUE ;
if (da0->n_dashes != da1->n_dashes)
return FALSE ;
for (unsigned int i = 0 ; i < da0->n_dashes; i++)
{
if (da0->dashes[i].unit != da1->dashes[i].unit)
return FALSE ;
if (da0->dashes[i].value != da1->dashes[i].value)
return FALSE ;
}
return TRUE ;
}
static SvgValue * svg_dash_array_interpolate (const SvgValue *value0,
const SvgValue *value1,
SvgComputeContext *context,
double t);
static void svg_dash_array_print (const SvgValue *value,
GString *s);
static SvgValue * svg_dash_array_accumulate (const SvgValue *value0,
const SvgValue *value1,
SvgComputeContext *context,
int n);
static SvgValue * svg_dash_array_resolve (const SvgValue *value,
SvgProperty attr,
unsigned int idx,
SvgElement *shape,
SvgComputeContext *context);
static const SvgValueClass SVG_DASH_ARRAY_CLASS = {
"SvgDashArray" ,
svg_value_default_free,
svg_dash_array_equal,
svg_dash_array_interpolate,
svg_dash_array_accumulate,
svg_dash_array_print,
svg_value_default_distance,
svg_dash_array_resolve,
};
static SvgDashArray *
svg_dash_array_alloc (unsigned int n)
{
SvgDashArray *a;
a = (SvgDashArray *) svg_value_alloc (&SVG_DASH_ARRAY_CLASS, svg_dash_array_size (n));
a->n_dashes = n;
return a;
}
SvgValue *
svg_dash_array_new_none (void )
{
static SvgDashArray none = { { &SVG_DASH_ARRAY_CLASS, 0 }, DASH_ARRAY_NONE, 0 };
return (SvgValue *) &none;
}
SvgValue *
svg_dash_array_new (double *values,
unsigned int n)
{
static SvgDashArray da01 = { { &SVG_DASH_ARRAY_CLASS, 0 }, DASH_ARRAY_DASHES, 2 , { { .unit = SVG_UNIT_NUMBER, .value = 0 }, { .unit = SVG_UNIT_NUMBER, .value = 1 } } };
static SvgDashArray da10 = { { &SVG_DASH_ARRAY_CLASS, 0 }, DASH_ARRAY_DASHES, 2 , { { .unit = SVG_UNIT_NUMBER, .value = 1 }, { .unit = SVG_UNIT_NUMBER, .value = 0 } } };
if (n == 2 && values[0 ] == 0 && values[1 ] == 1 )
{
return (SvgValue *) &da01;
}
else if (n == 2 && values[0 ] == 1 && values[1 ] == 0 )
{
return (SvgValue *) &da10;
}
else
{
SvgDashArray *a = svg_dash_array_alloc (n);
a->kind = DASH_ARRAY_DASHES;
for (unsigned int i = 0 ; i < n; i++)
{
a->dashes[i].unit = SVG_UNIT_NUMBER;
a->dashes[i].value = values[i];
}
return (SvgValue *) a;
}
}
SvgValue *
svg_dash_array_parse (GtkCssParser *parser)
{
if (gtk_css_parser_try_ident (parser, "none" ))
{
return svg_dash_array_new_none ();
}
else
{
GArray *array;
SvgDashArray *dashes;
array = g_array_new (FALSE , FALSE , sizeof (Dash));
while (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
{
Dash n;
gtk_css_parser_skip_whitespace (parser);
if (!svg_number_parse2 (parser, -DBL_MAX, DBL_MAX, SVG_PARSE_NUMBER|SVG_PARSE_PERCENTAGE|SVG_PARSE_LENGTH,
&n.value, &n.unit))
{
g_array_unref (array);
return NULL;
}
gtk_css_parser_skip_whitespace (parser);
if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_COMMA))
gtk_css_parser_skip (parser);
g_array_append_val (array, n);
}
dashes = svg_dash_array_alloc (array->len);
dashes->kind = DASH_ARRAY_DASHES;
for (unsigned int i = 0 ; i < array->len; i++)
{
Dash *n = &g_array_index (array, Dash, i);
dashes->dashes[i].unit = n->unit;
dashes->dashes[i].value = n->value;
}
g_array_unref (array);
return (SvgValue *) dashes;
}
}
static void
svg_dash_array_print (const SvgValue *value,
GString *s)
{
const SvgDashArray *dashes = (const SvgDashArray *) value;
if (dashes->kind == DASH_ARRAY_NONE)
{
g_string_append (s, "none" );
}
else
{
for (unsigned int i = 0 ; i < dashes->n_dashes; i++)
{
if (i > 0 )
g_string_append_c (s, ' ' );
string_append_double (s, "" , dashes->dashes[i].value);
g_string_append (s, svg_unit_name (dashes->dashes[i].unit));
}
}
}
static SvgValue *
svg_dash_array_interpolate (const SvgValue *value0,
const SvgValue *value1,
SvgComputeContext *context,
double t)
{
const SvgDashArray *a0 = (const SvgDashArray *) value0;
const SvgDashArray *a1 = (const SvgDashArray *) value1;
SvgDashArray *a = NULL;
unsigned int n_dashes;
if (a0->kind != a1->kind)
goto out;
if (a0->kind == DASH_ARRAY_NONE)
return (SvgValue *) svg_dash_array_new_none ();
n_dashes = lcm (a0->n_dashes, a1->n_dashes);
a = svg_dash_array_alloc (n_dashes);
a->kind = a0->kind;
for (unsigned int i = 0 ; i < n_dashes; i++)
{
if (a0->dashes[i % a0->n_dashes].unit != a1->dashes[i %a1->n_dashes].unit)
{
g_clear_pointer ((SvgValue **)&a, svg_value_unref);
break ;
}
a->dashes[i].unit = a0->dashes[i % a0->n_dashes].unit;
a->dashes[i].value = lerp (t, a0->dashes[i % a0->n_dashes].value,
a1->dashes[i % a1->n_dashes].value);
}
out:
if (a)
return (SvgValue *) a;
if (t < 0 .5 )
return svg_value_ref ((SvgValue *) value0);
else
return svg_value_ref ((SvgValue *) value1);
}
static SvgValue *
svg_dash_array_accumulate (const SvgValue *value0,
const SvgValue *value1,
SvgComputeContext *context,
int n)
{
return NULL;
}
static SvgValue *
svg_dash_array_resolve (const SvgValue *value,
SvgProperty attr,
unsigned int idx,
SvgElement *shape,
SvgComputeContext *context)
{
SvgDashArray *orig = (SvgDashArray *) value;
SvgDashArray *a;
double size;
g_assert (value->class == &SVG_DASH_ARRAY_CLASS);
if (orig->kind == DASH_ARRAY_NONE)
return svg_value_ref ((SvgValue *) orig);
a = svg_dash_array_alloc (orig->n_dashes);
a->kind = orig->kind;
size = normalized_diagonal (context->viewport);
for (unsigned int i = 0 ; i < orig->n_dashes; i++)
{
a->dashes[i].unit = SVG_UNIT_NUMBER;
switch ((unsigned int ) orig->dashes[i].unit)
{
case SVG_UNIT_NUMBER:
case SVG_UNIT_PX:
a->dashes[i].value = orig->dashes[i].value;
break ;
case SVG_UNIT_PERCENTAGE:
a->dashes[i].value = orig->dashes[i].value / 100 * size;
break ;
case SVG_UNIT_PT:
case SVG_UNIT_IN:
case SVG_UNIT_CM:
case SVG_UNIT_MM:
a->dashes[i].value = absolute_length_to_px (orig->dashes[i].value, orig->dashes[i].unit);
break ;
case SVG_UNIT_VW:
case SVG_UNIT_VH:
case SVG_UNIT_VMIN:
case SVG_UNIT_VMAX:
a->dashes[i].value = viewport_relative_to_px (orig->dashes[i].value, orig->dashes[i].unit, context->viewport);
break ;
case SVG_UNIT_EM:
a->dashes[i].value = orig->dashes[i].value * shape_get_current_font_size (shape, attr, context);
break ;
case SVG_UNIT_EX:
a->dashes[i].value = orig->dashes[i].value * 0 .5 * shape_get_current_font_size (shape, attr, context);
break ;
default :
g_assert_not_reached ();
}
}
return (SvgValue *) a;
}
DashArrayKind
svg_dash_array_get_kind (const SvgValue *value)
{
const SvgDashArray *da = (const SvgDashArray *) value;
g_assert (value->class == &SVG_DASH_ARRAY_CLASS);
return da->kind;
}
SvgUnit
svg_dash_array_get_unit (const SvgValue *value,
unsigned int pos)
{
const SvgDashArray *da = (const SvgDashArray *) value;
g_assert (value->class == &SVG_DASH_ARRAY_CLASS);
g_assert (pos < da->n_dashes);
return da->dashes[pos].unit;
}
double
svg_dash_array_get (const SvgValue *value,
unsigned int pos,
double one_hundred_percent)
{
const SvgDashArray *da = (const SvgDashArray *) value;
g_assert (value->class == &SVG_DASH_ARRAY_CLASS);
g_assert (pos < da->n_dashes);
if (da->dashes[pos].unit == SVG_UNIT_PERCENTAGE)
return da->dashes[pos].value * one_hundred_percent / 100 ;
else
return da->dashes[pos].value;
}
unsigned int
svg_dash_array_get_length (const SvgValue *value)
{
const SvgDashArray *da = (const SvgDashArray *) value;
g_assert (value->class == &SVG_DASH_ARRAY_CLASS);
return da->n_dashes;
}
Messung V0.5 in Prozent C=98 H=95 G=96
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-07-02)
¤
*© Formatika GbR, Deutschland