Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  gtkcsstransformvalue.c

  Sprache: C
 

/* GTK - The GIMP Toolkit
 * Copyright (C) 2011 Red Hat, Inc.
 *
 * 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 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/>.
 */


#include "config.h"

#include "gtkcsstransformvalueprivate.h"

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

#include "gtkcssnumbervalueprivate.h"
#include "gsktransform.h"

typedef union _GtkCssTransform GtkCssTransform;

typedef enum {
  GTK_CSS_TRANSFORM_NONE,
  GTK_CSS_TRANSFORM_MATRIX,
  GTK_CSS_TRANSFORM_TRANSLATE,
  GTK_CSS_TRANSFORM_ROTATE,
  GTK_CSS_TRANSFORM_SCALE,
  GTK_CSS_TRANSFORM_SKEW,
  GTK_CSS_TRANSFORM_SKEW_X,
  GTK_CSS_TRANSFORM_SKEW_Y,
  GTK_CSS_TRANSFORM_PERSPECTIVE
} GtkCssTransformType;

union _GtkCssTransform {
  GtkCssTransformType type;
  struct {
    GtkCssTransformType type;
    graphene_matrix_t   matrix;
  }                   matrix;
  struct {
    GtkCssTransformType type;
    GtkCssValue        *x;
    GtkCssValue        *y;
    GtkCssValue        *z;
  }                   translate, scale;
  struct {
    GtkCssTransformType type;
    GtkCssValue        *x;
    GtkCssValue        *y;
  }                   skew;
  struct {
    GtkCssTransformType type;
    GtkCssValue        *x;
    GtkCssValue        *y;
    GtkCssValue        *z;
    GtkCssValue        *angle;
  }                   rotate;
  struct {
    GtkCssTransformType type;
    GtkCssValue        *skew;
  }                   skew_x, skew_y;
  struct {
    GtkCssTransformType type;
    GtkCssValue        *depth;
  }                   perspective;
};

struct _GtkCssValue {
  GTK_CSS_VALUE_BASE
  guint             n_transforms;
  GtkCssTransform   transforms[1];
};

static GtkCssValue *    gtk_css_transform_value_alloc           (guint                  n_values);
static gboolean         gtk_css_transform_value_is_none         (const GtkCssValue     *value);

static void
gtk_css_transform_clear (GtkCssTransform *transform)
{
  switch (transform->type)
    {
    case GTK_CSS_TRANSFORM_MATRIX:
      break;
    case GTK_CSS_TRANSFORM_TRANSLATE:
      gtk_css_value_unref (transform->translate.x);
      gtk_css_value_unref (transform->translate.y);
      gtk_css_value_unref (transform->translate.z);
      break;
    case GTK_CSS_TRANSFORM_ROTATE:
      gtk_css_value_unref (transform->rotate.x);
      gtk_css_value_unref (transform->rotate.y);
      gtk_css_value_unref (transform->rotate.z);
      gtk_css_value_unref (transform->rotate.angle);
      break;
    case GTK_CSS_TRANSFORM_SCALE:
      gtk_css_value_unref (transform->scale.x);
      gtk_css_value_unref (transform->scale.y);
      gtk_css_value_unref (transform->scale.z);
      break;
    case GTK_CSS_TRANSFORM_SKEW:
      gtk_css_value_unref (transform->skew.x);
      gtk_css_value_unref (transform->skew.y);
      break;
    case GTK_CSS_TRANSFORM_SKEW_X:
      gtk_css_value_unref (transform->skew_x.skew);
      break;
    case GTK_CSS_TRANSFORM_SKEW_Y:
      gtk_css_value_unref (transform->skew_y.skew);
      break;
    case GTK_CSS_TRANSFORM_PERSPECTIVE:
      gtk_css_value_unref (transform->perspective.depth);
      break;
    case GTK_CSS_TRANSFORM_NONE:
    default:
      g_assert_not_reached ();
      break;
    }
}

static gboolean
gtk_css_transform_init_identity (GtkCssTransform     *transform,
                                 GtkCssTransformType  type)
{
  switch (type)
    {
    case GTK_CSS_TRANSFORM_MATRIX:
      graphene_matrix_init_identity (&transform->matrix.matrix);
      break;
    case GTK_CSS_TRANSFORM_TRANSLATE:
      transform->translate.x = gtk_css_number_value_new (0, GTK_CSS_PX);
      transform->translate.y = gtk_css_number_value_new (0, GTK_CSS_PX);
      transform->translate.z = gtk_css_number_value_new (0, GTK_CSS_PX);
      break;
    case GTK_CSS_TRANSFORM_ROTATE:
      transform->rotate.x = gtk_css_number_value_new (0, GTK_CSS_NUMBER);
      transform->rotate.y = gtk_css_number_value_new (0, GTK_CSS_NUMBER);
      transform->rotate.z = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
      transform->rotate.angle = gtk_css_number_value_new (0, GTK_CSS_DEG);
      break;
    case GTK_CSS_TRANSFORM_SCALE:
      transform->scale.x = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
      transform->scale.y = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
      transform->scale.z = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
      break;
    case GTK_CSS_TRANSFORM_SKEW:
      transform->skew.x = gtk_css_number_value_new (0, GTK_CSS_DEG);
      transform->skew.y = gtk_css_number_value_new (0, GTK_CSS_DEG);
      break;
    case GTK_CSS_TRANSFORM_SKEW_X:
      transform->skew_x.skew = gtk_css_number_value_new (0, GTK_CSS_DEG);
      break;
    case GTK_CSS_TRANSFORM_SKEW_Y:
      transform->skew_y.skew = gtk_css_number_value_new (0, GTK_CSS_DEG);
      break;
    case GTK_CSS_TRANSFORM_PERSPECTIVE:
      return FALSE;

    case GTK_CSS_TRANSFORM_NONE:
    default:
      g_assert_not_reached ();
      return FALSE;
    }

  transform->type = type;

  return TRUE;
}

