[mutter] clutter/text: Generate resource scaled text and paint it at proper scaling



commit af3662775eddc32bbc7265b5c176704563e676e9
Author: Marco Trevisan (Treviño) <mail 3v1n0 net>
Date:   Sat Sep 2 03:57:28 2017 +0200

    clutter/text: Generate resource scaled text and paint it at proper scaling
    
    When resource scale is set we need to generate a scaled PangoLayout (by adding
    a new scale attribute, or adjusting the one we already have according the
    resource scale), then it has to be painted with proper scaling matrix.
    
    So everything that has to do with PangoLayout has to be in real coordinates,
    then clutter logical coords multiplied by resource scaling.
    While the actual size of the layout is the one of the PangoLayout divided by
    resource scale.
    
    We map the text positions to logical coords by default, while using
    the pixel coordinates when painting.
    
    We fall back to scale 1 when calculating preferred size if no scale is
    known. The pango layout will not have set a layout scale attribute,
    meaning it'll be 1, thus we should just assume the layout scale is 1 here.
    Not doing so might result in the preferred size being 0x0 meaning the
    actor won't be laid out properly.
    
    Fixes https://gitlab.gnome.org/GNOME/mutter/issues/135
    
    https://bugzilla.gnome.org/show_bug.cgi?id=765011
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/3

 clutter/clutter/clutter-canvas.c |   2 +-
 clutter/clutter/clutter-text.c   | 365 ++++++++++++++++++++++++++++++---------
 clutter/tests/conform/text.c     |  13 ++
 3 files changed, 302 insertions(+), 78 deletions(-)
---
diff --git a/clutter/clutter/clutter-canvas.c b/clutter/clutter/clutter-canvas.c
index f49442b16..b0f1f080c 100644
--- a/clutter/clutter/clutter-canvas.c
+++ b/clutter/clutter/clutter-canvas.c
@@ -614,7 +614,7 @@ clutter_canvas_set_scale_factor (ClutterCanvas *canvas,
                                  float          scale)
 {
   g_return_if_fail (CLUTTER_IS_CANVAS (canvas));
-  g_return_if_fail (scale >= 1.0f);
+  g_return_if_fail (scale > 0.0f);
 
   if (canvas->priv->scale_factor != scale)
     {
diff --git a/clutter/clutter/clutter-text.c b/clutter/clutter/clutter-text.c
index 1642c79f6..b6f054863 100644
--- a/clutter/clutter/clutter-text.c
+++ b/clutter/clutter/clutter-text.c
@@ -144,15 +144,17 @@ struct _ClutterTextPrivate
    */
   gint x_pos;
 
-  /* the x position of the PangoLayout when in
-   * single line mode, to scroll the contents of the
+  /* the x position of the PangoLayout (in both physical and logical pixels)
+   * when in single line mode, to scroll the contents of the
    * text actor
    */
   gint text_x;
+  gint text_logical_x;
 
-  /* the y position of the PangoLayout, fixed to 0 by
-   * default for now */
+  /* the y position of the PangoLayout (in both physical and logical pixels),
+   * fixed to 0 by default for now */
   gint text_y;
+  gint text_logical_y;
 
   /* Where to draw the cursor */
   ClutterRect cursor_rect;
@@ -185,6 +187,9 @@ struct _ClutterTextPrivate
   ClutterInputContentHintFlags input_hints;
   ClutterInputContentPurpose input_purpose;
 
+  /* Signal handler for when the :resource-scale changes */
+  guint resource_scale_changed_id;
+
   /* bitfields */
   guint alignment               : 2;
   guint wrap                    : 1;
@@ -290,6 +295,33 @@ G_DECLARE_FINAL_TYPE (ClutterTextInputFocus, clutter_text_input_focus,
 G_DEFINE_TYPE (ClutterTextInputFocus, clutter_text_input_focus,
                CLUTTER_TYPE_INPUT_FOCUS)
 
+/* Utilities pango to (logical) pixels functions */
+static float
+pixels_to_pango (float px)
+{
+  return ceilf (px * (float) PANGO_SCALE);
+}
+
+static float
+logical_pixels_to_pango (float px,
+                         float scale)
+{
+  return pixels_to_pango (px * scale);
+}
+
+static float
+pango_to_pixels (float size)
+{
+  return ceilf (size / (float) PANGO_SCALE);
+}
+
+static float
+pango_to_logical_pixels (float size,
+                         float scale)
+{
+  return pango_to_pixels (size / scale);
+}
+
 static void
 clutter_text_input_focus_request_surrounding (ClutterInputFocus *focus)
 {
@@ -550,6 +582,41 @@ clutter_text_get_display_text (ClutterText *self)
     }
 }
 
+static void
+ensure_effective_pango_scale_attribute (ClutterText *self)
+{
+  float resource_scale;
+  ClutterTextPrivate *priv = self->priv;
+
+  if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (self), &resource_scale) ||
+      resource_scale == 1.0)
+    return;
+
+  if (priv->effective_attrs != NULL)
+    {
+      PangoAttrIterator *iter;
+      PangoAttribute *scale_attrib;
+      PangoAttrList *old_attributes;
+
+      old_attributes = priv->effective_attrs;
+      priv->effective_attrs = pango_attr_list_copy (priv->effective_attrs);
+      pango_attr_list_unref (old_attributes);
+
+      iter = pango_attr_list_get_iterator (priv->effective_attrs);
+      scale_attrib = pango_attr_iterator_get (iter, PANGO_ATTR_SCALE);
+
+      if (scale_attrib != NULL)
+        resource_scale *= ((PangoAttrFloat *) scale_attrib)->value;
+
+      pango_attr_iterator_destroy (iter);
+    }
+  else
+    priv->effective_attrs = pango_attr_list_new ();
+
+  pango_attr_list_change (priv->effective_attrs,
+                          pango_attr_scale_new (resource_scale));
+}
+
 static void
 set_effective_pango_attributes (ClutterText   *self,
                                 PangoAttrList *attributes)
