1/*
2 * Copyright © 2021 Benjamin Otte
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Benjamin Otte <otte@gnome.org>
18 */
19
20#include "config.h"
21
22#include "measuregraph.h"
23
24/* gdk_texture_new_for_surface() */
25#include "gdk/gdktextureprivate.h"
26
27#define MAX_SIZES 2048
28
29typedef struct _Size Size;
30struct _Size
31{
32 int min;
33 int nat;
34};
35
36struct _GtkInspectorMeasureGraph
37{
38 GObject parent_instance;
39
40 GdkPaintable *texture;
41 Size width;
42 Size height;
43 Size width_for_height[MAX_SIZES];
44 Size height_for_width[MAX_SIZES];
45};
46
47struct _GtkInspectorMeasureGraphClass
48{
49 GObjectClass parent_class;
50};
51
52static void
53gtk_inspector_measure_graph_ensure_texture (GtkInspectorMeasureGraph *self)
54{
55 int i, width, height;
56 cairo_surface_t *surface;
57 cairo_t *cr;
58
59 if (self->texture)
60 return;
61
62 if (self->width.nat == 0 || self->height.nat == 0)
63 {
64 self->texture = gdk_paintable_new_empty (intrinsic_width: 0, intrinsic_height: 0);
65 return;
66 }
67
68 width = self->width.nat;
69 for (i = 0; i < MAX_SIZES; i++)
70 width = MAX (width, self->width_for_height[i].nat);
71 width = MIN (width, MAX_SIZES);
72 height = self->height.nat;
73 for (i = 0; i < MAX_SIZES; i++)
74 height = MAX (height, self->height_for_width[i].nat);
75 height = MIN (height, MAX_SIZES);
76
77 surface = cairo_image_surface_create (format: CAIRO_FORMAT_ARGB32, width, height);
78 cr = cairo_create (target: surface);
79 cairo_set_operator (cr, op: CAIRO_OPERATOR_ADD);
80
81 cairo_set_source_rgba (cr, red: 0.5, green: 0, blue: 0, alpha: 1);
82 cairo_rectangle (cr, x: 0, y: 0, width: self->width.min, height);
83 cairo_fill (cr);
84 cairo_set_source_rgba (cr, red: 1, green: 0, blue: 0, alpha: 1);
85 for (i = self->width.min; i < width; i++)
86 cairo_rectangle (cr, x: i, y: 0, width: 1, height: self->height_for_width[i].min);
87 cairo_fill (cr);
88 cairo_set_source_rgba (cr, red: 1, green: 0, blue: 0, alpha: 0.3);
89 for (i = self->width.min; i < width; i++)
90 cairo_rectangle (cr, x: i, y: self->height_for_width[i].min, width: 1, height: self->height_for_width[i].nat - self->height_for_width[i].min);
91 cairo_fill (cr);
92
93 cairo_set_source_rgba (cr, red: 0, green: 0, blue: 0.5, alpha: 1);
94 cairo_rectangle (cr, x: 0, y: 0, width, height: self->height.min);
95 cairo_fill (cr);
96 cairo_set_source_rgba (cr, red: 0, green: 0, blue: 1, alpha: 1);
97 for (i = self->height.min; i < height; i++)
98 cairo_rectangle (cr, x: 0, y: i, width: self->width_for_height[i].min, height: 1);
99 cairo_fill (cr);
100 cairo_set_source_rgba (cr, red: 0, green: 0, blue: 1, alpha: 0.3);
101 for (i = self->height.min; i < height; i++)
102 cairo_rectangle (cr, x: self->width_for_height[i].min, y: i, width: self->width_for_height[i].nat - self->width_for_height[i].min, height: 1);
103 cairo_fill (cr);
104
105 cairo_set_operator (cr, op: CAIRO_OPERATOR_OVER);
106 cairo_set_source_rgba (cr, red: 0, green: 0, blue: 0, alpha: 1);
107 cairo_rectangle (cr, x: self->width.nat, y: 0, width: 1, height);
108 cairo_rectangle (cr, x: 0, y: self->height.nat, width, height: 1);
109 cairo_fill (cr);
110
111 cairo_destroy (cr);
112 self->texture = GDK_PAINTABLE (ptr: gdk_texture_new_for_surface (surface));
113 cairo_surface_destroy (surface);
114}
115
116static void
117gtk_inspector_measure_graph_paintable_snapshot (GdkPaintable *paintable,
118 GdkSnapshot *snapshot,
119 double width,
120 double height)
121{
122 GtkInspectorMeasureGraph *self = GTK_INSPECTOR_MEASURE_GRAPH (ptr: paintable);
123
124 gtk_inspector_measure_graph_ensure_texture (self);
125
126 if (self->texture == NULL)
127 return;
128
129 gdk_paintable_snapshot (paintable: self->texture, snapshot, width, height);
130}
131
132static int
133gtk_inspector_measure_graph_paintable_get_intrinsic_width (GdkPaintable *paintable)
134{
135 GtkInspectorMeasureGraph *self = GTK_INSPECTOR_MEASURE_GRAPH (ptr: paintable);
136
137 gtk_inspector_measure_graph_ensure_texture (self);
138
139 return gdk_paintable_get_intrinsic_width (paintable: self->texture);
140}
141
142static int
143gtk_inspector_measure_graph_paintable_get_intrinsic_height (GdkPaintable *paintable)
144{
145 GtkInspectorMeasureGraph *self = GTK_INSPECTOR_MEASURE_GRAPH (ptr: paintable);
146
147 gtk_inspector_measure_graph_ensure_texture (self);
148
149 return gdk_paintable_get_intrinsic_height (paintable: self->texture);
150}
151
152static double
153gtk_inspector_measure_graph_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
154{
155 GtkInspectorMeasureGraph *self = GTK_INSPECTOR_MEASURE_GRAPH (ptr: paintable);
156
157 gtk_inspector_measure_graph_ensure_texture (self);
158
159 return gdk_paintable_get_intrinsic_aspect_ratio (paintable: self->texture);
160}
161
162static void
163gtk_inspector_measure_graph_paintable_init (GdkPaintableInterface *iface)
164{
165 iface->snapshot = gtk_inspector_measure_graph_paintable_snapshot;
166 iface->get_intrinsic_width = gtk_inspector_measure_graph_paintable_get_intrinsic_width;
167 iface->get_intrinsic_height = gtk_inspector_measure_graph_paintable_get_intrinsic_height;
168 iface->get_intrinsic_aspect_ratio = gtk_inspector_measure_graph_paintable_get_intrinsic_aspect_ratio;
169}
170
171G_DEFINE_TYPE_EXTENDED (GtkInspectorMeasureGraph, gtk_inspector_measure_graph, G_TYPE_OBJECT, 0,
172 G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
173 gtk_inspector_measure_graph_paintable_init))
174
175static void
176gtk_inspector_measure_graph_dispose (GObject *object)
177{
178 GtkInspectorMeasureGraph *self = GTK_INSPECTOR_MEASURE_GRAPH (ptr: object);
179
180 g_clear_object (&self->texture);
181
182 G_OBJECT_CLASS (gtk_inspector_measure_graph_parent_class)->dispose (object);
183}
184
185static void
186gtk_inspector_measure_graph_class_init (GtkInspectorMeasureGraphClass *klass)
187{
188 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
189
190 gobject_class->dispose = gtk_inspector_measure_graph_dispose;
191}
192
193static void
194gtk_inspector_measure_graph_init (GtkInspectorMeasureGraph *self)
195{
196}
197
198GtkInspectorMeasureGraph *
199gtk_inspector_measure_graph_new (void)
200{
201 return g_object_new (GTK_TYPE_INSPECTOR_MEASURE_GRAPH, NULL);
202}
203
204void
205gtk_inspector_measure_graph_clear (GtkInspectorMeasureGraph *self)
206{
207 g_clear_object (&self->texture);
208
209 memset (s: &self->width, c: 0, n: sizeof (self->width));
210 memset (s: &self->height, c: 0, n: sizeof (self->height));
211 memset (s: &self->width_for_height, c: 0, n: sizeof (self->width_for_height));
212 memset (s: &self->height_for_width, c: 0, n: sizeof (self->height_for_width));
213
214 gdk_paintable_invalidate_size (paintable: GDK_PAINTABLE (ptr: self));
215 gdk_paintable_invalidate_contents (paintable: GDK_PAINTABLE (ptr: self));
216}
217
218void
219gtk_inspector_measure_graph_measure (GtkInspectorMeasureGraph *self,
220 GtkWidget *widget)
221{
222 int i;
223
224 g_clear_object (&self->texture);
225
226 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1, minimum: &self->width.min, natural: &self->width.nat, NULL, NULL);
227 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_VERTICAL, for_size: -1 ,minimum: &self->height.min, natural: &self->height.nat, NULL, NULL);
228
229 memset (s: &self->width_for_height, c: 0, n: sizeof (Size) * MIN (self->height.min, MAX_SIZES));
230 for (i = self->height.min; i < MAX_SIZES; i++)
231 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: i, minimum: &self->width_for_height[i].min, natural: &self->width_for_height[i].nat, NULL, NULL);
232 memset (s: &self->height_for_width, c: 0, n: sizeof (Size) * MIN (self->width.min, MAX_SIZES));
233 for (i = self->width.min; i < MAX_SIZES; i++)
234 gtk_widget_measure (widget, orientation: GTK_ORIENTATION_VERTICAL, for_size: i, minimum: &self->height_for_width[i].min, natural: &self->height_for_width[i].nat, NULL, NULL);
235
236 gdk_paintable_invalidate_size (paintable: GDK_PAINTABLE (ptr: self));
237 gdk_paintable_invalidate_contents (paintable: GDK_PAINTABLE (ptr: self));
238}
239
240GdkTexture *
241gtk_inspector_measure_graph_get_texture (GtkInspectorMeasureGraph *self)
242{
243 gtk_inspector_measure_graph_ensure_texture (self);
244
245 if (!GDK_IS_TEXTURE (self->texture))
246 return NULL;
247
248 return GDK_TEXTURE (self->texture);
249}
250
251

source code of gtk/gtk/inspector/measuregraph.c