Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gtksvgnumber.c

  Sprache: C
 

/*
 * 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 "gtksvgvalueprivate.h"
#include "gtksvgnumberprivate.h"
#include "gtksvgutilsprivate.h"
#include "gtksvgstringutilsprivate.h"
#include "gtksvgenumprivate.h"
#include "gtksvgprivate.h"
#include "gtksvgelementtypeprivate.h"
#include "gtksvgelementinternal.h"

typedef struct
{
  SvgValue base;
  SvgUnit unit;
  double value;
} SvgNumber;

static gboolean
svg_number_equal (const SvgValue *value0,
                  const SvgValue *value1)
{
  const SvgNumber *n0 = (const SvgNumber *) value0;
  const SvgNumber *n1 = (const SvgNumber *) value1;

  return n0->unit == n1->unit && n0->value == n1->value;
}

static SvgValue *
svg_number_interpolate (const SvgValue    *value0,
                        const SvgValue    *value1,
                        SvgComputeContext *context,
                        double             t)
{
  const SvgNumber *n0 = (const SvgNumber *) value0;
  const SvgNumber *n1 = (const SvgNumber *) value1;

  if (n0->unit != n1->unit)
    return NULL;

  return svg_number_new_full (n0->unit, lerp (t, n0->value, n1->value));
}

static SvgValue *
svg_number_accumulate (const SvgValue    *value0,
                       const SvgValue    *value1,
                       SvgComputeContext *context,
                       int                n)
{
  const SvgNumber *n0 = (const SvgNumber *) value0;
  const SvgNumber *n1 = (const SvgNumber *) value1;

  if (n0->unit != n1->unit)
    return NULL;

  return svg_number_new_full (n0->unit, accumulate (n0->value, n1->value, n));
}

static void
svg_number_print (const SvgValue *value,
                  GString        *string)
{
  const SvgNumber *n = (const SvgNumber *) value;
  string_append_double (string, "", n->value);
  g_string_append (string, svg_unit_name (n->unit));
}

static double
svg_number_distance (const SvgValue *value0,
                     const SvgValue *value1)
{
  const SvgNumber *n0 = (const SvgNumber *) value0;
  const SvgNumber *n1 = (const SvgNumber *) value1;

  if (n0->unit != n1->unit)
    return 1;

  return fabs (n0->value - n1->value);
}

gboolean
is_absolute_length (SvgUnit unit)
{
  switch ((unsigned int) unit)
    {
    case SVG_UNIT_PX:
    case SVG_UNIT_PT:
    case SVG_UNIT_IN:
    case SVG_UNIT_CM:
    case SVG_UNIT_MM:
      return TRUE;
    default:
      return FALSE;
    }
}

double
absolute_length_to_px (double  value,
                       SvgUnit unit)
{
  switch ((unsigned int) unit)
    {
    case SVG_UNIT_PX: return value;
    case SVG_UNIT_PT: return value * 96 / 72;
    case SVG_UNIT_IN: return value * 96;
    case SVG_UNIT_CM: return value * 96 / 2.54;
    case SVG_UNIT_MM: return value * 96 / 25.4;
    default: g_assert_not_reached ();
    }
}

double
angle_to_deg (double  value,
              SvgUnit unit)
{
  switch ((unsigned int) unit)
    {
    case SVG_UNIT_DEG: return value;
    case SVG_UNIT_RAD: return value * 180.0 / M_PI;
    case SVG_UNIT_GRAD: return value * 360.0 / 400.0;
    case SVG_UNIT_TURN: return value * 360.0;
    default: g_assert_not_reached ();
    }
}

double
viewport_relative_to_px (double                 value,
                         SvgUnit                unit,
                         const graphene_rect_t *viewport)
{
  switch ((unsigned int) unit)
    {
    case SVG_UNIT_VW: return value * viewport->size.width / 100;
    case SVG_UNIT_VH: return value * viewport->size.height / 100;
    case SVG_UNIT_VMIN: return value * MIN (viewport->size.width,
                                            viewport->size.height) / 100;
    case SVG_UNIT_VMAX: return value * MAX (viewport->size.width,
                                            viewport->size.height) / 100;
    default: g_assert_not_reached ();
    }
}

double
shape_get_current_font_size (SvgElement        *shape,
                             SvgProperty        attr,
                             SvgComputeContext *context)
{
  /* FIXME: units */
  if (attr != SVG_PROPERTY_FONT_SIZE)
    return ((SvgNumber *) svg_element_get_current_value (shape, SVG_PROPERTY_FONT_SIZE))->value;
  else if (context->parent)
    return ((SvgNumber *) svg_element_get_current_value (context->parent, SVG_PROPERTY_FONT_SIZE))->value;
  else
    return DEFAULT_FONT_SIZE;
}

