Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  gskcontainernode.c

  Sprache: C
 

/* GSK - The GTK Scene Kit
 *
 * Copyright 2016  Endless
 *
 * 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 "gskcontainernodeprivate.h"

#include "gskdiffprivate.h"
#include "gskrectprivate.h"
#include "gskrenderreplay.h"
#include "gpu/gskgpuocclusionprivate.h"

/* maximal number of rectangles we keep in a diff region before we throw
 * the towel and just use the bounding box of the parent node.
 * Meant to avoid performance corner cases.
 */

#define MAX_RECTS_IN_DIFF 30

/**
 * GskContainerNode:
 *
 * A render node that can contain other render nodes.
 */

struct _GskContainerNode
{
  GskRenderNode render_node;

  gboolean disjoint;
  graphene_rect_t opaque; /* Can be 0 0 0 0 to mean no opacity */
  guint n_children;
  GskRenderNode **children;
};

static void
gsk_container_node_finalize (GskRenderNode *node)
{
  GskContainerNode *container = (GskContainerNode *) node;
  GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_CONTAINER_NODE));

  for (guint i = 0; i < container->n_children; i++)
    gsk_render_node_unref (container->children[i]);

  g_free (container->children);

  parent_class->finalize (node);
}

static void
gsk_container_node_draw (GskRenderNode *node,
                         cairo_t       *cr,
                         GskCairoData  *data)
{
  GskContainerNode *container = (GskContainerNode *) node;
  guint i;

  for (i = 0; i < container->n_children; i++)
    {
      gsk_render_node_draw_full (container->children[i], cr, data);
    }
}

static int
gsk_container_node_compare_func (gconstpointer elem1, gconstpointer elem2, gpointer data)
{
  return gsk_render_node_can_diff ((const GskRenderNode *) elem1, (const GskRenderNode *) elem2) ? 0 : 1;
}

static GskDiffResult
gsk_container_node_keep_func (gconstpointer elem1, gconstpointer elem2, gpointer user_data)
{
  GskDiffData *data = user_data;
  gsk_render_node_diff ((GskRenderNode *) elem1, (GskRenderNode *) elem2, data);
  if (cairo_region_num_rectangles (data->region) > MAX_RECTS_IN_DIFF)
    return GSK_DIFF_ABORTED;

  return GSK_DIFF_OK;
}

static GskDiffResult
gsk_container_node_change_func (gconstpointer elem, gsize idx, gpointer user_data)
{
  const GskRenderNode *node = elem;
  GskDiffData *data = user_data;
  cairo_rectangle_int_t rect;

  gsk_rect_to_cairo_grow (&node->bounds, &rect);
  cairo_region_union_rectangle (data->region, &rect);
  if (cairo_region_num_rectangles (data->region) > MAX_RECTS_IN_DIFF)
    return GSK_DIFF_ABORTED;

  return GSK_DIFF_OK;
}

static GskDiffSettings *
gsk_container_node_get_diff_settings (void)
{
  static GskDiffSettings *settings = NULL;

  if (G_LIKELY (settings))
    return settings;

  settings = gsk_diff_settings_new (gsk_container_node_compare_func,
                                    gsk_container_node_keep_func,
                                    gsk_container_node_change_func,
                                    gsk_container_node_change_func);
  gsk_diff_settings_set_allow_abort (settings, TRUE);

  return settings;
}

static gboolean
gsk_render_node_diff_multiple (GskRenderNode **nodes1,
                               gsize           n_nodes1,
                               GskRenderNode **nodes2,
                               gsize           n_nodes2,
                               GskDiffData    *data)
{
  return gsk_diff ((gconstpointer *) nodes1, n_nodes1,
                   (gconstpointer *) nodes2, n_nodes2,
                   gsk_container_node_get_diff_settings (),
                   data) == GSK_DIFF_OK;
}

void
gsk_container_node_diff_with (GskRenderNode *container,
                              GskRenderNode *other,
                              GskDiffData   *data)
{
  GskContainerNode *self = (GskContainerNode *) container;

  if (gsk_render_node_diff_multiple (self->children,
                                     self->n_children,
                                     &other,
                                     1,
                                     data))
    return;

  gsk_render_node_diff_impossible (container, other, data);
}

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

  if (gsk_render_node_diff_multiple (self1->children,
                                     self1->n_children,
                                     self2->children,
                                     self2->n_children,
                                     data))
    return;

  gsk_render_node_diff_impossible (node1, node2, data);
}

static GskRenderNode **
gsk_container_node_get_children (GskRenderNode *node,
                                 gsize         *n_children)
{
  GskContainerNode *self = (GskContainerNode *) node;

  *n_children = self->n_children;

  return self->children;
}

static GskRenderNode *
gsk_container_node_replay (GskRenderNode   *node,
                           GskRenderReplay *replay)
{
  GskContainerNode *self = (GskContainerNode *) node;
  GskRenderNode *result;
  GPtrArray *array;
  gboolean changed;
  guint i;

  array = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
  changed = FALSE;

  for (i = 0; i < self->n_children; i++)
    {
      GskRenderNode *replayed = gsk_render_replay_filter_node (replay, self->children[i]);

      if (replayed != self->children[i])
        changed = TRUE;

      if (replayed != NULL)
        g_ptr_array_add (array, replayed);
    }

  if (!changed)
    result = gsk_render_node_ref (node);
  else
    result = gsk_container_node_new ((GskRenderNode **) array->pdata, array->len);

  g_ptr_array_unref (array);

  return result;
}

static gboolean
gsk_container_node_can_cache_opacity (GskContainerNode *self)
{
  GskRenderNode *node = (GskRenderNode *) self;

  return !gsk_render_node_contains_paste_node (node) &&
         !gsk_render_node_clears_background (node);
}