@@ -568,6 +635,8 @@ set_effective_pango_attributes (ClutterText   *self,
     {
       g_clear_pointer (&priv->effective_attrs, pango_attr_list_unref);
     }
+
+  ensure_effective_pango_scale_attribute (self);
 }
 
 static inline void
@@ -836,6 +905,18 @@ clutter_text_direction_changed_cb (GObject    *gobject,
   /* no need to queue a relayout: set_text_direction() will do that for us */
 }
 
+static void
+clutter_text_resource_scale_changed_cb (GObject    *gobject,
+                                        GParamSpec *pspec)
+{
+  ClutterText *self = CLUTTER_TEXT (gobject);
+  ClutterTextPrivate *priv = self->priv;
+
+  g_clear_pointer (&priv->effective_attrs, pango_attr_list_unref);
+  clutter_text_dirty_cache (self);
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (gobject));
+}
+
 /*
  * clutter_text_create_layout:
  * @text: a #ClutterText
@@ -903,7 +984,7 @@ clutter_text_create_layout (ClutterText *text,
        !((priv->editable && priv->single_line_mode) ||
          (priv->ellipsize == PANGO_ELLIPSIZE_NONE && !priv->wrap))))
     {
-      width = allocation_width * 1024 + 0.5f;
+      width = pixels_to_pango (allocation_width);
     }
 
   /* Pango only uses height if ellipsization is enabled, so don't set
@@ -920,7 +1001,7 @@ clutter_text_create_layout (ClutterText *text,
       priv->ellipsize != PANGO_ELLIPSIZE_NONE &&
       !priv->single_line_mode)
     {
-      height = allocation_height * 1024 + 0.5f;
+      height = pixels_to_pango (allocation_height);
     }
 
   /* Search for a cached layout with the same width and keep
@@ -1017,6 +1098,37 @@ clutter_text_create_layout (ClutterText *text,
   return oldest_cache->layout;
 }
 
+static PangoLayout *
+create_text_layout_with_scale (ClutterText *text,
+                               gfloat       allocation_width,
+                               gfloat       allocation_height,
+                               gfloat       scale)
+{
+  if (allocation_width > 0)
+    allocation_width = roundf (allocation_width * scale);
+
+  if (allocation_height > 0)
+    allocation_height = roundf (allocation_height * scale);
+
+  return clutter_text_create_layout (text, allocation_width, allocation_height);
+}
+
+static PangoLayout *
+maybe_create_text_layout_with_resource_scale (ClutterText *text,
+                                              gfloat       allocation_width,
+                                              gfloat       allocation_height)
+{
+  float resource_scale;
+
+  if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (text), &resource_scale))
+    return NULL;
+
+  return create_text_layout_with_scale (text,
+                                        allocation_width,
+                                        allocation_height,
+                                        resource_scale);
+}
+
 /**
  * clutter_text_coords_to_position:
  * @self: a #ClutterText
@@ -1037,14 +1149,18 @@ clutter_text_coords_to_position (ClutterText *self,
   gint index_;
   gint px, py;
   gint trailing;
+  gfloat resource_scale;
 
   g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
 
+  if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (self), &resource_scale))
+    return 0;
+
   /* Take any offset due to scrolling into account, and normalize
    * the coordinates to PangoScale units
    */
