Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gnome/gsk/   (Gnome Linux Desktop Version 4.23.2©)  Datei vom 30.5.2026 mit Größe 13 kB image not shown  

Quelle  gskarithmeticnode.c

  Sprache: C
 

/* GSK - The GTK Scene Kit
 *
 * Copyright 2025 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 "gskarithmeticnodeprivate.h"

#include "gskrendernodeprivate.h"
#include "gskrenderreplay.h"
#include "gskcontainernode.h"
#include "gskrectprivate.h"

#include "gdk/gdkcairoprivate.h"

/**
 * GskArithmeticNode:
 *
 * A render node applying the 'arithmetic' composite operator,
 * as defined in the
 * [CSS filter effects](https://www.w3.org/TR/filter-effects-1/)
 * spec,
 *
 *     result = k1 * i1 * i1 + k2 * i1 + k3 * i3 + k4
 */

struct _GskArithmeticNode
{
  GskRenderNode render_node;

  union {
    GskRenderNode *children[2];
    struct {
      GskRenderNode *first;
      GskRenderNode *second;
    };
  };
  GdkColorState *color_state;
  float factors[4];
  GskRectSnap snap;
};

static void
gsk_arithmetic_node_finalize (GskRenderNode *node)
{
  GskArithmeticNode *self = (GskArithmeticNode *) node;
  GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_ARITHMETIC_NODE));

  gsk_render_node_unref (self->first);
  gsk_render_node_unref (self->second);
  gdk_color_state_unref (self->color_state);

  parent_class->finalize (node);
}

static void
gsk_arithmetic_node_draw (GskRenderNode *node,
                          cairo_t       *cr,
                          GskCairoData  *data)
{
  GskArithmeticNode *self = (GskArithmeticNode *) node;
  cairo_pattern_t *first_pattern, *second_pattern;
  cairo_surface_t *first_surface, *second_surface;
  cairo_surface_t *first_image, *second_image;
  guchar *first_data, *second_data;
  int first_width, first_height, first_stride;
  int second_stride;
  guint32 pixel1, pixel2;
  float r1, g1, b1, a1, r2, g2, b2, a2, r, g, b, a;
  float k1, k2, k3, k4;
  gboolean cs_equal;
  GdkColor c, l;
  graphene_rect_t bounds;

  if (!gsk_cairo_rect_snap (cr, &node->bounds, self->snap, &bounds))
    return;

  gdk_cairo_rect (cr, &bounds);
  cairo_clip (cr);

  if (gdk_cairo_is_all_clipped (cr))
    return;

  k1 = self->factors[0];
  k2 = self->factors[1];
  k3 = self->factors[2];
  k4 = self->factors[3];

  cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
  gsk_render_node_draw_full (self->first, cr, data);
  first_pattern = cairo_pop_group (cr);
  cairo_pattern_get_surface (first_pattern, &first_surface);
  first_image = cairo_surface_map_to_image (first_surface, NULL);
  first_data = cairo_image_surface_get_data (first_image);
  first_width = cairo_image_surface_get_width (first_image);
  first_height = cairo_image_surface_get_height (first_image);
  first_stride = cairo_image_surface_get_stride (first_image);

  cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
  gsk_render_node_draw_full (self->second, cr, data);
  second_pattern = cairo_pop_group (cr);
  cairo_pattern_get_surface (second_pattern, &second_surface);
  second_image = cairo_surface_map_to_image (second_surface, NULL);
  second_data = cairo_image_surface_get_data (second_image);
  second_stride = cairo_image_surface_get_stride (second_image);

  g_assert (first_width == cairo_image_surface_get_width (second_image));
  g_assert (first_height == cairo_image_surface_get_height (second_image));

  cs_equal = gdk_color_state_equal (data->ccs, self->color_state);

  for (guint y = 0; y < first_height; y++)
    {
      for (guint x = 0; x < first_width; x++)
        {
          pixel1 = *(guint32 *)(first_data + y * first_stride + 4 * x);
          a1 = ((pixel1 >> 24) & 0xff) / 255.;

          pixel2 = *(guint32 *)(second_data + y * second_stride + 4 * x);
          a2 = ((pixel2 >> 24) & 0xff) / 255.;

          a = k1 * a1 * a2 + k2 * a1 + k3 * a2 + k4;
          a = CLAMP (a, 01);

          if (a > 0)
            {
              r1 = ((pixel1 >> 16) & 0xff) / 255.;
              g1 = ((pixel1 >> 8) & 0xff) / 255.;
              b1 = ((pixel1 >> 0) & 0xff) / 255.;

              if (!cs_equal && a1 > 0)
                {
                  r1 /= a1;
                  g1 /= a1;
                  b1 /= a1;

                  gdk_color_init (&c, data->ccs, (float[]) { r1, g1, b1, a1 });
                  gdk_color_convert (&l, self->color_state, &c);

                  r1 = l.r * l.a;
                  g1 = l.g * l.a;
                  b1 = l.b * l.a;
                }

              r2 = ((pixel2 >> 16) & 0xff) / 255.;
              g2 = ((pixel2 >> 8) & 0xff) / 255.;
              b2 = ((pixel2 >> 0) & 0xff) / 255.;

              if (!cs_equal && a2 > 0)
                {
                  r2 /= a2;
                  g2 /= a2;
                  b2 /= a2;

                  gdk_color_init (&c, data->ccs, (float[]) { r2, g2, b2, a2 });
                  gdk_color_convert (&l, self->color_state, &c);

                  r2 = l.r * l.a;
                  g2 = l.g * l.a;
                  b2 = l.b * l.a;
                }

              r = k1 * r1 * r2 + k2 * r1 + k3 * r2 + k4;
              g = k1 * g1 * g2 + k2 * g1 + k3 * g2 + k4;
              b = k1 * b1 * b2 + k2 * b1 + k3 * b2 + k4;

              r = CLAMP (r, 0, a);
              g = CLAMP (g, 0, a);
              b = CLAMP (b, 0, a);

              if (!cs_equal)
                {
                  r /= a;
                  g /= a;
                  b /= a;

                  gdk_color_init (&l, self->color_state, (float[]) { r, g, b, a });
                  gdk_color_convert (&c, data->ccs, &l);

                  r = c.r * c.a;
                  g = c.g * c.a;
                  b = c.b * c.a;
                }

            }
          else
            {
              r = 0;
              g = 0;
              b = 0;
            }

          *(guint32 *)(first_data + y * first_stride + 4 * x) =
              CLAMP ((int) roundf (a * 255), 0255) << 24 |
              CLAMP ((int) roundf (r * 255), 0255) << 16 |
              CLAMP ((int) roundf (g * 255), 0255) << 8 |
              CLAMP ((int) roundf (b * 255), 0255) << 0;
        }
    }

  cairo_surface_unmap_image (first_surface, first_image);
  cairo_surface_unmap_image (second_surface, second_image);

  cairo_set_source (cr, first_pattern);

  cairo_paint (cr);

  cairo_pattern_destroy (first_pattern);
  cairo_pattern_destroy (second_pattern);
}