static void
gsk_container_node_render_opacity (GskRenderNode  *node,
                                   GskOpacityData *data)
{
  GskContainerNode *self = (GskContainerNode *) node;
  guint i;

  if (gsk_container_node_can_cache_opacity (self))
    {
      if (!gsk_rect_is_empty (&self->opaque))
        {
          if (gsk_rect_is_empty (&data->opaque))
            data->opaque = self->opaque;
          else
            gsk_rect_coverage (&data->opaque, &self->opaque, &data->opaque);
        }
      return;
    }

  for (i = 0; i < self->n_children; i++)
    {
      gsk_render_node_render_opacity (self->children[i], data);
    }
}

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

  node_class->node_type = GSK_CONTAINER_NODE;

  node_class->finalize = gsk_container_node_finalize;
  node_class->draw = gsk_container_node_draw;
  node_class->diff = gsk_container_node_diff;
  node_class->get_children = gsk_container_node_get_children;
  node_class->replay = gsk_container_node_replay;
  node_class->render_opacity = gsk_container_node_render_opacity;
  node_class->occlusion = gsk_container_node_occlusion;
}

GSK_DEFINE_RENDER_NODE_TYPE (GskContainerNode, gsk_container_node)

/**
 * gsk_container_node_new:
 * @children: (array length=n_children) (transfer none): The children of the node
 * @n_children: Number of children in the @children array
 *
 * Creates a new `GskRenderNode` instance for holding the given @children.
 *
 * The new node will acquire a reference to each of the children.
 *
 * Returns: (transfer full) (type GskContainerNode): the new `GskRenderNode`
 */

GskRenderNode *
gsk_container_node_new (GskRenderNode **children,
                        guint           n_children)
{
  GskContainerNode *self;
  GskRenderNode *node;
  guint i;

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

  self->disjoint = TRUE;
  self->n_children = n_children;

  if (n_children == 0)
    {
      gsk_rect_init_from_rect (&node->bounds, graphene_rect_zero ());
      node->preferred_depth = GDK_MEMORY_NONE;
    }
  else
    {
      self->children = g_malloc_n (n_children, sizeof (GskRenderNode *));

      self->children[0] = gsk_render_node_ref (children[0]);
      node->preferred_depth = children[0]->preferred_depth;
      gsk_rect_init_from_rect (&node->bounds, &(children[0]->bounds));
      node->is_hdr = gsk_render_node_is_hdr (children[0]);
      node->clears_background = gsk_render_node_clears_background (children[0]);
      node->copy_mode = gsk_render_node_get_copy_mode (children[0]);
      node->contains_subsurface_node = gsk_render_node_contains_subsurface_node (children[0]);
      node->contains_paste_node = gsk_render_node_contains_paste_node (children[0]);
      node->needs_blending = n_children > 1 || gsk_render_node_needs_blending (children[0]);

      for (i = 1; i < n_children; i++)
        {
          self->children[i] = gsk_render_node_ref (children[i]);
          self->disjoint = self->disjoint && !gsk_rect_intersects (&node->bounds, &(children[i]->bounds));
          graphene_rect_union (&node->bounds, &(children[i]->bounds), &node->bounds);
          node->preferred_depth = gdk_memory_depth_merge (node->preferred_depth, children[i]->preferred_depth);
          node->clears_background |= gsk_render_node_clears_background (children[i]);
          node->is_hdr |= gsk_render_node_is_hdr (children[i]);
          node->copy_mode = MAX (node->copy_mode, gsk_render_node_get_copy_mode (children[i]));
          node->contains_subsurface_node |= gsk_render_node_contains_subsurface_node (children[i]);
          node->contains_paste_node |= gsk_render_node_contains_paste_node (children[i]);
        }

      if (gsk_container_node_can_cache_opacity (self))
        {
          GskOpacityData data = GSK_OPACITY_DATA_INIT_EMPTY (NULL);

          for (i = 0; i < self->n_children; i++)
            {
              gsk_render_node_render_opacity (self->children[i], &data);
            }
          self->opaque = data.opaque;

          node->fully_opaque = gsk_rect_contains_rect (&self->opaque, &node->bounds);
        }
   }

  return node;
}

/**
 * gsk_container_node_get_n_children:
 * @node: (type GskContainerNode): a container `GskRenderNode`
 *
 * Retrieves the number of direct children of @node.
 *
 * Returns: the number of children of the `GskRenderNode`
 */

guint
gsk_container_node_get_n_children (const GskRenderNode *node)
{
  const GskContainerNode *self = (const GskContainerNode *) node;

  return self->n_children;
}

/**
 * gsk_container_node_get_child:
 * @node: (type GskContainerNode): a container `GskRenderNode`
 * @idx: the position of the child to get
 *
 * Gets one of the children of @container.
 *
 * Returns: (transfer none): the @idx'th child of @container
 */

GskRenderNode *
gsk_container_node_get_child (const GskRenderNode *node,
                              guint                idx)
{
  const GskContainerNode *self = (const GskContainerNode *) node;

  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_CONTAINER_NODE), NULL);
  g_return_val_if_fail (idx < self->n_children, NULL);

  return self->children[idx];
}

/*< private>
 * gsk_container_node_is_disjoint:
 * @node: a container `GskRenderNode`
 *
 * Returns `TRUE` if it is known that the child nodes are not
 * overlapping. There is no guarantee that they do overlap
 * if this function return FALSE.
 *
 * Returns: `TRUE` if children don't overlap
 */

gboolean
gsk_container_node_is_disjoint (const GskRenderNode *node)
{
  const GskContainerNode *self = (const GskContainerNode *) node;

  return self->disjoint;
}


Messung V0.5 in Prozent
C=98 H=95 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


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