2018-02-16 04:32:32 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2018 Benjamin Otte
|
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*
|
|
|
|
* Authors: Benjamin Otte <otte@gnome.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "gdkpaintable.h"
|
|
|
|
|
2018-03-18 18:21:33 +00:00
|
|
|
#include "gdksnapshotprivate.h"
|
|
|
|
|
2018-04-24 01:17:23 +00:00
|
|
|
/* HACK: So we don't need to include any (not-yet-created) GSK or GTK headers */
|
|
|
|
void gtk_snapshot_push_debug (GdkSnapshot *snapshot,
|
|
|
|
const char *message,
|
|
|
|
...) G_GNUC_PRINTF (2, 3);
|
|
|
|
void gtk_snapshot_pop (GdkSnapshot *snapshot);
|
|
|
|
|
2018-02-16 04:32:32 +00:00
|
|
|
/**
|
2018-05-07 00:34:31 +00:00
|
|
|
* SECTION:gdkpaintable
|
2018-02-16 04:32:32 +00:00
|
|
|
* @Title: GdkPaintable
|
|
|
|
* @Short_description: An interface for a paintable region
|
|
|
|
* @See_also: #ClutterContent, #GtkImage, #GdkTexture, #GtkSnapshot
|
|
|
|
*
|
|
|
|
* #GdkPaintable is a simple interface used by GDK and GDK to represent
|
|
|
|
* objects that can be painted anywhere at any size without requiring any
|
|
|
|
* sort of layout. The interface is inspired by similar concepts elsewhere,
|
2019-02-04 08:53:22 +00:00
|
|
|
* such as [ClutterContent](https://developer.gnome.org/clutter/stable/ClutterContent.html),
|
|
|
|
* [HTML/CSS Paint Sources](https://www.w3.org/TR/css-images-4/#paint-source),
|
|
|
|
* or [SVG Paint Servers](https://www.w3.org/TR/SVG2/pservers.html).
|
2018-02-16 04:32:32 +00:00
|
|
|
*
|
|
|
|
* A #GdkPaintable can be snapshot at any time and size using
|
|
|
|
* gdk_paintable_snapshot(). How the paintable interprets that size and if it
|
|
|
|
* scales or centers itself into the given rectangle is implementation defined,
|
|
|
|
* though if you are implementing a #GdkPaintable and don't know what to do, it
|
|
|
|
* is suggested that you scale your paintable ignoring any potential aspect ratio.
|
|
|
|
*
|
|
|
|
* The contents that a #GdkPaintable produces may depend on the #GdkSnapshot passed
|
|
|
|
* to it. For example, paintables may decide to use more detailed images on higher
|
|
|
|
* resolution screens or when OpenGL is available. A #GdkPaintable will however
|
|
|
|
* always produce the same output for the same snapshot.
|
|
|
|
*
|
|
|
|
* A #GdkPaintable may change its contents, meaning that it will now produce a
|
|
|
|
* different output with the same snpashot. Once that happens, it will call
|
|
|
|
* gdk_paintable_invalidate_contents() which will emit the
|
|
|
|
* #GdkPaintable::invalidate-contents signal.
|
|
|
|
* If a paintable is known to never change its contents, it will set the
|
|
|
|
* %GDK_PAINTABLE_STATIC_CONTENT flag. If a consumer cannot deal with changing
|
|
|
|
* contents, it may call gdk_paintable_get_static_image() which will return a
|
|
|
|
* static paintable and use that.
|
|
|
|
*
|
|
|
|
* A paintable can report an intrinsic (or preferred) size or aspect ratio it
|
|
|
|
* wishes to be rendered at, though it doesn't have to. Consumers of the interface
|
|
|
|
* can use this information to layout thepaintable appropriately.
|
|
|
|
* Just like the contents, the size of a paintable can change. A paintable will
|
|
|
|
* indicate this by calling gdk_paintable_invalidate_size() which will emit the
|
|
|
|
* #GdkPaintable::invalidate-size signal.
|
|
|
|
* And just like for contents, if a paintable is known to never change its size,
|
|
|
|
* it will set the %GDK_PAINTABLE_STATIC_SIZE flag.
|
2018-05-07 00:34:31 +00:00
|
|
|
*
|
|
|
|
* Besides API for applications, there are some functions that are only
|
|
|
|
* useful for implementing subclasses and should not be used by applications:
|
|
|
|
* gdk_paintable_invalidate_contents(),
|
|
|
|
* gdk_paintable_invalidate_size(),
|
|
|
|
* gdk_paintable_new_empty().
|
2018-02-16 04:32:32 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
G_DEFINE_INTERFACE (GdkPaintable, gdk_paintable, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
enum {
|
|
|
|
INVALIDATE_CONTENTS,
|
|
|
|
INVALIDATE_SIZE,
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_paintable_default_snapshot (GdkPaintable *paintable,
|
|
|
|
GdkSnapshot *snapshot,
|
|
|
|
double width,
|
|
|
|
double height)
|
|
|
|
{
|
|
|
|
g_critical ("Paintable of type '%s' does not implement GdkPaintable::snapshot", G_OBJECT_TYPE_NAME (paintable));
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkPaintable *
|
|
|
|
gdk_paintable_default_get_current_image (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
g_warning ("FIXME: implement by snapshotting at default size and returning a GskRendererNodePaintable");
|
|
|
|
|
|
|
|
return paintable;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkPaintableFlags
|
|
|
|
gdk_paintable_default_get_flags (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gdk_paintable_default_get_intrinsic_width (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gdk_paintable_default_get_intrinsic_height (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static double gdk_paintable_default_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
int width, height;
|
|
|
|
|
|
|
|
width = gdk_paintable_get_intrinsic_width (paintable);
|
|
|
|
height = gdk_paintable_get_intrinsic_height (paintable);
|
|
|
|
|
|
|
|
if (width <= 0 || height <= 0)
|
|
|
|
return 0.0;
|
|
|
|
|
|
|
|
return (double) width / height;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_paintable_default_init (GdkPaintableInterface *iface)
|
|
|
|
{
|
|
|
|
iface->snapshot = gdk_paintable_default_snapshot;
|
|
|
|
iface->get_current_image = gdk_paintable_default_get_current_image;
|
|
|
|
iface->get_flags = gdk_paintable_default_get_flags;
|
|
|
|
iface->get_intrinsic_width = gdk_paintable_default_get_intrinsic_width;
|
|
|
|
iface->get_intrinsic_height = gdk_paintable_default_get_intrinsic_height;
|
|
|
|
iface->get_intrinsic_aspect_ratio = gdk_paintable_default_get_intrinsic_aspect_ratio;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GdkPaintable::invalidate-contents
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Emitted when the contents of the @paintable change.
|
|
|
|
*
|
|
|
|
* Examples for such an event would be videos changing to the next frame or
|
|
|
|
* the icon theme for an icon changing.
|
|
|
|
*/
|
|
|
|
signals[INVALIDATE_CONTENTS] =
|
|
|
|
g_signal_new ("invalidate-contents",
|
|
|
|
GDK_TYPE_PAINTABLE,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GdkPaintable::invalidate-size
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Emitted when the intrinsic size of the @paintable changes. This means the values
|
|
|
|
* reported by at least one of gdk_paintable_get_intrinsic_width(),
|
|
|
|
* gdk_paintable_get_intrinsic_height() or gdk_paintable_get_intrinsic_aspect_ratio()
|
|
|
|
* has changed.
|
|
|
|
*
|
|
|
|
* Examples for such an event would be a paintable displaying the contents of a toplevel
|
2018-03-20 14:14:10 +00:00
|
|
|
* surface being resized.
|
2018-02-16 04:32:32 +00:00
|
|
|
*/
|
|
|
|
signals[INVALIDATE_SIZE] =
|
|
|
|
g_signal_new ("invalidate-size",
|
|
|
|
GDK_TYPE_PAINTABLE,
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_snapshot:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
* @snapshot: a #GdkSnapshot to snapshot to
|
|
|
|
* @width: width to snapshot in
|
|
|
|
* @height: height to snapshot in
|
|
|
|
*
|
|
|
|
* Snapshots the given paintable with the given @width and @height at the
|
|
|
|
* current (0,0) offset of the @snapshot. If @width and @height are not larger
|
|
|
|
* than zero, this function will do nothing.
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-02-16 04:32:32 +00:00
|
|
|
void
|
|
|
|
gdk_paintable_snapshot (GdkPaintable *paintable,
|
|
|
|
GdkSnapshot *snapshot,
|
|
|
|
double width,
|
|
|
|
double height)
|
|
|
|
{
|
|
|
|
GdkPaintableInterface *iface;
|
|
|
|
|
|
|
|
g_return_if_fail (GDK_IS_PAINTABLE (paintable));
|
|
|
|
g_return_if_fail (snapshot != NULL);
|
|
|
|
|
|
|
|
if (width <= 0.0 || height <= 0.0)
|
|
|
|
return;
|
|
|
|
|
2018-04-24 01:17:23 +00:00
|
|
|
gtk_snapshot_push_debug (snapshot, "%s %p @ %gx%g", G_OBJECT_TYPE_NAME (paintable), paintable, width, height);
|
|
|
|
|
2018-02-16 04:32:32 +00:00
|
|
|
iface = GDK_PAINTABLE_GET_IFACE (paintable);
|
|
|
|
iface->snapshot (paintable, snapshot, width, height);
|
2018-04-24 01:17:23 +00:00
|
|
|
|
|
|
|
gtk_snapshot_pop (snapshot);
|
2018-02-16 04:32:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define GDK_PAINTABLE_IMMUTABLE (GDK_PAINTABLE_STATIC_SIZE | GDK_PAINTABLE_STATIC_CONTENTS)
|
|
|
|
static inline gboolean
|
|
|
|
gdk_paintable_is_immutable (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
return (gdk_paintable_get_flags (paintable) & GDK_PAINTABLE_IMMUTABLE) == GDK_PAINTABLE_IMMUTABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_get_current_image:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Gets an immutable paintable for the current contents displayed by @paintable.
|
|
|
|
*
|
|
|
|
* This is useful when you want to retain the current state of an animation, for
|
|
|
|
* example to take a screenshot of a running animation.
|
|
|
|
*
|
|
|
|
* If the @paintable is already immutable, it will return itself.
|
|
|
|
*
|
|
|
|
* Returns: (transfer full): An immutable paintable for the current
|
|
|
|
* contents of @paintable.
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-02-16 04:32:32 +00:00
|
|
|
GdkPaintable *
|
|
|
|
gdk_paintable_get_current_image (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
GdkPaintableInterface *iface;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), NULL);
|
|
|
|
|
|
|
|
if (gdk_paintable_is_immutable (paintable))
|
|
|
|
return g_object_ref (paintable);
|
|
|
|
|
|
|
|
iface = GDK_PAINTABLE_GET_IFACE (paintable);
|
|
|
|
return iface->get_current_image (paintable);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_get_flags:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Get flags for the paintable. This is oftentimes useful for optimizations.
|
|
|
|
*
|
|
|
|
* See #GdkPaintableFlags for the flags and what they mean.
|
|
|
|
*
|
|
|
|
* Returns: The #GdkPaintableFlags for this paintable.
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-02-16 04:32:32 +00:00
|
|
|
GdkPaintableFlags
|
|
|
|
gdk_paintable_get_flags (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
GdkPaintableInterface *iface;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), 0);
|
|
|
|
|
|
|
|
iface = GDK_PAINTABLE_GET_IFACE (paintable);
|
|
|
|
return iface->get_flags (paintable);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_get_intrinsic_width:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Gets the preferred width the @paintable would like to be displayed at.
|
|
|
|
* Consumers of this interface can use this to reserve enough space to draw
|
|
|
|
* the paintable.
|
|
|
|
*
|
|
|
|
* This is a purely informational value and does not in any way limit the values
|
|
|
|
* that may be passed to gdk_paintable_snapshot().
|
|
|
|
*
|
|
|
|
* If the @paintable does not have a preferred width, it returns 0. Negative
|
|
|
|
* values are never returned.
|
|
|
|
*
|
|
|
|
* Returns: the intrinsic width of @paintable or 0 if none.
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-02-16 04:32:32 +00:00
|
|
|
int
|
|
|
|
gdk_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
GdkPaintableInterface *iface;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), 0);
|
|
|
|
|
|
|
|
iface = GDK_PAINTABLE_GET_IFACE (paintable);
|
|
|
|
return iface->get_intrinsic_width (paintable);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_get_intrinsic_height:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Gets the preferred height the @paintable would like to be displayed at.
|
|
|
|
* Consumers of this interface can use this to reserve enough space to draw
|
|
|
|
* the paintable.
|
|
|
|
*
|
|
|
|
* This is a purely informational value and does not in any way limit the values
|
|
|
|
* that may be passed to gdk_paintable_snapshot().
|
|
|
|
*
|
|
|
|
* If the @paintable does not have a preferred height, it returns 0. Negative
|
|
|
|
* values are never returned.
|
|
|
|
*
|
|
|
|
* Returns: the intrinsic height of @paintable or 0 if none.
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-02-16 04:32:32 +00:00
|
|
|
int
|
|
|
|
gdk_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
GdkPaintableInterface *iface;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), 0);
|
|
|
|
|
|
|
|
iface = GDK_PAINTABLE_GET_IFACE (paintable);
|
|
|
|
return iface->get_intrinsic_height (paintable);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_get_intrinsic_aspect_ratio:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Gets the preferred aspect ratio the @paintable would like to be displayed at.
|
|
|
|
* The aspect ration is the width divided by the height, so a value of 0.5 means
|
|
|
|
* that the @paintable prefers to be displayed twice as high as it is wide.
|
|
|
|
* Consumers of this interface can use this to preserve aspect ratio when displaying
|
|
|
|
* this paintable.
|
|
|
|
*
|
|
|
|
* This is a purely informational value and does not in any way limit the values
|
|
|
|
* that may be passed to gdk_paintable_snapshot().
|
|
|
|
*
|
|
|
|
* Usually when a @paintable returns non-0 values from
|
|
|
|
* gdk_paintable_get_intrinsic_width() and gdk_paintable_get_intrinsic_height()
|
|
|
|
* the aspect ratio should conform to those values, though that is not required.
|
|
|
|
*
|
|
|
|
* If the @paintable does not have a preferred aspect ratio, it returns 0.0.
|
|
|
|
* Negative values are never returned.
|
|
|
|
*
|
|
|
|
* Returns: the intrinsic aspect ratio of @paintable or 0.0 if none.
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-02-16 04:32:32 +00:00
|
|
|
double
|
|
|
|
gdk_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
GdkPaintableInterface *iface;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), 0);
|
|
|
|
|
|
|
|
iface = GDK_PAINTABLE_GET_IFACE (paintable);
|
|
|
|
return iface->get_intrinsic_aspect_ratio (paintable);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_invalidate_contents:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Called by implementations of #GdkPaintable to invalidate their contents.
|
|
|
|
* Unless the contents are invalidated, implementations must guarantee that
|
|
|
|
* multiple calls to GdkPaintable::snapshot produce the same output.
|
|
|
|
*
|
|
|
|
* This function will emit the GdkPaintable::invalidate-contents signal.
|
|
|
|
*
|
|
|
|
* If a @paintable reports the %GDK_PAINTABLE_STATIC_CONTENTS flag,
|
|
|
|
* it must not call this function.
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-02-16 04:32:32 +00:00
|
|
|
void
|
|
|
|
gdk_paintable_invalidate_contents (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GDK_IS_PAINTABLE (paintable));
|
|
|
|
g_return_if_fail (!(gdk_paintable_get_flags (paintable) & GDK_PAINTABLE_STATIC_CONTENTS));
|
|
|
|
|
|
|
|
g_signal_emit (paintable, signals[INVALIDATE_CONTENTS], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_invalidate_size:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
*
|
|
|
|
* Called by implementations of #GdkPaintable to invalidate their size.
|
|
|
|
* As long as the size is not invalidated, @paintable must return the same values
|
|
|
|
* for its width, height and intrinsic height.
|
|
|
|
*
|
|
|
|
* This function will emit the GdkPaintable::invalidate-size signal.
|
|
|
|
*
|
|
|
|
* If a @paintable reports the %GDK_PAINTABLE_STATIC_SIZE flag,
|
|
|
|
* it must not call this function.
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-02-16 04:32:32 +00:00
|
|
|
void
|
|
|
|
gdk_paintable_invalidate_size (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GDK_IS_PAINTABLE (paintable));
|
|
|
|
g_return_if_fail (!(gdk_paintable_get_flags (paintable) & GDK_PAINTABLE_STATIC_SIZE));
|
|
|
|
|
|
|
|
g_signal_emit (paintable, signals[INVALIDATE_SIZE], 0);
|
|
|
|
}
|
2018-02-26 19:51:38 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_compute_concrete_size:
|
|
|
|
* @paintable: a #GdkPaintable
|
|
|
|
* @specified_width: the width @paintable could be drawn into or
|
|
|
|
* 0.0 if unknown
|
|
|
|
* @specified_height: the height @paintable could be drawn into or
|
|
|
|
* 0.0 if unknown
|
|
|
|
* @default_width: the width @paintable would be drawn into if
|
|
|
|
* no other constraints were given
|
|
|
|
* @default_height: the height @paintable would be drawn into if
|
|
|
|
* no other constraints were given
|
|
|
|
* @concrete_width: (out): will be set to the concrete width
|
|
|
|
* computed.
|
|
|
|
* @concrete_height: (out): will be set to the concrete height
|
|
|
|
* computed.
|
|
|
|
*
|
|
|
|
* Applies the sizing algorithm outlined in
|
|
|
|
* https://drafts.csswg.org/css-images-3/#default-sizing
|
|
|
|
* to the given @paintable. See that link for more details.
|
|
|
|
*
|
|
|
|
* It is not necessary to call this function when both @specified_width
|
|
|
|
* and @specified_height are known, but it is useful to call this
|
|
|
|
* function in GtkWidget:measure implementations to compute the
|
|
|
|
* other dimension when only one dimension is given.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gdk_paintable_compute_concrete_size (GdkPaintable *paintable,
|
|
|
|
double specified_width,
|
|
|
|
double specified_height,
|
|
|
|
double default_width,
|
|
|
|
double default_height,
|
|
|
|
double *concrete_width,
|
|
|
|
double *concrete_height)
|
|
|
|
{
|
|
|
|
double image_width, image_height, image_aspect;
|
|
|
|
|
|
|
|
g_return_if_fail (GDK_IS_PAINTABLE (paintable));
|
|
|
|
g_return_if_fail (specified_width >= 0);
|
|
|
|
g_return_if_fail (specified_height >= 0);
|
|
|
|
g_return_if_fail (default_width > 0);
|
|
|
|
g_return_if_fail (default_height > 0);
|
|
|
|
g_return_if_fail (concrete_width != NULL);
|
|
|
|
g_return_if_fail (concrete_height != NULL);
|
|
|
|
|
|
|
|
/* If the specified size is a definite width and height,
|
|
|
|
* the concrete object size is given that width and height.
|
|
|
|
*/
|
|
|
|
if (specified_width && specified_height)
|
|
|
|
{
|
|
|
|
*concrete_width = specified_width;
|
|
|
|
*concrete_height = specified_height;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
image_width = gdk_paintable_get_intrinsic_width (paintable);
|
|
|
|
image_height = gdk_paintable_get_intrinsic_height (paintable);
|
|
|
|
image_aspect = gdk_paintable_get_intrinsic_aspect_ratio (paintable);
|
|
|
|
|
|
|
|
/* If the specified size has neither a definite width nor height,
|
|
|
|
* and has no additional contraints, the dimensions of the concrete
|
|
|
|
* object size are calculated as follows:
|
|
|
|
*/
|
|
|
|
if (specified_width == 0.0 && specified_height == 0.0)
|
|
|
|
{
|
|
|
|
/* If the object has only an intrinsic aspect ratio,
|
|
|
|
* the concrete object size must have that aspect ratio,
|
|
|
|
* and additionally be as large as possible without either
|
|
|
|
* its height or width exceeding the height or width of the
|
|
|
|
* default object size.
|
|
|
|
*/
|
|
|
|
if (image_aspect > 0 && image_width == 0 && image_height == 0)
|
|
|
|
{
|
|
|
|
if (image_aspect * default_height > default_width)
|
|
|
|
{
|
|
|
|
*concrete_width = default_width;
|
|
|
|
*concrete_height = default_width / image_aspect;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*concrete_width = default_height * image_aspect;
|
|
|
|
*concrete_height = default_height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise, the width and height of the concrete object
|
|
|
|
* size is the same as the object's intrinsic width and
|
|
|
|
* intrinsic height, if they exist.
|
|
|
|
* If the concrete object size is still missing a width or
|
|
|
|
* height, and the object has an intrinsic aspect ratio,
|
|
|
|
* the missing dimension is calculated from the present
|
|
|
|
* dimension and the intrinsic aspect ratio.
|
|
|
|
* Otherwise, the missing dimension is taken from the default
|
|
|
|
* object size.
|
|
|
|
*/
|
|
|
|
if (image_width)
|
|
|
|
*concrete_width = image_width;
|
|
|
|
else if (image_aspect)
|
|
|
|
*concrete_width = image_height * image_aspect;
|
|
|
|
else
|
|
|
|
*concrete_width = default_width;
|
|
|
|
|
|
|
|
if (image_height)
|
|
|
|
*concrete_height = image_height;
|
|
|
|
else if (image_aspect)
|
|
|
|
*concrete_height = image_width / image_aspect;
|
|
|
|
else
|
|
|
|
*concrete_height = default_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the specified size has only a width or height, but not both,
|
|
|
|
* then the concrete object size is given that specified width or height.
|
|
|
|
* The other dimension is calculated as follows:
|
|
|
|
* If the object has an intrinsic aspect ratio, the missing dimension of
|
|
|
|
* the concrete object size is calculated using the intrinsic aspect-ratio
|
|
|
|
* and the present dimension.
|
|
|
|
* Otherwise, if the missing dimension is present in the object's intrinsic
|
|
|
|
* dimensions, the missing dimension is taken from the object's intrinsic
|
|
|
|
* dimensions.
|
|
|
|
* Otherwise, the missing dimension of the concrete object size is taken
|
|
|
|
* from the default object size.
|
|
|
|
*/
|
|
|
|
if (specified_width)
|
|
|
|
{
|
|
|
|
*concrete_width = specified_width;
|
|
|
|
if (image_aspect)
|
|
|
|
*concrete_height = specified_width / image_aspect;
|
|
|
|
else if (image_height)
|
|
|
|
*concrete_height = image_height;
|
|
|
|
else
|
|
|
|
*concrete_height = default_height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*concrete_height = specified_height;
|
|
|
|
if (image_aspect)
|
|
|
|
*concrete_width = specified_height * image_aspect;
|
|
|
|
else if (image_width)
|
|
|
|
*concrete_width = image_width;
|
|
|
|
else
|
|
|
|
*concrete_width = default_width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-02 05:55:02 +00:00
|
|
|
#define GDK_TYPE_EMPTY_PAINTABLE (gdk_empty_paintable_get_type())
|
|
|
|
static
|
|
|
|
G_DECLARE_FINAL_TYPE(GdkEmptyPaintable, gdk_empty_paintable, GDK, EMPTY_PAINTABLE, GObject)
|
|
|
|
|
|
|
|
struct _GdkEmptyPaintable
|
|
|
|
{
|
|
|
|
GObject parent_instance;
|
|
|
|
|
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _GdkEmptyPaintableClass
|
|
|
|
{
|
|
|
|
GObjectClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_empty_paintable_snapshot (GdkPaintable *paintable,
|
|
|
|
GdkSnapshot *snapshot,
|
|
|
|
double width,
|
|
|
|
double height)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkPaintableFlags
|
|
|
|
gdk_empty_paintable_get_flags (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
return GDK_PAINTABLE_STATIC_SIZE
|
|
|
|
| GDK_PAINTABLE_STATIC_CONTENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gdk_empty_paintable_get_intrinsic_width (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
GdkEmptyPaintable *self = GDK_EMPTY_PAINTABLE (paintable);
|
|
|
|
|
|
|
|
return self->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
gdk_empty_paintable_get_intrinsic_height (GdkPaintable *paintable)
|
|
|
|
{
|
|
|
|
GdkEmptyPaintable *self = GDK_EMPTY_PAINTABLE (paintable);
|
|
|
|
|
|
|
|
return self->height;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_empty_paintable_paintable_init (GdkPaintableInterface *iface)
|
|
|
|
{
|
|
|
|
iface->snapshot = gdk_empty_paintable_snapshot;
|
|
|
|
iface->get_flags = gdk_empty_paintable_get_flags;
|
|
|
|
iface->get_intrinsic_width = gdk_empty_paintable_get_intrinsic_width;
|
|
|
|
iface->get_intrinsic_height = gdk_empty_paintable_get_intrinsic_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GdkEmptyPaintable, gdk_empty_paintable, G_TYPE_OBJECT,
|
|
|
|
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
|
|
|
|
gdk_empty_paintable_paintable_init))
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_empty_paintable_class_init (GdkEmptyPaintableClass *klass)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_empty_paintable_init (GdkEmptyPaintable *self)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gdk_paintable_new_empty:
|
|
|
|
* @intrinsic_width: The intrinsic width to report. Can be 0 for no width.
|
|
|
|
* @intrinsic_height: The intrinsic height to report. Can be 0 for no height.
|
|
|
|
*
|
|
|
|
* Returns a paintable that has the given intrinsic size and draws nothing.
|
|
|
|
* This is often useful for implementing the GdkPaintableClass:get_current_image()
|
|
|
|
* virtual function when the paintable is in an incomplete state (like a
|
|
|
|
* #GtkMediaStream before receiving the first frame).
|
|
|
|
*
|
2018-04-06 14:20:48 +00:00
|
|
|
* Returns: (transfer full): a #GdkPaintable
|
2018-05-07 00:34:31 +00:00
|
|
|
*/
|
2018-04-02 05:55:02 +00:00
|
|
|
GdkPaintable *
|
|
|
|
gdk_paintable_new_empty (int intrinsic_width,
|
|
|
|
int intrinsic_height)
|
|
|
|
{
|
|
|
|
GdkEmptyPaintable *result;
|
|
|
|
|
2018-07-05 19:41:59 +00:00
|
|
|
g_return_val_if_fail (intrinsic_width >= 0, NULL);
|
|
|
|
g_return_val_if_fail (intrinsic_height >= 0, NULL);
|
2018-04-02 05:55:02 +00:00
|
|
|
|
|
|
|
result = g_object_new (GDK_TYPE_EMPTY_PAINTABLE, NULL);
|
|
|
|
|
|
|
|
result->width = intrinsic_width;
|
|
|
|
result->height = intrinsic_height;
|
|
|
|
|
|
|
|
return GDK_PAINTABLE (result);
|
|
|
|
}
|