static GskTransform *
gtk_css_transform_apply (const GtkCssTransform   *transform,
                         GskTransform            *next)
{
  graphene_matrix_t skew;

  switch (transform->type)
    {
    case GTK_CSS_TRANSFORM_MATRIX:
      return gsk_transform_matrix (next, &transform->matrix.matrix);

    case GTK_CSS_TRANSFORM_TRANSLATE:
      return gsk_transform_translate_3d (next,
                                         &GRAPHENE_POINT3D_INIT (
                                             gtk_css_number_value_get (transform->translate.x, 100),
                                             gtk_css_number_value_get (transform->translate.y, 100),
                                             gtk_css_number_value_get (transform->translate.z, 100)
                                         ));

    case GTK_CSS_TRANSFORM_ROTATE:
      {
        graphene_vec3_t axis;

        graphene_vec3_init (&axis,
                            gtk_css_number_value_get (transform->rotate.x, 1),
                            gtk_css_number_value_get (transform->rotate.y, 1),
                            gtk_css_number_value_get (transform->rotate.z, 1));
        return gsk_transform_rotate_3d (next,
                                        gtk_css_number_value_get (transform->rotate.angle, 100),
                                        &axis);
      }

    case GTK_CSS_TRANSFORM_SCALE:
      return gsk_transform_scale_3d (next,
                                     gtk_css_number_value_get (transform->scale.x, 1),
                                     gtk_css_number_value_get (transform->scale.y, 1),
                                     gtk_css_number_value_get (transform->scale.z, 1));

    case GTK_CSS_TRANSFORM_SKEW:
      graphene_matrix_init_skew (&skew,
                                 gtk_css_number_value_get (transform->skew.x, 100) / 180.0f * G_PI,
                                 gtk_css_number_value_get (transform->skew.y, 100) / 180.0f * G_PI);
      return gsk_transform_matrix (next, &skew);

    case GTK_CSS_TRANSFORM_SKEW_X:
      graphene_matrix_init_skew (&skew,
                                 gtk_css_number_value_get (transform->skew_x.skew, 100) / 180.0f * G_PI,
                                 0);
      return gsk_transform_matrix (next, &skew);

    case GTK_CSS_TRANSFORM_SKEW_Y:
      graphene_matrix_init_skew (&skew,
                                 0,
                                 gtk_css_number_value_get (transform->skew_y.skew, 100) / 180.0f * G_PI);
      return gsk_transform_matrix (next, &skew);

    case GTK_CSS_TRANSFORM_PERSPECTIVE:
      return gsk_transform_perspective (next,
                                        gtk_css_number_value_get (transform->perspective.depth, 100));

    case GTK_CSS_TRANSFORM_NONE:
    default:
      g_assert_not_reached ();
      break;
    }

  return NULL;
}

/* NB: The returned matrix may be invalid */
static GskTransform *
gtk_css_transform_value_compute_transform (const GtkCssValue *value)
{
  GskTransform *transform;
  guint i;

  transform = NULL;

  for (i = 0; i < value->n_transforms; i++)
    {
      transform = gtk_css_transform_apply (&value->transforms[i], transform);
    }

  return transform;
}

static void
gtk_css_value_transform_free (GtkCssValue *value)
{
  guint i;

  for (i = 0; i < value->n_transforms; i++)
    gtk_css_transform_clear (&value->transforms[i]);

  g_free (value);
}

