Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  svgpaintable.c

  Sprache: C
 

/*
 * Copyright (c) 2025 RedHat, 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.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/>.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */


#include "svgpaintable.h"

#include <gtk/gtk.h>
#include <librsvg/rsvg.h>

/**
 * SvgPaintable:
 *
 * An opaque object that implements the GdkPaintable interface.
 */

struct _SvgPaintable
{
  GObject parent_instance;
  GFile *file;
  GskRenderNode *node;
  double width;
  double height;
};

struct _SvgPaintableClass
{
  GObjectClass parent_class;
};

enum {
  PROP_FILE = 1,
  NUM_PROPERTIES
};

static GParamSpec *props[NUM_PROPERTIES] = { NULL, };

/* {{{ Utilities */

/* Like gtk_snapshot_append_node, but transforms the node
 * to map the @from rect to the @to rect.
 */

static void
gtk_snapshot_append_node_scaled (GtkSnapshot     *snapshot,
                                 GskRenderNode   *node,
                                 graphene_rect_t *from,
                                 graphene_rect_t *to)
{
  if (graphene_rect_equal (from, to))
    {
      gtk_snapshot_append_node (snapshot, node);
    }
  else
    {
      gtk_snapshot_save (snapshot);
      gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (to->origin.x,
                                                              to->origin.y));
      gtk_snapshot_scale (snapshot, to->size.width / from->size.width,
                                    to->size.height / from->size.height);
      gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- from->origin.x,
                                                              - from->origin.y));
      gtk_snapshot_append_node (snapshot, node);
      gtk_snapshot_restore (snapshot);
    }
}

/* }}} */
/* {{{ SVG Handling */

static GskRenderNode *
render_node_from_svg (GFile  *file,
                      double *out_width,
                      double *out_height)
{
  RsvgHandle *handle;
  double width, height;
  GskRenderNode *node;
  cairo_t *cr;
  GError *error = NULL;

  handle = rsvg_handle_new_from_gfile_sync (file,
                                            RSVG_HANDLE_FLAGS_NONE,
                                            NULL,
                                            &error);
  if (!handle)
    {
      g_warning ("Failed to load SVG file: %s", error->message);
      g_clear_error (&error);
      return NULL;
    }

  if (!rsvg_handle_get_intrinsic_size_in_pixels (handle, &width, &height))
    {
      gboolean has_viewbox;
      RsvgRectangle viewbox;

      rsvg_handle_get_intrinsic_dimensions (handle,
                                            NULL, NULL, NULL, NULL,
                                            &has_viewbox,
                                            &viewbox);

      if (has_viewbox)
        {
          width = viewbox.width;
          height = viewbox.height;
        }
      else
        {
          g_warning ("SVG without intrinsic size or viewbox");
          g_object_unref (handle);
          return NULL;
        }
    }

  node = gsk_cairo_node_new (&GRAPHENE_RECT_INIT (00, width, height));
  cr = gsk_cairo_node_get_draw_context (node);

  if (!rsvg_handle_render_document (handle,
                                    cr,
                                    &(RsvgRectangle) { 00, width, height },
                                    &error))
    {
      g_warning ("Failed to render SVG: %s", error->message);
      g_clear_error (&error);
      g_clear_pointer (&node, gsk_render_node_unref);
    }

  cairo_destroy (cr);
  g_object_unref (handle);

  *out_width = width;
  *out_height = height;

  return node;
}

/* }}} */
/* {{{ GdkPaintable implementation */

static void
svg_paintable_snapshot (GdkPaintable *paintable,
                        GdkSnapshot  *snapshot,
                        double        width,
                        double        height)
{
  SvgPaintable *self = SVG_PAINTABLE (paintable);
  double render_width;
  double render_height;
  graphene_rect_t icon_rect;
  graphene_rect_t render_rect;

  if (!self->file)
    return;

  if (self->width >= self->height)
    {
      render_width = width;
      render_height = height * (self->height / self->width);
    }
  else
    {
      render_width = width * (self->width / self->height);
      render_height = height;
    }

  graphene_rect_init (&icon_rect, 00, self->width, self->height);
  graphene_rect_init (&render_rect,
                      (width - render_width) / 2,
                      (height - render_height) / 2,
                      render_width,
                      render_height);

  if (!self->node)
    {
      gtk_snapshot_append_color (snapshot, &(GdkRGBA) { 238/255.0106/255.0167/255.0,  1 }, &GRAPHENE_RECT_INIT (00, width, height));
    }
  else
    {
      gtk_snapshot_append_node_scaled (snapshot, self->node, &icon_rect, &render_rect);
    }
}

static int
svg_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
  return ceil (SVG_PAINTABLE (paintable)->width);
}

static int
svg_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
  return ceil (SVG_PAINTABLE (paintable)->height);
}

static void
svg_paintable_init_interface (GdkPaintableInterface *iface)
{
  iface->snapshot = svg_paintable_snapshot;
  iface->get_intrinsic_width = svg_paintable_get_intrinsic_width;
  iface->get_intrinsic_height = svg_paintable_get_intrinsic_height;
}

/* }}} */ 
/* {{{ GObject boilerplate */

G_DEFINE_TYPE_WITH_CODE (SvgPaintable, svg_paintable, G_TYPE_OBJECT,
                         G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
                                                svg_paintable_init_interface))

static void
svg_paintable_init (SvgPaintable *self)
{
}

static void
svg_paintable_dispose (GObject *object)
{
  SvgPaintable *self = SVG_PAINTABLE (object);

  g_clear_object (&self->file);
  g_clear_pointer (&self->node, gsk_render_node_unref);

  G_OBJECT_CLASS (svg_paintable_parent_class)->dispose (object);
}

static void
svg_paintable_set_property (GObject      *object,
                            guint         prop_id,
                            const GValue *value,
                            GParamSpec   *pspec)
{
  SvgPaintable *self = SVG_PAINTABLE (object);

  switch (prop_id)
    {
    case PROP_FILE:
      g_set_object (&self->file, g_value_get_object (value));
      g_clear_pointer (&self->node, gsk_render_node_unref);
      if (self->file)
        self->node = render_node_from_svg (self->file,
                                           &self->width,
                                           &self->height);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
svg_paintable_get_property (GObject    *object,
                            guint       prop_id,
                            GValue     *value,
                            GParamSpec *pspec)
{
  SvgPaintable *self = SVG_PAINTABLE (object);

  switch (prop_id)
    {
    case PROP_FILE:
      g_value_set_object (value, self->file);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}


static void
svg_paintable_class_init (SvgPaintableClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);

  object_class->dispose = svg_paintable_dispose;
  object_class->set_property = svg_paintable_set_property;
  object_class->get_property = svg_paintable_get_property;

  props[PROP_FILE] = g_param_spec_object ("file", NULL, NULL,
                                          G_TYPE_FILE,
                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);

  g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
}

/* }}} */
/* {{{ Public API */

/**
 * svg_paintable_new:
 * @file: the file
 *
 * Creates a paintable that will draw the SVG image contained
 * in @file, preserving its aspect ratio. The intrinsic size
 * of the paintable is the intrinsic size of the SVG.
 *
 * Returns: a paintable
 */

SvgPaintable *
svg_paintable_new (GFile *file)
{
  return g_object_new (SVG_TYPE_PAINTABLE,
                       "file", file,
                       NULL);
}

/* }}} */

/* vim:set foldmethod=marker: */

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

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