-  px = (x - self->priv->text_x) * PANGO_SCALE;
-  py = (y - self->priv->text_y) * PANGO_SCALE;
+  px = logical_pixels_to_pango (x - self->priv->text_logical_x, resource_scale);
+  py = logical_pixels_to_pango (y - self->priv->text_logical_y, resource_scale);
 
   pango_layout_xy_to_index (clutter_text_get_layout (self),
                             px, py,
@@ -1053,26 +1169,12 @@ clutter_text_coords_to_position (ClutterText *self,
   return index_ + trailing;
 }
 
-/**
- * clutter_text_position_to_coords:
- * @self: a #ClutterText
- * @position: position in characters
- * @x: (out): return location for the X coordinate, or %NULL
- * @y: (out): return location for the Y coordinate, or %NULL
- * @line_height: (out): return location for the line height, or %NULL
- *
- * Retrieves the coordinates of the given @position.
- *
- * Return value: %TRUE if the conversion was successful
- *
- * Since: 1.0
- */
-gboolean
-clutter_text_position_to_coords (ClutterText *self,
-                                 gint         position,
-                                 gfloat      *x,
-                                 gfloat      *y,
-                                 gfloat      *line_height)
+static gboolean
+clutter_text_position_to_coords_internal (ClutterText *self,
+                                          gint         position,
+                                          gfloat      *x,
+                                          gfloat      *y,
+                                          gfloat      *line_height)
 {
   ClutterTextPrivate *priv;
   PangoRectangle rect;
@@ -1138,7 +1240,7 @@ clutter_text_position_to_coords (ClutterText *self,
 
   if (x)
     {
-      *x = (gfloat) rect.x / 1024.0f;
+      *x = pango_to_pixels (rect.x);
 
       /* Take any offset due to scrolling into account */
       if (priv->single_line_mode)
@@ -1146,14 +1248,58 @@ clutter_text_position_to_coords (ClutterText *self,
     }
 
   if (y)
-    *y = (gfloat) rect.y / 1024.0f;
+    *y = pango_to_pixels (rect.y);
 
   if (line_height)
-    *line_height = (gfloat) rect.height / 1024.0f;
+    *line_height = pango_to_pixels (rect.height);
 
   return TRUE;
 }
 
+/**
+ * clutter_text_position_to_coords:
+ * @self: a #ClutterText
+ * @position: position in characters
+ * @x: (out): return location for the X coordinate, or %NULL
+ * @y: (out): return location for the Y coordinate, or %NULL
+ * @line_height: (out): return location for the line height, or %NULL
+ *
+ * Retrieves the coordinates of the given @position.
+ *
+ * Return value: %TRUE if the conversion was successful
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_position_to_coords (ClutterText *self,
+                                 gint         position,
+                                 gfloat      *x,
+                                 gfloat      *y,
+                                 gfloat      *line_height)
+{
+  gfloat resource_scale;
+  gboolean ret;
+
+  g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
+
+  if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (self), &resource_scale))
+    return FALSE;
+
+  ret = clutter_text_position_to_coords_internal (self, position,
+                                                  x, y, line_height);
+
+  if (x)
+    *x /= resource_scale;
+
+  if (y)
+    *y /= resource_scale;
+
+  if (line_height)
+    *line_height /= resource_scale;
+
+  return ret;
+}
+
 static inline void
 update_cursor_location (ClutterText *self)
 {
@@ -1171,7 +1317,8 @@ update_cursor_location (ClutterText *self)
 }
 
 static inline void
-clutter_text_ensure_cursor_position (ClutterText *self)
+clutter_text_ensure_cursor_position (ClutterText *self,
+                                     float        scale)
 {
   ClutterTextPrivate *priv = self->priv;
   gfloat x, y, cursor_height;
@@ -1194,15 +1341,15 @@ clutter_text_ensure_cursor_position (ClutterText *self)
                 priv->preedit_set ? priv->preedit_cursor_pos : 0);
 
   x = y = cursor_height = 0;
-  clutter_text_position_to_coords (self, position,
-                                   &x, &y,
-                                   &cursor_height);
+  clutter_text_position_to_coords_internal (self, position,
+                                            &x, &y,
+                                            &cursor_height);
 
   clutter_rect_init (&cursor_rect,
                      x,
-                     y + CURSOR_Y_PADDING,
-                     priv->cursor_size,
-                     cursor_height - 2 * CURSOR_Y_PADDING);
+                     y + CURSOR_Y_PADDING * scale,
+                     priv->cursor_size * scale,
+                     cursor_height - 2 * CURSOR_Y_PADDING * scale);
 
   if (!clutter_rect_equals (&priv->cursor_rect, &cursor_rect))
     {
@@ -1625,6 +1772,12 @@ clutter_text_dispose (GObject *gobject)
       priv->direction_changed_id = 0;
     }
 
+  if (priv->resource_scale_changed_id)
+    {
+      g_signal_handler_disconnect (self, priv->resource_scale_changed_id);
+      priv->resource_scale_changed_id = 0;
+    }
+
   if (priv->settings_changed_id)
     {
       g_signal_handler_disconnect (clutter_get_default_backend (),
@@ -1677,6 +1830,7 @@ typedef void (* ClutterTextSelectionFunc) (ClutterText           *text,
 
 static void
 clutter_text_foreach_selection_rectangle (ClutterText              *self,
+                                          float                     scale,
                                           ClutterTextSelectionFunc  func,
                                           gpointer                  user_data)
 {
@@ -1728,9 +1882,9 @@ clutter_text_foreach_selection_rectangle (ClutterText              *self,
                                       &n_ranges);
       pango_layout_line_x_to_index (line, 0, &index_, NULL);
 
-      clutter_text_position_to_coords (self,
-                                       bytes_to_offset (utf8, index_),
-                                       NULL, &y, &height);
+      clutter_text_position_to_coords_internal (self,
+                                                bytes_to_offset (utf8, index_),
+                                                NULL, &y, &height);
 
       box.y1 = y;
       box.y2 = y + height;
@@ -1740,18 +1894,18 @@ clutter_text_foreach_selection_rectangle (ClutterText              *self,
           gfloat range_x;
           gfloat range_width;
 
-          range_x = ranges[i * 2] / PANGO_SCALE;
+          range_x = pango_to_pixels (ranges[i * 2]);
 
           /* Account for any scrolling in single line mode */
           if (priv->single_line_mode)
             range_x += priv->text_x;
 
 
-          range_width = ((gfloat) ranges[i * 2 + 1] - (gfloat) ranges[i * 2])
-                      / PANGO_SCALE;
-
+          range_width = pango_to_pixels (ranges[i * 2 + 1] - ranges[i * 2]);
           box.x1 = range_x;
-          box.x2 = ceilf (range_x + range_width + .5f);
+          box.x2 = ceilf (range_x + range_width);
+
+          clutter_actor_box_scale (&box, scale);
 
           func (self, &box, user_data);
         }
@@ -1770,6 +1924,14 @@ add_selection_rectangle_to_path (ClutterText           *text,
   cogl_path_rectangle (user_data, box->x1, box->y1, box->x2, box->y2);
 }
 
+static void
+clutter_text_foreach_selection_rectangle_prescaled (ClutterText              *self,
+                                                    ClutterTextSelectionFunc  func,
+                                                    gpointer                  user_data)
+{
+  clutter_text_foreach_selection_rectangle (self, 1.0f, func, user_data);
+}
+
 /* Draws the selected text, its background, and the cursor */
 static void
 selection_paint (ClutterText     *self,
@@ -1825,9 +1987,9 @@ selection_paint (ClutterText     *self,
       else
         color = &priv->text_color;
 
-      clutter_text_foreach_selection_rectangle (self,
-                                                add_selection_rectangle_to_path,
-                                                selection_path);
+      clutter_text_foreach_selection_rectangle_prescaled (self,
+                                                          add_selection_rectangle_to_path,
+                                                          selection_path);
 
       cogl_path_fill (selection_path);
 
@@ -2416,6 +2578,7 @@ clutter_text_paint (ClutterActor *self)
   guint n_chars;
   float alloc_width;
   float alloc_height;
+  float resource_scale;
 
   fb = cogl_get_draw_framebuffer ();
 
@@ -2425,8 +2588,6 @@ clutter_text_paint (ClutterActor *self)
   n_chars = clutter_text_buffer_get_length (get_buffer (text));
 
   clutter_actor_get_allocation_box (self, &alloc);
-  alloc_width = alloc.x2 - alloc.x1;
-  alloc_height = alloc.y2 - alloc.y1;
 
   if (G_UNLIKELY (default_color_pipeline == NULL))
     {
@@ -2459,7 +2620,8 @@ clutter_text_paint (ClutterActor *self)
       cogl_framebuffer_draw_rectangle (fb,
                                        color_pipeline,
                                        0, 0,
-                                       alloc_width, alloc_height);
+                                       clutter_actor_box_get_width (&alloc),
+                                       clutter_actor_box_get_height (&alloc));
 
       cogl_object_unref (color_pipeline);
     }
@@ -2472,6 +2634,12 @@ clutter_text_paint (ClutterActor *self)
       !clutter_text_should_draw_cursor (text))
     return;
 
+  if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (self), &resource_scale))
+    return;
+
+  clutter_actor_box_scale (&alloc, resource_scale);
+  clutter_actor_box_get_size (&alloc, &alloc_width, &alloc_height);
+
   if (priv->editable && priv->single_line_mode)
     layout = clutter_text_create_layout (text, -1, -1);
   else