static SvgValue *
svg_number_resolve (const SvgValue    *value,
                    SvgProperty        attr,
                    unsigned int       idx,
                    SvgElement        *shape,
                    SvgComputeContext *context)
{
  const SvgNumber *n = (const SvgNumber *) value;
  SvgElementType type = svg_element_get_type (shape);

  switch (n->unit)
    {
    case SVG_UNIT_NUMBER:
    case SVG_UNIT_PX:
      switch ((unsigned int) attr)
        {
        case SVG_PROPERTY_OPACITY:
        case SVG_PROPERTY_FILL_OPACITY:
        case SVG_PROPERTY_STROKE_OPACITY:
        case SVG_PROPERTY_STOP_OFFSET:
          return svg_number_new (CLAMP (n->value, 01));
        default:
          return svg_value_ref ((SvgValue *) value);
        }
      break;
    case SVG_UNIT_PERCENTAGE:
      switch ((unsigned int) attr)
        {
        case SVG_PROPERTY_FONT_SIZE:
          {
            double parent_size;

            if (context->parent)
              parent_size = ((SvgNumber *) context->parent->current[SVG_PROPERTY_FONT_SIZE])->value;
            else
              parent_size = DEFAULT_FONT_SIZE;

            return svg_number_new (n->value * parent_size / 100);
          }
          break;
        case SVG_PROPERTY_OPACITY:
        case SVG_PROPERTY_FILL_OPACITY:
        case SVG_PROPERTY_STROKE_OPACITY:
        case SVG_PROPERTY_STOP_OFFSET:
          return svg_number_new (CLAMP (n->value / 10001));
        case SVG_PROPERTY_FILTER:
          return svg_number_new (n->value / 100);
        case SVG_PROPERTY_STROKE_WIDTH:
        case SVG_PROPERTY_R:
          if (type != SVG_ELEMENT_RADIAL_GRADIENT)
            return svg_number_new_full (SVG_UNIT_PX, n->value * normalized_diagonal (context->viewport) / 100);
          else
            return svg_value_ref ((SvgValue *) value);
        case SVG_PROPERTY_CX:
        case SVG_PROPERTY_RX:
          if (type != SVG_ELEMENT_RADIAL_GRADIENT)
            return svg_number_new_full (SVG_UNIT_PX, n->value * context->viewport->size.width / 100);
          else
            return svg_value_ref ((SvgValue *) value);
        case SVG_PROPERTY_CY:
        case SVG_PROPERTY_RY:
          if (type != SVG_ELEMENT_RADIAL_GRADIENT)
            return svg_number_new_full (SVG_UNIT_PX, n->value * context->viewport->size.height / 100);
          else
            return svg_value_ref ((SvgValue *) value);
        case SVG_PROPERTY_Y:
        case SVG_PROPERTY_HEIGHT:
          if (type != SVG_ELEMENT_FILTER &&
              type != SVG_ELEMENT_PATTERN &&
              (type != SVG_ELEMENT_MASK ||
               svg_enum_get (svg_element_get_current_value (shape, SVG_PROPERTY_BOUND_UNITS)) != COORD_UNITS_OBJECT_BOUNDING_BOX))
            return svg_number_new_full (SVG_UNIT_PX, n->value * context->viewport->size.height / 100);
          else
            return svg_value_ref ((SvgValue *) value);
        case SVG_PROPERTY_X:
        case SVG_PROPERTY_WIDTH:
          if (type != SVG_ELEMENT_FILTER &&
              type != SVG_ELEMENT_PATTERN &&
              (type != SVG_ELEMENT_MASK ||
               svg_enum_get (svg_element_get_current_value (shape, SVG_PROPERTY_BOUND_UNITS)) != COORD_UNITS_OBJECT_BOUNDING_BOX))
            return svg_number_new_full (SVG_UNIT_PX, n->value * context->viewport->size.width / 100);
          else
            return svg_value_ref ((SvgValue *) value);
        case SVG_PROPERTY_X1:
        case SVG_PROPERTY_X2:
          if (type == SVG_ELEMENT_LINE)
            return svg_number_new_full (SVG_UNIT_PX, n->value * context->viewport->size.width / 100);
          else
            return svg_value_ref ((SvgValue *) value);
        case SVG_PROPERTY_Y1:
        case SVG_PROPERTY_Y2:
          if (type == SVG_ELEMENT_LINE)
            return svg_number_new_full (SVG_UNIT_PX, n->value * context->viewport->size.height / 100);
          else
            return svg_value_ref ((SvgValue *) value);
        default:
          return svg_value_ref ((SvgValue *) value);
        }
      break;
    case SVG_UNIT_PT:
    case SVG_UNIT_IN:
    case SVG_UNIT_CM:
    case SVG_UNIT_MM:
      return svg_number_new_full (SVG_UNIT_PX, absolute_length_to_px (n->value, n->unit));

    case SVG_UNIT_VW:
    case SVG_UNIT_VH:
    case SVG_UNIT_VMIN:
    case SVG_UNIT_VMAX:
      return svg_number_new_full (SVG_UNIT_PX, viewport_relative_to_px (n->value,
                                                                        n->unit,
                                                                        context->viewport));

    case SVG_UNIT_EM:
      return svg_number_new_full (SVG_UNIT_PX, n->value * shape_get_current_font_size (shape, attr, context));

    case SVG_UNIT_EX:
      return svg_number_new_full (SVG_UNIT_PX, n->value * 0.5 * shape_get_current_font_size (shape, attr, context));

    case SVG_UNIT_RAD:
    case SVG_UNIT_DEG:
    case SVG_UNIT_GRAD:
    case SVG_UNIT_TURN:
      return svg_number_new_full (SVG_UNIT_DEG, angle_to_deg (n->value, n->unit));

    case SVG_UNIT_S:
    case SVG_UNIT_MS:
    default:
      g_assert_not_reached ();
    }
}