/* returns TRUE if dest == src */
static gboolean
gtk_css_transform_compute (GtkCssTransform      *dest,
                           GtkCssTransform      *src,
                           guint                 property_id,
                           GtkCssComputeContext *context)
{
  dest->type = src->type;

  switch (src->type)
    {
    case GTK_CSS_TRANSFORM_MATRIX:
      memcpy (dest, src, sizeof (GtkCssTransform));
      return TRUE;
    case GTK_CSS_TRANSFORM_TRANSLATE:
      dest->translate.x = gtk_css_value_compute (src->translate.x, property_id, context);
      dest->translate.y = gtk_css_value_compute (src->translate.y, property_id, context);
      dest->translate.z = gtk_css_value_compute (src->translate.z, property_id, context);
      return dest->translate.x == src->translate.x
          && dest->translate.y == src->translate.y
          && dest->translate.z == src->translate.z;
    case GTK_CSS_TRANSFORM_ROTATE:
      dest->rotate.x = gtk_css_value_compute (src->rotate.x, property_id, context);
      dest->rotate.y = gtk_css_value_compute (src->rotate.y, property_id, context);
      dest->rotate.z = gtk_css_value_compute (src->rotate.z, property_id, context);
      dest->rotate.angle = gtk_css_value_compute (src->rotate.angle, property_id, context);
      return dest->rotate.x == src->rotate.x
          && dest->rotate.y == src->rotate.y
          && dest->rotate.z == src->rotate.z
          && dest->rotate.angle == src->rotate.angle;
    case GTK_CSS_TRANSFORM_SCALE:
      dest->scale.x = gtk_css_value_compute (src->scale.x, property_id, context);
      dest->scale.y = gtk_css_value_compute (src->scale.y, property_id, context);
      dest->scale.z = gtk_css_value_compute (src->scale.z, property_id, context);
      return dest->scale.x == src->scale.x
          && dest->scale.y == src->scale.y
          && dest->scale.z == src->scale.z;
    case GTK_CSS_TRANSFORM_SKEW:
      dest->skew.x = gtk_css_value_compute (src->skew.x, property_id, context);
      dest->skew.y = gtk_css_value_compute (src->skew.y, property_id, context);
      return dest->skew.x == src->skew.x
          && dest->skew.y == src->skew.y;
    case GTK_CSS_TRANSFORM_SKEW_X:
      dest->skew_x.skew = gtk_css_value_compute (src->skew_x.skew, property_id, context);
      return dest->skew_x.skew == src->skew_x.skew;
    case GTK_CSS_TRANSFORM_SKEW_Y:
      dest->skew_y.skew = gtk_css_value_compute (src->skew_y.skew, property_id, context);
      return dest->skew_y.skew == src->skew_y.skew;
    case GTK_CSS_TRANSFORM_PERSPECTIVE:
      dest->perspective.depth = gtk_css_value_compute (src->perspective.depth, property_id, context);
      return dest->perspective.depth == src->perspective.depth;
    case GTK_CSS_TRANSFORM_NONE:
    default:
      g_assert_not_reached ();
      return FALSE;
    }
}

static GtkCssValue *
gtk_css_value_transform_compute (GtkCssValue          *value,
                                 guint                 property_id,
                                 GtkCssComputeContext *context)
{
  GtkCssValue *result;
  gboolean changes;
  guint i;

  /* Special case the 99% case of "none" */
  if (gtk_css_transform_value_is_none (value))
    return gtk_css_value_ref (value);

  changes = FALSE;
  result = gtk_css_transform_value_alloc (value->n_transforms);

  for (i = 0; i < value->n_transforms; i++)
    {
      changes |= !gtk_css_transform_compute (&result->transforms[i],
                                             &value->transforms[i],
                                             property_id,
                                             context);
    }

  if (!changes)
    {
      gtk_css_value_unref (result);
      result = gtk_css_value_ref (value);
    }

  return result;
}

static gboolean
gtk_css_transform_equal (const GtkCssTransform *transform1,
                         const GtkCssTransform *transform2)
{
  if (transform1->type != transform2->type)
    return FALSE;

  switch (transform1->type)
    {
    case GTK_CSS_TRANSFORM_MATRIX:
      {
        guint i, j;

        for (i = 0; i < 4; i++)
          for (j = 0; j < 4; j++)
            {
              if (graphene_matrix_get_value (&transform1->matrix.matrix, i, j)
                  != graphene_matrix_get_value (&transform2->matrix.matrix, i, j))
                return FALSE;
            }
        return TRUE;
      }
    case GTK_CSS_TRANSFORM_TRANSLATE:
      return gtk_css_value_equal (transform1->translate.x, transform2->translate.x)
          && gtk_css_value_equal (transform1->translate.y, transform2->translate.y)
          && gtk_css_value_equal (transform1->translate.z, transform2->translate.z);
    case GTK_CSS_TRANSFORM_ROTATE:
      return gtk_css_value_equal (transform1->rotate.x, transform2->rotate.x)
          && gtk_css_value_equal (transform1->rotate.y, transform2->rotate.y)
          && gtk_css_value_equal (transform1->rotate.z, transform2->rotate.z)
          && gtk_css_value_equal (transform1->rotate.angle, transform2->rotate.angle);
    case GTK_CSS_TRANSFORM_SCALE:
      return gtk_css_value_equal (transform1->scale.x, transform2->scale.x)
          && gtk_css_value_equal (transform1->scale.y, transform2->scale.y)
          && gtk_css_value_equal (transform1->scale.z, transform2->scale.z);
    case GTK_CSS_TRANSFORM_SKEW:
      return gtk_css_value_equal (transform1->skew.x, transform2->skew.x)
          && gtk_css_value_equal (transform1->skew.y, transform2->skew.y);
    case GTK_CSS_TRANSFORM_SKEW_X:
      return gtk_css_value_equal (transform1->skew_x.skew, transform2->skew_x.skew);
    case GTK_CSS_TRANSFORM_SKEW_Y:
      return gtk_css_value_equal (transform1->skew_y.skew, transform2->skew_y.skew);
    case GTK_CSS_TRANSFORM_PERSPECTIVE:
      return gtk_css_value_equal (transform1->perspective.depth, transform2->perspective.depth);
    case GTK_CSS_TRANSFORM_NONE:
    default:
      g_assert_not_reached ();
      return FALSE;
    }
}

