paintable: Add gdk_paintable_compute_concrete_size()
authorBenjamin Otte <otte@redhat.com>
Mon, 26 Feb 2018 19:51:38 +0000 (20:51 +0100)
committerBenjamin Otte <otte@redhat.com>
Fri, 16 Mar 2018 05:04:44 +0000 (06:04 +0100)
Do the CSS size computation routine. This will be used elsewhere soon.

docs/reference/gdk/gdk4-sections.txt
gdk/gdkpaintable.c
gdk/gdkpaintable.h

index a1d5457772e7efc3dd11326868dbf14f646367f4..91c23004c6b8b1c7626ce475c9d8350b059017eb 100644 (file)
@@ -724,6 +724,7 @@ gdk_paintable_get_flags
 gdk_paintable_get_intrinsic_width
 gdk_paintable_get_intrinsic_height
 gdk_paintable_get_intrinsic_aspect_ratio
+gdk_paintable_compute_concrete_size
 gdk_paintable_invalidate_contents
 gdk_paintable_invalidate_size
 <SECTION>
index 617e3d2a213495b2676574d287967d392c43636e..eb317a82346d023c76072ec58a9c26788daafb64 100644 (file)
@@ -394,3 +394,151 @@ gdk_paintable_invalidate_size (GdkPaintable *paintable)
 
   g_signal_emit (paintable, signals[INVALIDATE_SIZE], 0);
 }
+
+/**
+ * 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;
+    }
+}
+
index 35135e2559e270bcf8cb7c0fe359734c3d7c54f7..99e4e83ff9ab30a2e088e13d4b08526365140bb9 100644 (file)
@@ -126,6 +126,14 @@ int             gdk_paintable_get_intrinsic_height      (GdkPaintable
 GDK_AVAILABLE_IN_ALL
 double          gdk_paintable_get_intrinsic_aspect_ratio(GdkPaintable           *paintable);
 
+GDK_AVAILABLE_IN_ALL
+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);
 /* for implementations only */
 GDK_AVAILABLE_IN_ALL
 void            gdk_paintable_invalidate_contents       (GdkPaintable           *paintable);