static const SvgValueClass SVG_NUMBER_CLASS = {
  "SvgNumber",
  svg_value_default_free,
  svg_number_equal,
  svg_number_interpolate,
  svg_number_accumulate,
  svg_number_print,
  svg_number_distance,
  svg_number_resolve,
};

SvgValue *
svg_number_new (double value)
{
  static SvgNumber singletons[] = {
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_NUMBER, .value = 0 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_NUMBER, .value = 1 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_NUMBER, .value = 2 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_NUMBER, .value = 4 }, /* default miter limit */
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_NUMBER, .value = DEFAULT_FONT_SIZE },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_NUMBER, .value = PANGO_WEIGHT_NORMAL },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_NUMBER, .value = -1 }, /* unset path length */
  };
  SvgValue *result;

  for (unsigned int i = 0; i < G_N_ELEMENTS (singletons); i++)
    {
      if (value == singletons[i].value)
        return (SvgValue *) &singletons[i];
    }

  result = svg_value_alloc (&SVG_NUMBER_CLASS, sizeof (SvgNumber));
  ((SvgNumber *) result)->unit = SVG_UNIT_NUMBER;
  ((SvgNumber *) result)->value = value;

  return result;
}

SvgValue *
svg_percentage_new (double value)
{
  static SvgNumber singletons[] = {
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_PERCENTAGE, .value = -10 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_PERCENTAGE, .value = 0 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_PERCENTAGE, .value = 25 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_PERCENTAGE, .value = 50 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_PERCENTAGE, .value = 100 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_PERCENTAGE, .value = 120 },
    { { &SVG_NUMBER_CLASS, 0 }, .unit = SVG_UNIT_PERCENTAGE, .value = 150 },
  };
  SvgValue *result;

  for (unsigned int i = 0; i < G_N_ELEMENTS (singletons); i++)
    {
      if (value == singletons[i].value)
        return (SvgValue *) &singletons[i];
    }

  result = svg_value_alloc (&SVG_NUMBER_CLASS, sizeof (SvgNumber));
  ((SvgNumber *) result)->unit = SVG_UNIT_PERCENTAGE;
  ((SvgNumber *) result)->value = value;

  return result;
}

SvgValue *
svg_number_new_full (SvgUnit unit,
                     double  value)
{
  if (unit == SVG_UNIT_NUMBER)
    {
      return svg_number_new (value);
    }
  else if (unit == SVG_UNIT_PERCENTAGE)
    {
      return svg_percentage_new (value);
    }
  else
    {
      SvgNumber *result;

      result = (SvgNumber *) svg_value_alloc (&SVG_NUMBER_CLASS, sizeof (SvgNumber));
      result->value = value;
      result->unit = unit;

      return (SvgValue *) result;
    }
}