static void
gsk_arithmetic_node_diff (GskRenderNode *node1,
                          GskRenderNode *node2,
                          GskDiffData   *data)
{
  GskArithmeticNode *self1 = (GskArithmeticNode *) node1;
  GskArithmeticNode *self2 = (GskArithmeticNode *) node2;

  if (self1->factors[0] == self2->factors[0] &&
      self1->factors[1] == self2->factors[1] &&
      self1->factors[2] == self2->factors[2] &&
      self1->factors[3] == self2->factors[3] &&
      self1->snap == self2->snap &&
      gdk_color_state_equal (self1->color_state, self2->color_state))
    {
      gsk_render_node_diff (self1->first, self2->first, data);
      gsk_render_node_diff (self1->second, self2->second, data);
    }
  else
    {
      gsk_render_node_diff_impossible (node1, node2, data);
    }
}

static GskRenderNode **
gsk_arithmetic_node_get_children (GskRenderNode *node,
                                  gsize         *n_children)
{
  GskArithmeticNode *self = (GskArithmeticNode *) node;

  *n_children = G_N_ELEMENTS (self->children);

  return self->children;
}

static GskRenderNode *
gsk_arithmetic_node_replay (GskRenderNode   *node,
                            GskRenderReplay *replay)
{
  GskArithmeticNode *self = (GskArithmeticNode *) node;
  GskRenderNode *result, *first, *second;

  first = gsk_render_replay_filter_node (replay, self->first);
  second = gsk_render_replay_filter_node (replay, self->second);

  if (first == NULL)
    {
      if (second == NULL)
        return NULL;

      first = gsk_container_node_new (NULL, 0);
    }
  else if (second == NULL)
    {
      second = gsk_container_node_new (NULL, 0);
    }

  if (first == self->first && second == self->second)
    result = gsk_render_node_ref (node);
  else
    result = gsk_arithmetic_node_new (&node->bounds,
                                      self->snap,
                                      first, second,
                                      self->color_state,
                                      self->factors);

  gsk_render_node_unref (first);
  gsk_render_node_unref (second);

  return result;
}

static void
gsk_arithmetic_node_class_init (gpointer g_class,
                                gpointer class_data)
{
  GskRenderNodeClass *node_class = g_class;

  node_class->node_type = GSK_ARITHMETIC_NODE;

  node_class->finalize = gsk_arithmetic_node_finalize;
  node_class->draw = gsk_arithmetic_node_draw;
  node_class->diff = gsk_arithmetic_node_diff;
  node_class->get_children = gsk_arithmetic_node_get_children;
  node_class->replay = gsk_arithmetic_node_replay;
}

GSK_DEFINE_RENDER_NODE_TYPE (GskArithmeticNode, gsk_arithmetic_node)

/*< private >
 * gsk_arithmetic_node_new:
 * @bounds: The bounds for the node
 * @snap: how to snap the rectangle to the pixel grid
 * @first: The first node to be composited
 * @second: The second node to be composited
 * @color_state: The color state to composite in
 * @factors: the 4 factors, often named "k1" to "k4"
 *
 * Creates a `GskRenderNode` that will composite the
 * @first and @second nodes arithmetically.
 *
 * Returns: (transfer full) (type GskArithmeticNode): A new `GskRenderNode`
 */

GskRenderNode *
gsk_arithmetic_node_new (const graphene_rect_t *bounds,
                         GskRectSnap            snap,
                         GskRenderNode         *first,
                         GskRenderNode         *second,
                         GdkColorState         *color_state,
                         const float            factors[4])
{
  GskArithmeticNode *self;
  GskRenderNode *node;
  graphene_rect_t child_bounds;

  g_return_val_if_fail (GSK_IS_RENDER_NODE (first), NULL);
  g_return_val_if_fail (GSK_IS_RENDER_NODE (second), NULL);

  self = gsk_render_node_alloc (GSK_TYPE_ARITHMETIC_NODE);
  node = (GskRenderNode *) self;

  if (!GDK_IS_DEFAULT_COLOR_STATE (color_state))
    {
      g_warning ("Arithmetic compositing in %s is not supported", gdk_color_state_get_name (color_state));
      return NULL;
    }

  self->snap = snap;
  self->first = gsk_render_node_ref (first);
  self->second = gsk_render_node_ref (second);
  self->color_state = gdk_color_state_ref (color_state);
  self->factors[0] = factors[0];
  self->factors[1] = factors[1];
  self->factors[2] = factors[2];
  self->factors[3] = factors[3];

  graphene_rect_union (&first->bounds, &second->bounds, &child_bounds);
  graphene_rect_intersection (bounds, &child_bounds, &node->bounds);

  node->preferred_depth = gdk_memory_depth_merge (gsk_render_node_get_preferred_depth (first),
                                                  gsk_render_node_get_preferred_depth (second));
  node->is_hdr = gsk_render_node_is_hdr (first) ||
                 gsk_render_node_is_hdr (second);
  node->fully_opaque = !gsk_rect_snap_can_shrink (snap) &&
                       gsk_render_node_is_fully_opaque (first) &&
                       gsk_render_node_is_fully_opaque (second) &&
                       gsk_rect_contains_rect (&first->bounds, bounds) &&
                       gsk_rect_contains_rect (&second->bounds, bounds) &&
                       factors[0] + factors[1] + factors[2] + factors[3] >= 1;
  node->contains_subsurface_node = gsk_render_node_contains_subsurface_node (first) ||
                                   gsk_render_node_contains_subsurface_node (second);
  node->contains_paste_node = gsk_render_node_contains_paste_node (first) ||
                              gsk_render_node_contains_paste_node (second);

  return node;
}

/*< private >
 * gsk_arithmetic_node_get_first_child:
 * @node: (type GskArithmeticNode): a `GskRenderNode`
 *
 * Retrieves the first `GskRenderNode` child of the @node.
 *
 * Returns: (transfer none): the first child node
 */

GskRenderNode *
gsk_arithmetic_node_get_first_child (const GskRenderNode *node)
{
  const GskArithmeticNode *self = (const GskArithmeticNode *) node;

  return self->first;
}

/*< private >
 * gsk_arithmetic_node_get_second_child:
 * @node: (type GskArithmeticNode): a `GskRenderNode`
 *
 * Retrieves the second `GskRenderNode` child of the @node.
 *
 * Returns: (transfer none): the second child node
 */

GskRenderNode *
gsk_arithmetic_node_get_second_child (const GskRenderNode *node)
{
  const GskArithmeticNode *self = (const GskArithmeticNode *) node;

  return self->second;
}

/*< private >
 * gsk_arithmetic_node_get_factors:
 * @node: (type GskArithmeticNode): a `GskRenderNode`
 *
 * Retrieves the factors used by @node.
 *
 * Returns: (transfer none) (array fixed-size=4): the factors
 */

const float *
gsk_arithmetic_node_get_factors (const GskRenderNode *node)
{
  const GskArithmeticNode *self = (const GskArithmeticNode *) node;

  return self->factors;
}

/*< private >
 * gsk_arithmetic_node_get_color_state:
 * @node: (type GskArithmeticNode): a `GskRenderNode`
 *
 * Retrieves the color state of the @node.
 *
 * Returns: (transfer none): the color state
 */

GdkColorState *
gsk_arithmetic_node_get_color_state (const GskRenderNode *node)
{
  const GskArithmeticNode *self = (const GskArithmeticNode *) node;

  return self->color_state;
}

/*< private >
 * gsk_arithmetic_node_get_snap:
 * @node: (type GskArithmeticNode): a `GskRenderNode`
 *
 * Retrieves the snap value for this node
 *
 * Returns: the snap value
 **/

GskRectSnap
gsk_arithmetic_node_get_snap (const GskRenderNode *node)
{
  const GskArithmeticNode *self = (const GskArithmeticNode *) node;

  return self->snap;
}

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

¤ Dauer der Verarbeitung: 0.15 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.