static gboolean
gtk_css_value_transform_equal (const GtkCssValue *value1,
                               const GtkCssValue *value2)
{
  const GtkCssValue *larger;
  guint i, n;

  n = MIN (value1->n_transforms, value2->n_transforms);
  for (i = 0; i < n; i++)
    {
      if (!gtk_css_transform_equal (&value1->transforms[i], &value2->transforms[i]))
        return FALSE;
    }

  larger = value1->n_transforms > value2->n_transforms ? value1 : value2;

  for (; i < larger->n_transforms; i++)
    {
      GtkCssTransform transform;

      if (!gtk_css_transform_init_identity (&transform, larger->transforms[i].type))
        return FALSE;

      if (!gtk_css_transform_equal (&larger->transforms[i], &transform))
        {
          gtk_css_transform_clear (&transform);
          return FALSE;
        }

      gtk_css_transform_clear (&transform);
    }

  return TRUE;
}

static void
gtk_css_transform_transition_default (GtkCssTransform       *result,
                                      const GtkCssTransform *start,
                                      const GtkCssTransform *end,
                                      guint                  property_id,
                                      double                 progress)
{
  graphene_matrix_t start_mat, end_mat;
  GskTransform *trans;

  result->type = GTK_CSS_TRANSFORM_MATRIX;

  if (start)
    trans = gtk_css_transform_apply (start, NULL);
  else
    trans = NULL;
  gsk_transform_to_matrix (trans, &start_mat);
  gsk_transform_unref (trans);

  if (end)
    trans = gtk_css_transform_apply (end, NULL);
  else
    trans = NULL;
  gsk_transform_to_matrix (trans, &end_mat);
  gsk_transform_unref (trans);

  graphene_matrix_interpolate (&start_mat,
                               &end_mat,
                               progress,
                               &result->matrix.matrix);
}

static void
gtk_css_transform_transition (GtkCssTransform       *result,
                              const GtkCssTransform *start,
                              const GtkCssTransform *end,
                              guint                  property_id,
                              double                 progress)
{
  result->type = start->type;

  switch (start->type)
    {
    case GTK_CSS_TRANSFORM_MATRIX:
      graphene_matrix_interpolate (&start->matrix.matrix,
                                   &end->matrix.matrix,
                                   progress,
                                   &result->matrix.matrix);
      break;
    case GTK_CSS_TRANSFORM_TRANSLATE:
      result->translate.x = gtk_css_value_transition (start->translate.x, end->translate.x, property_id, progress);
      result->translate.y = gtk_css_value_transition (start->translate.y, end->translate.y, property_id, progress);
      result->translate.z = gtk_css_value_transition (start->translate.z, end->translate.z, property_id, progress);
      break;
    case GTK_CSS_TRANSFORM_ROTATE:
      result->rotate.x = gtk_css_value_transition (start->rotate.x, end->rotate.x, property_id, progress);
      result->rotate.y = gtk_css_value_transition (start->rotate.y, end->rotate.y, property_id, progress);
      result->rotate.z = gtk_css_value_transition (start->rotate.z, end->rotate.z, property_id, progress);
      result->rotate.angle = gtk_css_value_transition (start->rotate.angle, end->rotate.angle, property_id, progress);
      break;
    case GTK_CSS_TRANSFORM_SCALE:
      result->scale.x = gtk_css_value_transition (start->scale.x, end->scale.x, property_id, progress);
      result->scale.y = gtk_css_value_transition (start->scale.y, end->scale.y, property_id, progress);
      result->scale.z = gtk_css_value_transition (start->scale.z, end->scale.z, property_id, progress);
      break;
    case GTK_CSS_TRANSFORM_SKEW:
      result->skew.x = gtk_css_value_transition (start->skew.x, end->skew.x, property_id, progress);
      result->skew.y = gtk_css_value_transition (start->skew.y, end->skew.y, property_id, progress);
      break;
    case GTK_CSS_TRANSFORM_SKEW_X:
      result->skew_x.skew = gtk_css_value_transition (start->skew_x.skew, end->skew_x.skew, property_id, progress);
      break;
    case GTK_CSS_TRANSFORM_SKEW_Y:
      result->skew_y.skew = gtk_css_value_transition (start->skew_y.skew, end->skew_y.skew, property_id, progress);
      break;
    case GTK_CSS_TRANSFORM_PERSPECTIVE:
      gtk_css_transform_transition_default (result, start, end, property_id, progress);
      break;
    case GTK_CSS_TRANSFORM_NONE:
    default:
      g_assert_not_reached ();
      break;
    }
}

static GtkCssValue *
gtk_css_value_transform_transition (GtkCssValue *start,
                                    GtkCssValue *end,
                                    guint        property_id,
                                    double       progress)
{
  GtkCssValue *result;
  guint i, n;

  if (gtk_css_transform_value_is_none (start))
    {
      if (gtk_css_transform_value_is_none (end))
        return gtk_css_value_ref (start);

      n = 0;
    }
  else if (gtk_css_transform_value_is_none (end))
    {
      n = 0;
    }
  else
    {
      n = MIN (start->n_transforms, end->n_transforms);
    }

  /* Check transforms are compatible. If not, transition between
   * their result matrices.
   */

  for (i = 0; i < n; i++)
    {
      if (start->transforms[i].type != end->transforms[i].type)
        {
          GskTransform *transform;
          graphene_matrix_t start_matrix, end_matrix;

          transform = gtk_css_transform_value_compute_transform (start);
          gsk_transform_to_matrix (transform, &start_matrix);
          gsk_transform_unref (transform);

          transform = gtk_css_transform_value_compute_transform (end);
          gsk_transform_to_matrix (transform, &end_matrix);
          gsk_transform_unref (transform);

          result = gtk_css_transform_value_alloc (1);
          result->transforms[0].type = GTK_CSS_TRANSFORM_MATRIX;
          graphene_matrix_interpolate (&start_matrix, &end_matrix, progress, &result->transforms[0].matrix.matrix);

          return result;
        }
    }

  result = gtk_css_transform_value_alloc (MAX (start->n_transforms, end->n_transforms));

  for (i = 0; i < n; i++)
    {
      gtk_css_transform_transition (&result->transforms[i],
                                    &start->transforms[i],
                                    &end->transforms[i],
                                    property_id,
                                    progress);
    }

  for (; i < start->n_transforms; i++)
    {
      GtkCssTransform transform;

      if (gtk_css_transform_init_identity (&transform, start->transforms[i].type))
        {
          gtk_css_transform_transition (&result->transforms[i],
                                        &start->transforms[i],
                                        &transform,
                                        property_id,
                                        progress);
          gtk_css_transform_clear (&transform);
        }
      else
        {
          gtk_css_transform_transition_default (&result->transforms[i],
                                                &start->transforms[i],
                                                NULL,
                                                property_id,
                                                progress);
        }
    }
  for (; i < end->n_transforms; i++)
    {
      GtkCssTransform transform;

      if (gtk_css_transform_init_identity (&transform, end->transforms[i].type))
        {
          gtk_css_transform_transition (&result->transforms[i],
                                        &transform,
                                        &end->transforms[i],
                                        property_id,
                                        progress);
          gtk_css_transform_clear (&transform);
        }
      else
        {
          gtk_css_transform_transition_default (&result->transforms[i],
                                                NULL,
                                                &end->transforms[i],
                                                property_id,
                                                progress);
        }
    }

  g_assert (i == MAX (start->n_transforms, end->n_transforms));

  return result;
}

static void
gtk_css_transform_print (const GtkCssTransform *transform,
                         GString               *string)
{
  char buf[G_ASCII_DTOSTR_BUF_SIZE];

  switch (transform->type)
    {
    case GTK_CSS_TRANSFORM_MATRIX:
      if (graphene_matrix_is_2d (&transform->matrix.matrix))
        {
          g_string_append (string, "matrix(");
          g_ascii_dtostr (buf, sizeof (buf), graphene_matrix_get_value (&transform->matrix.matrix, 00));
          g_string_append (string, buf);
          g_string_append (string, ", ");
          g_ascii_dtostr (buf, sizeof (buf), graphene_matrix_get_value (&transform->matrix.matrix, 01));
          g_string_append (string, buf);
          g_string_append (string, ", ");
          g_ascii_dtostr (buf, sizeof (buf), graphene_matrix_get_value (&transform->matrix.matrix, 02));
          g_string_append (string, buf);
          g_string_append (string, ", ");
          g_ascii_dtostr (buf, sizeof (buf), graphene_matrix_get_value (&transform->matrix.matrix, 10));
          g_string_append (string, buf);
          g_string_append (string, ", ");
          g_ascii_dtostr (buf, sizeof (buf), graphene_matrix_get_value (&transform->matrix.matrix, 11));
          g_string_append (string, buf);
          g_string_append (string, ", ");
          g_ascii_dtostr (buf, sizeof (buf), graphene_matrix_get_value (&transform->matrix.matrix, 12));
          g_string_append (string, buf);
          g_string_append (string, ")");
        }
      else
        {
          guint i;

          g_string_append (string, "matrix3d(");
          for (i = 0; i < 16; i++)
            {
              g_ascii_dtostr (buf, sizeof (buf), graphene_matrix_get_value (&transform->matrix.matrix, i / 4, i % 4));
              g_string_append (string, buf);
              if (i < 15)
                g_string_append (string, ", ");
            }
          g_string_append (string, ")");
        }
      break;
    case GTK_CSS_TRANSFORM_TRANSLATE:
      g_string_append (string, "translate3d(");
      gtk_css_value_print (transform->translate.x, string);
      g_string_append (string, ", ");
      gtk_css_value_print (transform->translate.y, string);
      g_string_append (string, ", ");
      gtk_css_value_print (transform->translate.z, string);
      g_string_append (string, ")");
      break;
    case GTK_CSS_TRANSFORM_ROTATE:
      g_string_append (string, "rotate3d(");
      gtk_css_value_print (transform->rotate.x, string);
      g_string_append (string, ", ");
      gtk_css_value_print (transform->rotate.y, string);
      g_string_append (string, ", ");
      gtk_css_value_print (transform->rotate.z, string);
      g_string_append (string, ", ");
      gtk_css_value_print (transform->rotate.angle, string);
      g_string_append (string, ")");
      break;
    case GTK_CSS_TRANSFORM_SCALE:
      if (gtk_css_number_value_get (transform->scale.z, 100) == 1)
        {
          g_string_append (string, "scale(");
          gtk_css_value_print (transform->scale.x, string);
          if (!gtk_css_value_equal (transform->scale.x, transform->scale.y))
            {
              g_string_append (string, ", ");
              gtk_css_value_print (transform->scale.y, string);
            }
          g_string_append (string, ")");
        }
      else
        {
          g_string_append (string, "scale3d(");
          gtk_css_value_print (transform->scale.x, string);
          g_string_append (string, ", ");
          gtk_css_value_print (transform->scale.y, string);
          g_string_append (string, ", ");
          gtk_css_value_print (transform->scale.z, string);
          g_string_append (string, ")");
        }
      break;
    case GTK_CSS_TRANSFORM_SKEW:
      g_string_append (string, "skew(");
      gtk_css_value_print (transform->skew.x, string);
      g_string_append (string, ", ");
      gtk_css_value_print (transform->skew.y, string);
      g_string_append (string, ")");
      break;
    case GTK_CSS_TRANSFORM_SKEW_X:
      g_string_append (string, "skewX(");
      gtk_css_value_print (transform->skew_x.skew, string);
      g_string_append (string, ")");
      break;
    case GTK_CSS_TRANSFORM_SKEW_Y:
      g_string_append (string, "skewY(");
      gtk_css_value_print (transform->skew_y.skew, string);
      g_string_append (string, ")");
      break;
    case GTK_CSS_TRANSFORM_PERSPECTIVE:
      g_string_append (string, "perspective(");
      gtk_css_value_print (transform->perspective.depth, string);
      g_string_append (string, ")");
      break;
    case GTK_CSS_TRANSFORM_NONE:
    default:
      g_assert_not_reached ();
      break;
    }
}

static void
gtk_css_value_transform_print (const GtkCssValue *value,
                               GString           *string)
{
  guint i;

  if (gtk_css_transform_value_is_none (value))
    {
      g_string_append (string, "none");
      return;
    }

  for (i = 0; i < value->n_transforms; i++)
    {
      if (i > 0)
        g_string_append_c (string, ' ');

      gtk_css_transform_print (&value->transforms[i], string);
    }
}

static const GtkCssValueClass GTK_CSS_VALUE_TRANSFORM = {
  "GtkCssTransformValue",
  gtk_css_value_transform_free,
  gtk_css_value_transform_compute,
  NULL,
  gtk_css_value_transform_equal,
  gtk_css_value_transform_transition,
  NULL,
  NULL,
  gtk_css_value_transform_print
};

static GtkCssValue transform_none_singleton = { >K_CSS_VALUE_TRANSFORM, 11000, {  { GTK_CSS_TRANSFORM_NONE } } };

static GtkCssValue *
gtk_css_transform_value_alloc (guint n_transforms)
{
  GtkCssValue *result;
           
  g_return_val_if_fail (n_transforms > 0, NULL);
         
  result = gtk_css_value_alloc (>K_CSS_VALUE_TRANSFORM, sizeof (GtkCssValue) + sizeof (GtkCssTransform) * (n_transforms - 1));
  result->n_transforms = n_transforms;
            
  return result;
}

GtkCssValue *
_gtk_css_transform_value_new_none (void)
{
  return gtk_css_value_ref (&transform_none_singleton);
}

static gboolean
gtk_css_transform_value_is_none (const GtkCssValue *value)
{
  return value->n_transforms == 0;
}

static guint
gtk_css_transform_parse_float (GtkCssParser *parser,
                               guint         n,
                               gpointer      data)
{
  float *f = data;
  double d;

  if (!gtk_css_parser_consume_number (parser, &d))
    return 0;

  f[n] = d;
  return 1;
}

static guint
gtk_css_transform_parse_length (GtkCssParser *parser,
                                guint         n,
                                gpointer      data)
{
  GtkCssValue **values = data;

  values[n] = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH);
  if (values[n] == NULL)
    return 0;

  return 1;
}

static guint
gtk_css_transform_parse_angle (GtkCssParser *parser,
                               guint         n,
                               gpointer      data)
{
  GtkCssValue **values = data;

  values[n] = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE);
  if (values[n] == NULL)
    return 0;

  return 1;
}

static guint
gtk_css_transform_parse_number (GtkCssParser *parser,
                                guint         n,
                                gpointer      data)
{
  GtkCssValue **values = data;

  values[n] = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER);
  if (values[n] == NULL)
    return 0;

  return 1;
}

static guint
gtk_css_transform_parse_rotate3d (GtkCssParser *parser,
                                  guint         n,
                                  gpointer      data)
{
  GtkCssTransform *transform = data;

  switch (n)
  {
    case 0:
      transform->rotate.x = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER);
      if (transform->rotate.x == NULL)
        return 0;
      break;

    case 1:
      transform->rotate.y = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER);
      if (transform->rotate.y == NULL)
        return 0;
      break;

    case 2:
      transform->rotate.z = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER);
      if (transform->rotate.z == NULL)
        return 0;
      break;

    case 3:
      transform->rotate.angle = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE);
      if (transform->rotate.angle == NULL)
        return 0;
      break;

    default:
      g_assert_not_reached();
      return 0;
  }

  return 1;
}