gboolean
svg_number_parse2 (GtkCssParser        *parser,
                   double               min,
                   double               max,
                   SvgNumberParseFlags  flags,
                   double              *d,
                   SvgUnit             *u)
{
  const GtkCssToken *token;
  double number;
  SvgUnit unit;

  token = gtk_css_parser_get_token (parser);

  if (gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE))
    {
      if ((flags & SVG_PARSE_PERCENTAGE) == 0)
        {
          gtk_css_parser_error_value (parser, "Percentages are not allowed here");
          return FALSE;
        }

      number = token->number.number;
      unit = SVG_UNIT_PERCENTAGE;
    }
  else if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) ||
           gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER) ||
           gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_NUMBER) ||
           gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_NUMBER))
    {
      number = token->number.number;

      if (number == 0)
        {
          if (flags & SVG_PARSE_NUMBER)
            unit = SVG_UNIT_NUMBER;
          else if (flags & SVG_PARSE_LENGTH)
            unit = SVG_UNIT_PX;
          else if (flags & SVG_PARSE_TIME)
            unit = SVG_UNIT_S;
          else if (flags & SVG_PARSE_ANGLE)
            unit = SVG_UNIT_DEG;
          else
            unit = SVG_UNIT_PERCENTAGE;
        }
      else if (flags & SVG_PARSE_NUMBER)
        {
          unit = SVG_UNIT_NUMBER;
        }
      else
        {
          gtk_css_parser_error_syntax (parser, "Unit is missing");
          return FALSE;
        }
    }
  else if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION) ||
           gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION) ||
           gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_DIMENSION) ||
           gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_DIMENSION))
    {
      unsigned int i;

      number = token->dimension.value;

      for (i = 0; i < SVG_UNIT_TURN; i++)
        {
          if (g_ascii_strcasecmp (token->dimension.dimension, svg_unit_name (i)) == 0)
            break;
        }

      if (svg_unit_dimension (i) == SVG_DIMENSION_LENGTH)
        {
          if (flags & SVG_PARSE_LENGTH)
            unit = i;
          else
            {
              gtk_css_parser_error_value (parser, "Lengths are not allowed here");
              return FALSE;
            }
        }
      else if (svg_unit_dimension (i) == SVG_DIMENSION_TIME)
        {
          if (flags & SVG_PARSE_TIME)
            unit = i;
          else
            {
              gtk_css_parser_error_value (parser, "Times are not allowed here");
              return FALSE;
            }
        }
      else if (svg_unit_dimension (i) == SVG_DIMENSION_ANGLE)
        {
          if (flags & SVG_PARSE_ANGLE)
            unit = i;
          else
            {
              gtk_css_parser_error_value (parser, "Angles are not allowed here");
              return FALSE;
            }
        }
      else
        {
          gtk_css_parser_error_syntax (parser, "'%s' is not a valid unit", token->dimension.dimension);
          return FALSE;
        }
    }
  else
    {
      gtk_css_parser_error_syntax (parser, "Expected a number");
      return FALSE;
    }

  if (number < min || number > max)
    {
      gtk_css_parser_error_value (parser, "Out of range");
      return FALSE;
    }

  *d = number;
  *u = unit;

  gtk_css_parser_consume_token (parser);
  return TRUE;
}

SvgValue *
svg_number_parse (GtkCssParser        *parser,
                  double               min,
                  double               max,
                  SvgNumberParseFlags  flags)
{
  double d;
  SvgUnit unit;

  if (svg_number_parse2 (parser, min, max, flags, &d, &unit))
    return svg_number_new_full (unit, d);
  else
    return NULL;
}

double
svg_number_get (const SvgValue *value,
                double          one_hundred_percent)
{
  const SvgNumber *n = (const SvgNumber *) value;

  g_assert (value->class == &SVG_NUMBER_CLASS);

  if (n->unit == SVG_UNIT_PERCENTAGE)
    return n->value / 100 * one_hundred_percent;
  else
    return n->value;
}

SvgUnit
svg_number_get_unit (const SvgValue *value)
{
  const SvgNumber *n = (const SvgNumber *) value;

  g_assert (value->class == &SVG_NUMBER_CLASS);

  return n->unit;
}

gboolean
svg_value_is_number (const SvgValue *value)
{
  return value->class == &SVG_NUMBER_CLASS;
}

gboolean
svg_value_is_positive_number (const SvgValue *value)
{
  const SvgNumber *n = (const SvgNumber *) value;

  return svg_value_is_number (value) && n->value >= 0;
}

Messung V0.5 in Prozent
C=99 H=98 G=98

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik