Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  gskgpucachedstroke.c

  Sprache: C
 

#include "config.h"

#include "gskgpucachedstrokeprivate.h"

#include "gskgpucacheprivate.h"
#include "gskgpucachedprivate.h"
#include "gskgpudeviceprivate.h"
#include "gskgpuuploadopprivate.h"
#include "gskgpuutilsprivate.h"
#include "gskgpuprintprivate.h"
#include "gskgpuimageprivate.h"
#include "gskenumtypes.h"
#include "gskrectprivate.h"
#include "gskstrokeprivate.h"
#include "gskpathprivate.h"
#include "gsktransformprivate.h"

#include "gdk/gdkcolorstateprivate.h"
#include "gdk/gdkcolorprivate.h"
#include "gdk/gdkcairoprivate.h"

#include "gsk/gskprivate.h"

typedef struct _GskGpuCachedStroke GskGpuCachedStroke;

struct _GskGpuCachedStroke
{
  GskGpuCached parent;

  GskPath *path;
  GskStroke stroke;
  float sx, sy;

  /* Subpixel position of the stroke bounds wrt to device grid */
  guint fx, fy;

  GskGpuImage *image;
  graphene_point_t image_offset;
};

static void
gsk_gpu_cached_stroke_finalize (GskGpuCached *cached)
{
  GskGpuCachedStroke *self = (GskGpuCachedStroke *) cached;
  GskGpuCachePrivate *priv = gsk_gpu_cache_get_private (cached->cache);

  g_hash_table_remove (priv->stroke_cache, self);

  gsk_path_unref (self->path);
  gsk_stroke_clear (&self->stroke);
  g_object_unref (self->image);
}

static gboolean
gsk_gpu_cached_stroke_should_collect (GskGpuCached *cached,
                                      gint64        cache_timeout,
                                      gint64        timestamp)
{
  if (gsk_gpu_cached_is_old (cached, cache_timeout, timestamp))
    {
      if (cached->atlas)
        gsk_gpu_cached_set_stale (cached, TRUE);
      else
        return TRUE;
    }

  /* Strokes are only collected when their atlas is freed */
  return FALSE;
}

static guint
gsk_gpu_cached_stroke_hash (gconstpointer data)
{
  const GskGpuCachedStroke *self = data;

  /* We ignore dashes here */
  return GPOINTER_TO_UINT (self->path) ^
         ((guint) (self->stroke.line_width * 10)) ^
         (((guint) (self->stroke.miter_limit * 10)) << 4) ^
         (self->stroke.line_cap << 6) ^
         (self->stroke.line_join << 8) ^
         (((guint) (self->sx * 16)) << 16) ^
         ((guint) (self->sy * 16) << 8) ^
         (self->fx << 4) ^
         self->fy;
}

static gboolean
gsk_gpu_cached_stroke_equal (gconstpointer v1,
                             gconstpointer v2)
{
  const GskGpuCachedStroke *stroke1 = v1;
  const GskGpuCachedStroke *stroke2 = v2;

  return stroke1->fx == stroke2->fx &&
         stroke1->fy == stroke2->fy &&
         stroke1->path == stroke2->path &&
         stroke1->sx == stroke2->sx &&
         stroke1->sy == stroke2->sy &&
         gsk_stroke_equal (&stroke1->stroke, &stroke2->stroke);
}

static const GskGpuCachedClass GSK_GPU_CACHED_STROKE_CLASS =
{
  sizeof (GskGpuCachedStroke),
  "Stroke",
  FALSE,
  gsk_gpu_cached_print_no_stats,
  gsk_gpu_cached_stroke_finalize,
  gsk_gpu_cached_stroke_should_collect
};

typedef struct _StrokeData StrokeData;
struct _StrokeData
{
  GskPath *path;
  GskStroke stroke;
};

static void
stroke_data_free (gpointer data)
{
  StrokeData *stroke = data;

  gsk_path_unref (stroke->path);
  gsk_stroke_clear (&stroke->stroke);
  g_free (stroke);
}

static void
stroke_path (gpointer  data,
             cairo_t  *cr)
{
  StrokeData *stroke = data;

  cairo_set_source_rgba (cr, 1111);
  gsk_cairo_stroke_path (cr, stroke->path, &stroke->stroke);
}

static void
stroke_path_print (gpointer  data,
                   GString  *string)
{
  StrokeData *stroke = data;
  char *str;

  g_string_append_printf (string, "stroke %g ",
                          gsk_stroke_get_line_width (&stroke->stroke));
  gsk_gpu_print_enum (string, GSK_TYPE_LINE_CAP, gsk_stroke_get_line_cap (&stroke->stroke));
  gsk_gpu_print_enum (string, GSK_TYPE_LINE_JOIN, gsk_stroke_get_line_join (&stroke->stroke));
  g_string_append_printf (string, "%g ", gsk_stroke_get_miter_limit (&stroke->stroke));

  str = gsk_path_to_string (stroke->path);
  g_string_append_printf (string, "%.*s%s",
                          20, str, strlen (str) > 20 ? "…" : "");
  g_free (str);
}

static gsize
mod_subpixel (float  pos,
              float  scale,
              gsize  subpixel_scale,
              float *delta)
{
  scale *= subpixel_scale;
  pos = fmod (scale * pos, subpixel_scale);
  *delta = (ceil (pos) - pos) / scale;
  if (pos > 0.0)
    return subpixel_scale - (gsize) ceil (pos);
  else
    return (gsize) - ceil (pos);
}