@@ -2503,8 +2671,15 @@ clutter_text_paint (ClutterActor *self)
         }
     }
 
+  if (resource_scale != 1.0f)
+    {
+      float paint_scale = 1.0f / resource_scale;
+      cogl_framebuffer_push_matrix (fb);
+      cogl_framebuffer_scale (fb, paint_scale, paint_scale, 1.0f);
+    }
+
   if (clutter_text_should_draw_cursor (text))
-    clutter_text_ensure_cursor_position (text);
+    clutter_text_ensure_cursor_position (text, resource_scale);
 
   if (priv->editable && priv->single_line_mode)
     {
@@ -2518,7 +2693,7 @@ clutter_text_paint (ClutterActor *self)
       clip_set = TRUE;
 
       actor_width = alloc_width - 2 * TEXT_PADDING;
-      text_width  = logical_rect.width / PANGO_SCALE;
+      text_width  = pango_to_pixels (logical_rect.width);
 
       rtl = priv->resolved_direction == PANGO_DIRECTION_RTL;
 
@@ -2575,8 +2750,10 @@ clutter_text_paint (ClutterActor *self)
     {
       priv->text_x = text_x;
       priv->text_y = text_y;
+      priv->text_logical_x = roundf ((float) text_x / resource_scale);
+      priv->text_logical_y = roundf ((float) text_y / resource_scale);
 
-      clutter_text_ensure_cursor_position (text);
+      clutter_text_ensure_cursor_position (text, resource_scale);
     }
 
   real_opacity = clutter_actor_get_paint_opacity (self)
@@ -2595,6 +2772,9 @@ clutter_text_paint (ClutterActor *self)
 
   selection_paint (text, fb);
 
+  if (resource_scale != 1.0f)
+    cogl_framebuffer_pop_matrix (fb);
+
   if (clip_set)
     cogl_framebuffer_pop_clip (fb);
 }
@@ -2624,26 +2804,32 @@ add_selection_to_paint_volume (ClutterText           *text,
 
 static void
 clutter_text_get_paint_volume_for_cursor (ClutterText        *text,
+                                          float               resource_scale,
                                           ClutterPaintVolume *volume)
 {
   ClutterTextPrivate *priv = text->priv;
   ClutterVertex origin;
 
-  clutter_text_ensure_cursor_position (text);
+  clutter_text_ensure_cursor_position (text, resource_scale);
 
   if (priv->position == priv->selection_bound)
     {
-      origin.x = priv->cursor_rect.origin.x;
-      origin.y = priv->cursor_rect.origin.y;
+      float width, height;
+
+      width = priv->cursor_rect.size.width / resource_scale;
+      height = priv->cursor_rect.size.height / resource_scale;
+      origin.x = priv->cursor_rect.origin.x / resource_scale;
+      origin.y = priv->cursor_rect.origin.y / resource_scale;
       origin.z = 0;
 
       clutter_paint_volume_set_origin (volume, &origin);
-      clutter_paint_volume_set_width (volume, priv->cursor_rect.size.width);
-      clutter_paint_volume_set_height (volume, priv->cursor_rect.size.height);
+      clutter_paint_volume_set_width (volume, width);
+      clutter_paint_volume_set_height (volume, height);
     }
   else
     {
       clutter_text_foreach_selection_rectangle (text,
+                                                1.0f / resource_scale,
                                                 add_selection_to_paint_volume,
                                                 volume);
     }
@@ -2666,6 +2852,7 @@ clutter_text_get_paint_volume (ClutterActor       *self,
       PangoLayout *layout;
       PangoRectangle ink_rect;
       ClutterVertex origin;
+      float resource_scale;
 
       /* If the text is single line editable then it gets clipped to
          the allocation anyway so we can just use that */
@@ -2680,19 +2867,24 @@ clutter_text_get_paint_volume (ClutterActor       *self,
       if (!clutter_actor_has_allocation (self))
         return FALSE;
 
+      if (!clutter_actor_get_resource_scale (self, &resource_scale))
+        return FALSE;
+
       _clutter_paint_volume_init_static (&priv->paint_volume, self);
 
       layout = clutter_text_get_layout (text);
       pango_layout_get_extents (layout, &ink_rect, NULL);
 
-      origin.x = ink_rect.x / (float) PANGO_SCALE;
-      origin.y = ink_rect.y / (float) PANGO_SCALE;
+      origin.x = pango_to_logical_pixels (ink_rect.x, resource_scale);
+      origin.y = pango_to_logical_pixels (ink_rect.y, resource_scale);
       origin.z = 0;
       clutter_paint_volume_set_origin (&priv->paint_volume, &origin);
       clutter_paint_volume_set_width (&priv->paint_volume,
-                                      ink_rect.width / (float) PANGO_SCALE);
+                                      pango_to_logical_pixels (ink_rect.width,
+                                                               resource_scale));
       clutter_paint_volume_set_height (&priv->paint_volume,
-                                       ink_rect.height / (float) PANGO_SCALE);
+                                       pango_to_logical_pixels (ink_rect.height,
+                                                                resource_scale));
 
       /* If the cursor is visible then that will likely be drawn
          outside of the ink rectangle so we should merge that in */
@@ -2702,7 +2894,8 @@ clutter_text_get_paint_volume (ClutterActor       *self,
 
           _clutter_paint_volume_init_static (&cursor_paint_volume, self);
 
-          clutter_text_get_paint_volume_for_cursor (text, &cursor_paint_volume);
+          clutter_text_get_paint_volume_for_cursor (text, resource_scale,
+                                                    &cursor_paint_volume);
 
           clutter_paint_volume_union (&priv->paint_volume,
                                       &cursor_paint_volume);
@@ -2730,9 +2923,12 @@ clutter_text_get_preferred_width (ClutterActor *self,
   PangoLayout *layout;
   gint logical_width;
   gfloat layout_width;
+  gfloat resource_scale;
 
-  layout = clutter_text_create_layout (text, -1, -1);
+  if (!clutter_actor_get_resource_scale (self, &resource_scale))
+    resource_scale = 1;
 
+  layout = clutter_text_create_layout (text, -1, -1);
   pango_layout_get_extents (layout, NULL, &logical_rect);
 
   /* the X coordinate of the logical rectangle might be non-zero
@@ -2742,7 +2938,7 @@ clutter_text_get_preferred_width (ClutterActor *self,
   logical_width = logical_rect.x + logical_rect.width;
 
   layout_width = logical_width > 0
-    ? ceilf (logical_width / 1024.0f)
+    ? pango_to_logical_pixels (logical_width, resource_scale)
     : 1;
 
   if (min_width_p)
@@ -2784,12 +2980,16 @@ clutter_text_get_preferred_height (ClutterActor *self,
       PangoRectangle logical_rect = { 0, };
       gint logical_height;
       gfloat layout_height;
+      gfloat resource_scale;
+
+      if (!clutter_actor_get_resource_scale (self, &resource_scale))
+        resource_scale = 1;
 
       if (priv->single_line_mode)
         for_width = -1;
 
-      layout = clutter_text_create_layout (CLUTTER_TEXT (self),
-                                           for_width, -1);
+      layout = create_text_layout_with_scale (CLUTTER_TEXT (self),
+                                              for_width, -1, resource_scale);
 
       pango_layout_get_extents (layout, NULL, &logical_rect);
 
@@ -2798,7 +2998,7 @@ clutter_text_get_preferred_height (ClutterActor *self,
        * the height accordingly
        */
       logical_height = logical_rect.y + logical_rect.height;
-      layout_height = ceilf (logical_height / 1024.0f);
+      layout_height = pango_to_logical_pixels (logical_height, resource_scale);
 
       if (min_height_p)
         {
@@ -2814,7 +3014,8 @@ clutter_text_get_preferred_height (ClutterActor *self,
               pango_layout_line_get_extents (line, NULL, &logical_rect);
 
               logical_height = logical_rect.y + logical_rect.height;
-              line_height = ceilf (logical_height / 1024.0f);
+              line_height = pango_to_logical_pixels (logical_height,
+                                                     resource_scale);
 
               *min_height_p = line_height;
             }
@@ -2845,9 +3046,9 @@ clutter_text_allocate (ClutterActor           *self,
   if (text->priv->editable && text->priv->single_line_mode)
     clutter_text_create_layout (text, -1, -1);
   else
-    clutter_text_create_layout (text,
-                                box->x2 - box->x1,
-                                box->y2 - box->y1);
+    maybe_create_text_layout_with_resource_scale (text,
+                                                  box->x2 - box->x1,
+                                                  box->y2 - box->y1);
 
   parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
   parent_class->allocate (self, box, flags);
@@ -4418,6 +4619,11 @@ clutter_text_init (ClutterText *self)
                       NULL);
 
   priv->input_focus = clutter_text_input_focus_new (self);
+
+  priv->resource_scale_changed_id =
+    g_signal_connect (self, "notify::resource-scale",
+                      G_CALLBACK (clutter_text_resource_scale_changed_cb),
+                      NULL);
 }
 
 /**
@@ -5528,6 +5734,7 @@ clutter_text_set_markup (ClutterText *self,
 PangoLayout *
 clutter_text_get_layout (ClutterText *self)
 {
+  PangoLayout *layout;
   gfloat width, height;
 
   g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
@@ -5536,8 +5743,12 @@ clutter_text_get_layout (ClutterText *self)
     return clutter_text_create_layout (self, -1, -1);
 
   clutter_actor_get_size (CLUTTER_ACTOR (self), &width, &height);
+  layout = maybe_create_text_layout_with_resource_scale (self, width, height);
 
-  return clutter_text_create_layout (self, width, height);
+  if (!layout)
+    layout = clutter_text_create_layout (self, width, height);
+
+  return layout;
 }
 
 /**
@@ -6541,10 +6752,10 @@ clutter_text_get_layout_offsets (ClutterText *self,
   priv = self->priv;
 
   if (x != NULL)
-    *x = priv->text_x;
+    *x = priv->text_logical_x;
 
   if (y != NULL)
-    *y = priv->text_y;
+    *y = priv->text_logical_y;
 }
 
 /**
diff --git a/clutter/tests/conform/text.c b/clutter/tests/conform/text.c
index 30101ce34..cef99023e 100644
--- a/clutter/tests/conform/text.c
+++ b/clutter/tests/conform/text.c
@@ -468,6 +468,19 @@ validate_markup_attributes (ClutterText   *text,
 
       a = attributes->data;
 
+      if (a->klass->type == PANGO_ATTR_SCALE)
+        {
+          PangoAttrFloat *scale = (PangoAttrFloat*) a;
+          float resource_scale;
+
+          if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (text), &resource_scale))
+            resource_scale = 1.0;
+
+          g_assert_cmpfloat (scale->value, ==, resource_scale);
+          g_slist_free_full (attributes, (GDestroyNotify) pango_attribute_destroy);
+          continue;
+        }
+
       g_assert (a->klass->type == attr_type);
       g_assert_cmpint (a->start_index, ==, start_index);
       g_assert_cmpint (a->end_index, ==, end_index);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]