GtkCssValue *
_gtk_css_transform_value_parse (GtkCssParser *parser)
{
  GtkCssValue *value;
  GArray *array;
  guint i;
  gboolean computed = TRUE;

  if (gtk_css_parser_try_ident (parser, "none"))
    return _gtk_css_transform_value_new_none ();

  array = g_array_new (FALSEFALSEsizeof (GtkCssTransform));

  while (TRUE)
    {
      GtkCssTransform transform;

      memset (&transform, 0sizeof (GtkCssTransform));

      if (gtk_css_parser_has_function (parser, "matrix"))
        {
          float f[6];

          if (!gtk_css_parser_consume_function (parser, 66, gtk_css_transform_parse_float, f))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_MATRIX;
          graphene_matrix_init_from_2d (&transform.matrix.matrix, f[0], f[1], f[2], f[3], f[4], f[5]);
        }
      else if (gtk_css_parser_has_function (parser, "matrix3d"))
        {
          float f[16];

          if (!gtk_css_parser_consume_function (parser, 1616, gtk_css_transform_parse_float, f))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_MATRIX;
          graphene_matrix_init_from_float (&transform.matrix.matrix, f);
        }
      else if (gtk_css_parser_has_function (parser, "perspective"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_length, &transform.perspective.depth))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_PERSPECTIVE;
          computed = computed && gtk_css_value_is_computed (transform.perspective.depth);
        }
      else if (gtk_css_parser_has_function (parser, "rotate") ||
               gtk_css_parser_has_function (parser, "rotateZ"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_angle, &transform.rotate.angle))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_ROTATE;
          transform.rotate.x = gtk_css_number_value_new (0, GTK_CSS_NUMBER);
          transform.rotate.y = gtk_css_number_value_new (0, GTK_CSS_NUMBER);
          transform.rotate.z = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          computed = computed && gtk_css_value_is_computed (transform.rotate.angle);
        }
      else if (gtk_css_parser_has_function (parser, "rotate3d"))
        {
          if (!gtk_css_parser_consume_function (parser, 44, gtk_css_transform_parse_rotate3d, &transform))
            {
              g_clear_pointer (&transform.rotate.x, gtk_css_value_unref);
              g_clear_pointer (&transform.rotate.y, gtk_css_value_unref);
              g_clear_pointer (&transform.rotate.z, gtk_css_value_unref);
              g_clear_pointer (&transform.rotate.angle, gtk_css_value_unref);
              goto fail;
            }

          transform.type = GTK_CSS_TRANSFORM_ROTATE;
          computed = computed && gtk_css_value_is_computed (transform.rotate.angle) &&
                                 gtk_css_value_is_computed (transform.rotate.x) &&
                                 gtk_css_value_is_computed (transform.rotate.y) &&
                                 gtk_css_value_is_computed (transform.rotate.z);
        }
      else if (gtk_css_parser_has_function (parser, "rotateX"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_angle, &transform.rotate.angle))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_ROTATE;
          transform.rotate.x = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          transform.rotate.y = gtk_css_number_value_new (0, GTK_CSS_NUMBER);
          transform.rotate.z = gtk_css_number_value_new (0, GTK_CSS_NUMBER);
          computed = computed && gtk_css_value_is_computed (transform.rotate.angle);
        }
      else if (gtk_css_parser_has_function (parser, "rotateY"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_angle, &transform.rotate.angle))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_ROTATE;
          transform.rotate.x = gtk_css_number_value_new (0, GTK_CSS_NUMBER);
          transform.rotate.y = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          transform.rotate.z = gtk_css_number_value_new (0, GTK_CSS_NUMBER);
          computed = computed && gtk_css_value_is_computed (transform.rotate.angle);
        }
      else if (gtk_css_parser_has_function (parser, "scale"))
        {
          GtkCssValue *values[2] = { NULL, NULL };

          if (!gtk_css_parser_consume_function (parser, 12, gtk_css_transform_parse_number, values))
            {
              g_clear_pointer (&values[0], gtk_css_value_unref);
              g_clear_pointer (&values[1], gtk_css_value_unref);
              goto fail;
            }

          transform.type = GTK_CSS_TRANSFORM_SCALE;
          transform.scale.x = values[0];
          if (values[1])
            transform.scale.y = values[1];
          else
            transform.scale.y = gtk_css_value_ref (values[0]);
          transform.scale.z = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          computed = computed && gtk_css_value_is_computed (transform.scale.x) &&
                                 gtk_css_value_is_computed (transform.scale.y);
        }
      else if (gtk_css_parser_has_function (parser, "scale3d"))
        {
          GtkCssValue *values[3] = { NULL, NULL };

          if (!gtk_css_parser_consume_function (parser, 33, gtk_css_transform_parse_number, values))
            {
              g_clear_pointer (&values[0], gtk_css_value_unref);
              g_clear_pointer (&values[1], gtk_css_value_unref);
              g_clear_pointer (&values[2], gtk_css_value_unref);
              goto fail;
            }

          transform.type = GTK_CSS_TRANSFORM_SCALE;
          transform.scale.x = values[0];
          transform.scale.y = values[1];
          transform.scale.z = values[2];
          computed = computed && gtk_css_value_is_computed (transform.scale.x) &&
                                 gtk_css_value_is_computed (transform.scale.y) &&
                                 gtk_css_value_is_computed (transform.scale.z);
        }
      else if (gtk_css_parser_has_function (parser, "scaleX"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_number, &transform.scale.x))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_SCALE;
          transform.scale.y = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          transform.scale.z = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          computed = computed && gtk_css_value_is_computed (transform.scale.x);
        }
      else if (gtk_css_parser_has_function (parser, "scaleY"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_number, &transform.scale.y))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_SCALE;
          transform.scale.x = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          transform.scale.z = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          computed = computed && gtk_css_value_is_computed (transform.scale.y);
        }
      else if (gtk_css_parser_has_function (parser, "scaleZ"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_number, &transform.scale.z))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_SCALE;
          transform.scale.x = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          transform.scale.y = gtk_css_number_value_new (1, GTK_CSS_NUMBER);
          computed = computed && gtk_css_value_is_computed (transform.scale.z);
        }
      else if (gtk_css_parser_has_function (parser, "skew"))
        {
          GtkCssValue *values[2] = { NULL, NULL };

          if (!gtk_css_parser_consume_function (parser, 22, gtk_css_transform_parse_angle, values))
            {
              g_clear_pointer (&values[0], gtk_css_value_unref);
              g_clear_pointer (&values[1], gtk_css_value_unref);
              goto fail;
            }

          transform.type = GTK_CSS_TRANSFORM_SKEW;
          transform.skew.x = values[0];
          transform.skew.y = values[1];
          computed = computed && gtk_css_value_is_computed (transform.skew.x) &&
                                 gtk_css_value_is_computed (transform.skew.y);
        }
      else if (gtk_css_parser_has_function (parser, "skewX"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_angle, &transform.skew_x.skew))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_SKEW_X;
          computed = computed && gtk_css_value_is_computed (transform.skew_x.skew);
        }
      else if (gtk_css_parser_has_function (parser, "skewY"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_angle, &transform.skew_y.skew))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_SKEW_Y;
          computed = computed && gtk_css_value_is_computed (transform.skew_y.skew);
        }
      else if (gtk_css_parser_has_function (parser, "translate"))
        {
          GtkCssValue *values[2] = { NULL, NULL };

          if (!gtk_css_parser_consume_function (parser, 12, gtk_css_transform_parse_length, values))
            {
              g_clear_pointer (&values[0], gtk_css_value_unref);
              g_clear_pointer (&values[1], gtk_css_value_unref);
              goto fail;
            }

          transform.type = GTK_CSS_TRANSFORM_TRANSLATE;
          transform.translate.x = values[0];
          if (values[1])
            transform.translate.y = values[1];
          else
            transform.translate.y = gtk_css_number_value_new (0, GTK_CSS_PX);
          transform.translate.z = gtk_css_number_value_new (0, GTK_CSS_PX);
          computed = computed && gtk_css_value_is_computed (transform.translate.x) &&
                                 gtk_css_value_is_computed (transform.translate.y);
        }
      else if (gtk_css_parser_has_function (parser, "translate3d"))
        {
          GtkCssValue *values[3] = { NULL, NULL };

          if (!gtk_css_parser_consume_function (parser, 33, gtk_css_transform_parse_length, values))
            {
              g_clear_pointer (&values[0], gtk_css_value_unref);
              g_clear_pointer (&values[1], gtk_css_value_unref);
              g_clear_pointer (&values[2], gtk_css_value_unref);
              goto fail;
            }

          transform.type = GTK_CSS_TRANSFORM_TRANSLATE;
          transform.translate.x = values[0];
          transform.translate.y = values[1];
          transform.translate.z = values[2];
          computed = computed && gtk_css_value_is_computed (transform.translate.x) &&
                                 gtk_css_value_is_computed (transform.translate.y) &&
                                 gtk_css_value_is_computed (transform.translate.z);
        }
      else if (gtk_css_parser_has_function (parser, "translateX"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_length, &transform.translate.x))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_TRANSLATE;
          transform.translate.y = gtk_css_number_value_new (0, GTK_CSS_PX);
          transform.translate.z = gtk_css_number_value_new (0, GTK_CSS_PX);
          computed = computed && gtk_css_value_is_computed (transform.translate.x);
        }
      else if (gtk_css_parser_has_function (parser, "translateY"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_length, &transform.translate.y))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_TRANSLATE;
          transform.translate.x = gtk_css_number_value_new (0, GTK_CSS_PX);
          transform.translate.z = gtk_css_number_value_new (0, GTK_CSS_PX);
          computed = computed && gtk_css_value_is_computed (transform.translate.y);
        }
      else if (gtk_css_parser_has_function (parser, "translateZ"))
        {
          if (!gtk_css_parser_consume_function (parser, 11, gtk_css_transform_parse_length, &transform.translate.z))
            goto fail;

          transform.type = GTK_CSS_TRANSFORM_TRANSLATE;
          transform.translate.x = gtk_css_number_value_new (0, GTK_CSS_PX);
          transform.translate.y = gtk_css_number_value_new (0, GTK_CSS_PX);
          computed = computed && gtk_css_value_is_computed (transform.translate.z);
        }
      else
        {
          break;
        }

      g_array_append_val (array, transform);
    }

  if (array->len == 0)
    {
      gtk_css_parser_error_syntax (parser, "Expected a transform");
      goto fail;
    }

  value = gtk_css_transform_value_alloc (array->len);
  value->is_computed = computed;
  memcpy (value->transforms, array->data, sizeof (GtkCssTransform) * array->len);

  g_array_free (array, TRUE);

  return value;

fail:
  for (i = 0; i < array->len; i++)
    {
      gtk_css_transform_clear (&g_array_index (array, GtkCssTransform, i));
    }
  g_array_free (array, TRUE);
  return NULL;
}

GskTransform *
gtk_css_transform_value_get_transform (const GtkCssValue *transform)
{
  g_return_val_if_fail (transform->class == >K_CSS_VALUE_TRANSFORM, FALSE);

  if (transform->n_transforms == 0)
    return NULL;

  return gtk_css_transform_value_compute_transform (transform);
}


Messung V0.5 in Prozent
C=98 H=95 G=96

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© 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