static void
determine_scale_and_subpixel_grid (const graphene_size_t *scale,
                                   GskTransform           *modelview,
                                   float                  *sx,
                                   float                  *sy,
                                   size_t                 *subpixel_scale)
{
  if (gsk_transform_get_fine_category (modelview) <= GSK_FINE_TRANSFORM_CATEGORY_2D)
    {
      *sx = *sy = ceilf (MAX (scale->width, scale->height) + 0.5);
      *subpixel_scale = 1;
    }
  else
    {
      *sx = scale->width;
      *sy = scale->height;
      *subpixel_scale = 32;
    }
}

GskGpuImage *
gsk_gpu_cached_stroke_lookup (GskGpuCache           *self,
                              GskGpuFrame           *frame,
                              const graphene_size_t *scale,
                              const graphene_rect_t *bounds,
                              GskTransform          *modelview,
                              GskPath               *path,
                              const GskStroke       *stroke,
                              graphene_rect_t       *out_rect)
{
  GskGpuCachePrivate *priv = gsk_gpu_cache_get_private (self);
  float sx, sy, dx, dy;
  GskGpuCachedStroke *cached;
  gsize fx, fy, padding;
  cairo_rectangle_int_t area;
  GskGpuImage *image = NULL;
  graphene_rect_t viewport;
  size_t subpixel_scale;

  determine_scale_and_subpixel_grid (scale, modelview, &sx, &sy, &subpixel_scale);

  fx = mod_subpixel (bounds->origin.x, sx, subpixel_scale, &dx);
  fy = mod_subpixel (bounds->origin.y, sy, subpixel_scale, &dy);

  cached = g_hash_table_lookup (priv->stroke_cache,
                                &(GskGpuCachedStroke) {
                                  .path = path,
                                  .stroke = *stroke,
                                  .sx = sx,
                                  .sy = sy,
                                  .fx = fx,
                                  .fy = fy,
                                });
  if (cached)
    {
      gsk_gpu_cached_use ((GskGpuCached *) cached);

      graphene_rect_init (out_rect,
                          cached->image_offset.x - dx,
                          cached->image_offset.y - dy,
                          gsk_gpu_image_get_width (cached->image) / sx,
                          gsk_gpu_image_get_height (cached->image) / sy);

      return g_object_ref (cached->image);
    }

  if (!gsk_path_get_stroke_bounds (path, stroke, &viewport) ||
      !gsk_rect_snap_to_grid_grow (&viewport,
                                   scale,
                                   &GRAPHENE_POINT_INIT ((float) fx / (sx * subpixel_scale),
                                                         (float) fy / (sy * subpixel_scale)),
                                   &viewport))
    return NULL;

  padding = 1;

  /* Should already be integers because of snap_to_grid() above, but round just to be sure */
  cached = gsk_gpu_cached_new_from_atlas (self,
                                          &GSK_GPU_CACHED_STROKE_CLASS,
                                          round (sx * viewport.size.width) + 2 * padding,
                                          round (sy * viewport.size.height) + 2 * padding);

  if (cached)
    {
      image = gsk_gpu_cached_get_atlas_image ((GskGpuCached *) cached);
      area = *gsk_gpu_cached_get_atlas_area ((GskGpuCached *) cached);
      g_object_ref (image);
      cached->path = gsk_path_ref (path);
      cached->stroke = GSK_STROKE_INIT_COPY (stroke);
      cached->sx = sx;
      cached->sy = sy;
      cached->fx = fx;
      cached->fy = fy;
      cached->image = g_object_ref (image);
      graphene_rect_inset (&viewport, padding / -sx, padding / -sy);
      cached->image_offset = GRAPHENE_POINT_INIT (viewport.origin.x - area.x / sx,
                                                  viewport.origin.y - area.y / sy);

      ((GskGpuCached *) cached)->pixels = area.width * area.height;

      g_hash_table_insert (priv->stroke_cache, cached, cached);
      gsk_gpu_cached_use ((GskGpuCached *) cached);

    }
  else
    {
      /* If the unclipped path is too large to fit in the atlas,
       * we give up on caching. We still need to return a mask,
       * but we'll use the clipped bounds that we were given.
       * We'll also assume those are grid aligned.
       */

      viewport = *bounds;
      area.x = 0;
      area.y = 0;
      area.width = ceil (sx * viewport.size.width);
      area.height = ceil (sy * viewport.size.height);

      image = gsk_gpu_device_create_upload_image (gsk_gpu_cache_get_device (self),
                                                  FALSE,
                                                  GDK_MEMORY_DEFAULT,
                                                  gsk_gpu_color_state_get_conversion (GDK_COLOR_STATE_SRGB),
                                                  area.width,
                                                  area.height);
      if (image == NULL)
        return NULL;
    }

  gsk_gpu_upload_cairo_into_op (frame,
                                image,
                                &area,
                                &viewport,
                                stroke_path,
                                stroke_path_print,
                                g_memdup2 (&(StrokeData) {
                                  .path = gsk_path_ref (path),
                                  .stroke = GSK_STROKE_INIT_COPY (stroke),
                                }, sizeof (StrokeData)),
                                (GDestroyNotify) stroke_data_free);

  graphene_rect_init (out_rect,
                      viewport.origin.x - area.x / sx - dx,
                      viewport.origin.y - area.y / sy - dy,
                      gsk_gpu_image_get_width (image) / sx,
                      gsk_gpu_image_get_height (image) / sy);

  return image;
}

void
gsk_gpu_cached_stroke_init_cache (GskGpuCache *cache)
{
  GskGpuCachePrivate *priv = gsk_gpu_cache_get_private (cache);

  priv->stroke_cache = g_hash_table_new (gsk_gpu_cached_stroke_hash,
                                         gsk_gpu_cached_stroke_equal);
}

void
gsk_gpu_cached_stroke_finish_cache (GskGpuCache *cache)
{
  GskGpuCachePrivate *priv = gsk_gpu_cache_get_private (cache);

  g_hash_table_unref (priv->stroke_cache);
}

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

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