]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtklabel.c
Merge branch 'native-layout-incubator'
[~andy/gtk] / gtk / gtklabel.c
index 865d8f4af9f889019f7d913e0f95d2dc10cf06d7..60ea406bc4fa26fbc1d656aaf3e9d429c6776291 100644 (file)
@@ -59,7 +59,7 @@ typedef struct
   gint wrap_width;
   gint width_chars;
   gint max_width_chars;
-  gboolean full_size;
+
   gboolean mnemonics_visible;
 } GtkLabelPrivate;
 
@@ -151,10 +151,14 @@ enum {
   PROP_SINGLE_LINE_MODE,
   PROP_ANGLE,
   PROP_MAX_WIDTH_CHARS,
-  PROP_TRACK_VISITED_LINKS,
-  PROP_FULL_SIZE
+  PROP_TRACK_VISITED_LINKS
 };
 
+/* When rotating ellipsizable text we want the natural size to request 
+ * more to ensure the label wont ever ellipsize in an allocation of full natural size.
+ * */
+#define ROTATION_ELLIPSIZE_PADDING 2
+
 static guint signals[LAST_SIGNAL] = { 0 };
 
 static const GdkColor default_link_color = { 0, 0, 0, 0xeeee };
@@ -236,7 +240,7 @@ static void gtk_label_ensure_select_info  (GtkLabel *label);
 static void gtk_label_clear_select_info   (GtkLabel *label);
 static void gtk_label_update_cursor       (GtkLabel *label);
 static void gtk_label_clear_layout        (GtkLabel *label);
-static void gtk_label_ensure_layout       (GtkLabel *label);
+static void gtk_label_ensure_layout       (GtkLabel *label, gboolean guess_wrap_width);
 static void gtk_label_invalidate_wrap_width (GtkLabel *label);
 static void gtk_label_select_region_index (GtkLabel *label,
                                            gint      anchor_index,
@@ -301,22 +305,22 @@ static void          gtk_label_get_link_colors  (GtkWidget  *widget,
 static void          emit_activate_link         (GtkLabel     *label,
                                                  GtkLabelLink *link);
 
-static void gtk_label_layout_interface_init (GtkExtendedLayoutIface *iface);
-
-static void gtk_label_get_desired_width     (GtkExtendedLayout      *layout,
-                                             gint                   *minimum_size,
-                                             gint                   *natural_size);
-static void gtk_label_get_desired_height    (GtkExtendedLayout      *layout,
-                                             gint                   *minimum_size,
-                                             gint                   *natural_size);
-static void gtk_label_get_width_for_height  (GtkExtendedLayout      *layout,
-                                             gint                    height,
-                                             gint                   *minimum_width,
-                                             gint                   *natural_width);
-static void gtk_label_get_height_for_width  (GtkExtendedLayout      *layout,
-                                             gint                    width,
-                                             gint                   *minimum_height,
-                                             gint                   *natural_height);
+static void     gtk_label_extended_layout_init  (GtkExtendedLayoutIface *iface);
+static gboolean gtk_label_is_height_for_width   (GtkExtendedLayout      *layout);
+static void     gtk_label_get_desired_width     (GtkExtendedLayout      *layout,
+                                                gint                   *minimum_size,
+                                                gint                   *natural_size);
+static void     gtk_label_get_desired_height    (GtkExtendedLayout      *layout,
+                                                gint                   *minimum_size,
+                                                gint                   *natural_size);
+static void     gtk_label_get_width_for_height  (GtkExtendedLayout      *layout,
+                                                gint                    height,
+                                                gint                   *minimum_width,
+                                                gint                   *natural_width);
+static void     gtk_label_get_height_for_width  (GtkExtendedLayout      *layout,
+                                                gint                    width,
+                                                gint                   *minimum_height,
+                                                gint                   *natural_height);
 
 static GQuark quark_angle = 0;
 
@@ -326,7 +330,7 @@ G_DEFINE_TYPE_WITH_CODE (GtkLabel, gtk_label, GTK_TYPE_MISC,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                gtk_label_buildable_interface_init)
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
-                                                gtk_label_layout_interface_init));
+                                                gtk_label_extended_layout_init));
 
 static void
 add_move_binding (GtkBindingSet  *binding_set,
@@ -661,12 +665,13 @@ gtk_label_class_init (GtkLabelClass *class)
 
   /**
    * GtkLabel:width-chars:
-   * 
+   *
    * The desired width of the label, in characters. If this property is set to
-   * -1, the width will be calculated automatically, otherwise the label will
-   * request either 3 characters or the property value, whichever is greater.
-   * If the "width-chars" property is set to a positive value, then the 
-   * #GtkLabel:max-width-chars property is ignored. 
+   * -1, the width will be calculated automatically.
+   *
+   * See the section on <link linkend="label-text-layout">text layout</link>
+   * for details of how #GtkLabel:width-chars and #GtkLabel:max-width-chars
+   * determine the width of ellipsized and wrapped labels.
    *
    * Since: 2.6
    **/
@@ -723,11 +728,12 @@ gtk_label_class_init (GtkLabelClass *class)
    * GtkLabel:max-width-chars:
    * 
    * The desired maximum width of the label, in characters. If this property 
-   * is set to -1, the width will be calculated automatically, otherwise the 
-   * label will request space for no more than the requested number of 
-   * characters. If the #GtkLabel:width-chars property is set to a positive 
-   * value, then the "max-width-chars" property is ignored.
-   * 
+   * is set to -1, the width will be calculated automatically.
+   *
+   * See the section on <link linkend="label-text-layout">text layout</link>
+   * for details of how #GtkLabel:width-chars and #GtkLabel:max-width-chars
+   * determine the width of ellipsized and wrapped labels.
+   *
    * Since: 2.6
    **/
   g_object_class_install_property (gobject_class,
@@ -756,24 +762,6 @@ gtk_label_class_init (GtkLabelClass *class)
                                                          P_("Whether visited links should be tracked"),
                                                          TRUE,
                                                          GTK_PARAM_READWRITE));
-
-  /**
-   * GtkLabel:full-size:
-   *
-   * Use the entire space the widget got assigned for text wrapping. Overrides
-   * any #GtkLabel:width-chars, #GtkLabel:max-width-chars and screen size based
-   * constraints. Requires #GtkLabel:angle to be 0°, 90°, 180° or 270°.
-   *
-   * Since: 2.18
-   **/
-  g_object_class_install_property (gobject_class,
-                                   PROP_FULL_SIZE,
-                                   g_param_spec_boolean ("full-size",
-                                                        P_("Full size"),
-                                                        P_("Use the entire size of the widget to wrap text"),
-                                                        FALSE,
-                                                        GTK_PARAM_READWRITE));
-  
   /*
    * Key bindings
    */
@@ -960,9 +948,6 @@ gtk_label_set_property (GObject      *object,
     case PROP_TRACK_VISITED_LINKS:
       gtk_label_set_track_visited_links (label, g_value_get_boolean (value));
       break;
-    case PROP_FULL_SIZE:
-      gtk_label_set_full_size (label, g_value_get_boolean (value));
-      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1049,9 +1034,6 @@ gtk_label_get_property (GObject     *object,
     case PROP_TRACK_VISITED_LINKS:
       g_value_set_boolean (value, gtk_label_get_track_visited_links (label));
       break;
-    case PROP_FULL_SIZE:
-      g_value_set_int (value, gtk_label_get_full_size (label));
-      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -2953,17 +2935,25 @@ gtk_label_clear_layout (GtkLabel *label)
     }
 }
 
-static gint
-get_label_char_width (GtkLabel *label)
+
+static void
+get_label_width (GtkLabel *label,
+                gint     *minimum,
+                gint     *natural)
 {
-  GtkLabelPrivate *priv;
-  PangoContext *context;
+  GtkWidgetAuxInfo *aux_info;
+  GtkLabelPrivate  *priv;
+  PangoLayout      *layout;
+  PangoContext     *context;
   PangoFontMetrics *metrics;
-  gint char_width, digit_width, char_pixels, w;
-  
-  priv = GTK_LABEL_GET_PRIVATE (label);
-  
-  context = pango_layout_get_context (label->layout);
+  PangoRectangle    rect;
+  gint              char_width, digit_width, char_pixels, text_width, ellipsize_chars, guess_width;
+
+  priv     = GTK_LABEL_GET_PRIVATE (label);
+  aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE);
+
+  layout  = pango_layout_copy (label->layout);
+  context = pango_layout_get_context (layout);
   metrics = pango_context_get_metrics (context, GTK_WIDGET (label)->style->font_desc, 
                                       pango_context_get_language (context));
   
@@ -2971,24 +2961,88 @@ get_label_char_width (GtkLabel *label)
   digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
   char_pixels = MAX (char_width, digit_width);
   pango_font_metrics_unref (metrics);
-  
-  if (priv->width_chars < 0)
-    {
-      PangoRectangle rect;
-      
-      pango_layout_set_width (label->layout, -1);
-      pango_layout_get_extents (label->layout, NULL, &rect);
       
-      w = char_pixels * MAX (priv->max_width_chars, 3);
-      w = MIN (rect.width, w);
+  /* Fetch the length of the complete unwrapped text */
+  pango_layout_set_width (layout, -1);
+  pango_layout_get_extents (layout, NULL, &rect);
+  text_width = rect.width;
+
+  /* Fetch the width that was guessed by gtk_label_ensure_layout() */
+  pango_layout_get_extents (label->layout, NULL, &rect);
+  guess_width = rect.width;
+
+  /* enforce minimum width for ellipsized labels at ~3 chars */
+  if (label->ellipsize)
+    ellipsize_chars = 3;
+  else
+    ellipsize_chars = 0;
+
+  /* "width-chars" Hard-coded minimum width: 
+   *    - minimum size should be MAX (width-chars, strlen ("..."));
+   *    - natural size should be MAX (width-chars, strlen (label->text));
+   *
+   * "max-width-chars" User specified maximum size requisition
+   *    - minimum size should be MAX (width-chars, 0)
+   *    - natural size should be MIN (max-width-chars, strlen (label->text))
+   *
+   *    For ellipsizing labels; if max-width-chars is specified: either it is used as 
+   *    a minimum size or the label text as a minimum size (natural size still overflows).
+   *
+   *    For wrapping labels; A reasonable minimum size is useful to naturally layout
+   *    interfaces automatically. In this case if no "width-chars" is specified, the minimum
+   *    width will default to the wrap guess that gtk_label_ensure_layout() does.
+   *
+   *    In *any* case the minimum width is completely overridden if an explicit width 
+   *    request was provided.
+   */
+
+  if (label->ellipsize || label->wrap)
+    {
+      *minimum = char_pixels * MAX (priv->width_chars, ellipsize_chars);
+
+      /* Default to the minimum width regularly guessed by GTK+ if no minimum
+       * width was specified, only allow unwrapping of these labels.
+       *
+       * Note that when specifying a small width_chars for a long text;
+       * an accordingly large size will be required for the label height.
+       */
+      if (label->wrap && priv->width_chars <= 0)
+       *minimum = guess_width;
+
+      if (priv->max_width_chars < 0)
+       {
+         *natural = MAX (*minimum, text_width);
+       }
+      else
+       {
+         gint max_char_width = char_pixels * priv->max_width_chars;
+         gint max_width      = MIN (text_width, max_char_width);
+
+         /* With max-char-width specified, we let the minimum widths of 
+          * ellipsized text crawl up to the max-char-width
+          * (note that we dont want to limit the minimum width for wrapping text).
+          */
+         if (label->ellipsize)
+           *minimum = MIN (text_width, max_width);
+
+         *natural = MAX (*minimum, max_width);
+       }
     }
   else
     {
-      /* enforce minimum width for ellipsized labels at ~3 chars */
-      w = char_pixels * MAX (priv->width_chars, 3);
+      *minimum = text_width;
+      *natural = *minimum;
     }
-  
-  return w;
+
+  /* if a width-request is set, use that as the requested label width */
+  if ((label->wrap || label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0) &&
+      aux_info && aux_info->width > 0)
+    {
+      *minimum = aux_info->width * PANGO_SCALE;
+      *natural = MAX (*natural, *minimum);
+    }
+
+  g_object_unref (layout);
 }
 
 static void
@@ -3010,14 +3064,38 @@ get_label_wrap_width (GtkLabel *label)
   
   if (priv->wrap_width < 0)
     {
-      if (priv->width_chars > 0 || priv->max_width_chars > 0)
-       priv->wrap_width = get_label_char_width (label);
+      if (priv->width_chars > 0)
+       {
+         PangoLayout      *layout;
+         PangoContext     *context;
+         PangoFontMetrics *metrics;
+         PangoRectangle    rect;
+         gint              char_width, digit_width, char_pixels, text_width;
+
+         layout  = pango_layout_copy (label->layout);
+         context = pango_layout_get_context (layout);
+         metrics = pango_context_get_metrics (context, GTK_WIDGET (label)->style->font_desc, 
+                                              pango_context_get_language (context));
+         
+         char_width = pango_font_metrics_get_approximate_char_width (metrics);
+         digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
+         char_pixels = MAX (char_width, digit_width);
+         pango_font_metrics_unref (metrics);
+         
+         pango_layout_set_width (layout, -1);
+         pango_layout_get_extents (layout, NULL, &rect);
+         g_object_unref (layout);
+
+         text_width = rect.width;
+
+         priv->wrap_width = PANGO_PIXELS (MAX (text_width, char_pixels * priv->width_chars));
+       }
       else
        {
          PangoLayout *layout;
   
          layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), 
-                                                  "This long string gives a good enough length for any line to have.");
+                                                  "This string is just about long enough.");
          pango_layout_get_size (layout, &priv->wrap_width, NULL);
          g_object_unref (layout);
        }
@@ -3027,7 +3105,7 @@ get_label_wrap_width (GtkLabel *label)
 }
 
 static void
-gtk_label_ensure_layout (GtkLabel *label)
+gtk_label_ensure_layout (GtkLabel *label, gboolean guess_wrap_width)
 {
   GtkWidget *widget;
   PangoRectangle logical_rect;
@@ -3102,12 +3180,22 @@ gtk_label_ensure_layout (GtkLabel *label)
          GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE);
          gint longest_paragraph;
          gint width, height;
+         gint aux_width = 0;
 
-         if (aux_info && aux_info->width > 0)
-           pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
-         else if (widget->allocation.width > 1)
+         if ((angle == 90 || angle == 270) && aux_info && aux_info->height > 0)
+           aux_width = aux_info->height;
+         else if (aux_info && aux_info->width > 0)
+           aux_width = aux_info->width;
+
+         if (aux_width > 0)
+           pango_layout_set_width (label->layout, aux_width * PANGO_SCALE);
+         else if (guess_wrap_width == FALSE &&
+                  widget->allocation.width > 1 && widget->allocation.height > 1)
            {
-             width = widget->allocation.width - label->misc.xpad * 2;
+             if (angle == 90 || angle == 270)
+               width = widget->allocation.height - label->misc.ypad * 2;
+             else
+               width = widget->allocation.width  - label->misc.xpad * 2;
 
              pango_layout_set_wrap (label->layout, label->wrap_mode);
              pango_layout_set_width (label->layout, MAX (width, 1) * PANGO_SCALE);
@@ -3190,200 +3278,237 @@ get_single_line_height (GtkWidget   *widget,
   descent = pango_font_metrics_get_descent (metrics);
   pango_font_metrics_unref (metrics);
 
-  return PANGO_PIXELS (ascent + descent);
+  return ascent + descent;
 }
 
-
-
 static void
-gtk_label_layout_interface_init (GtkExtendedLayoutIface *iface)
+gtk_label_extended_layout_init (GtkExtendedLayoutIface *iface)
 {
+  iface->is_height_for_width  = gtk_label_is_height_for_width;
   iface->get_desired_width    = gtk_label_get_desired_width;
-  iface->get_desired_height    = gtk_label_get_desired_height;
+  iface->get_desired_height   = gtk_label_get_desired_height;
   iface->get_width_for_height = gtk_label_get_width_for_height;
   iface->get_height_for_width = gtk_label_get_height_for_width;
 }
 
+static gboolean
+gtk_label_is_height_for_width (GtkExtendedLayout *layout)
+{
+  GtkLabel *label = GTK_LABEL (layout);
+  gdouble   angle = gtk_label_get_angle (label);
+
+  if (angle == 90 || angle == 270)
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+get_size_for_allocation (GtkLabel        *label,
+                         GtkOrientation   orientation,
+                         gint             allocation,
+                         gint            *minimum_size,
+                         gint            *natural_size)
+{
+  PangoLayout *layout;
+  GtkWidgetAuxInfo *aux_info =
+    _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE);
+  gint aux_size;
+  gint text_height;
+
+  gtk_label_ensure_layout (label, FALSE);
+  layout = pango_layout_copy (label->layout);
+
+  if (aux_info)
+    {
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
+        aux_size = aux_info->width;
+      else
+        aux_size = aux_info->height;
+    }
+  else
+    aux_size = 0;
+
+  if (aux_size > 0)
+    pango_layout_set_width (layout, aux_size * PANGO_SCALE);
+  else
+    pango_layout_set_width (layout, allocation * PANGO_SCALE);
+
+  pango_layout_get_pixel_size (layout, NULL, &text_height);
+
+  if (minimum_size)
+    *minimum_size = text_height;
+
+  if (natural_size)
+    *natural_size = text_height;
+
+  g_object_unref (layout);
+}
+
 static void
 gtk_label_get_desired_size (GtkExtendedLayout *layout,
-                           GtkOrientation     orientation,
+                            GtkOrientation     orientation,
                             gint              *minimum_size,
                             gint              *natural_size)
 {
-  GtkLabelPrivate *priv = GTK_LABEL_GET_PRIVATE (layout);
-  GtkLabel *label = GTK_LABEL (layout);
+  GtkLabel      *label = GTK_LABEL (layout);
   PangoRectangle required_rect;
-  GtkWidgetAuxInfo *aux_info;
-  PangoLayout *natural_layout; 
-  gint minimum = 0, natural = 0;
+  PangoRectangle natural_rect;
+  gdouble        angle;
 
-  /*  
-   * If word wrapping is on, then the height requisition can depend
-   * on:
+  /* "width-chars" Hard-coded minimum width:
+   *    - minimum size should be MAX (width-chars, strlen ("..."));
+   *    - natural size should be MAX (width-chars, strlen (label->text));
    *
-   *   - Any width set on the widget via gtk_widget_set_size_request().
-   *   - The padding of the widget (xpad, set by gtk_misc_set_padding)
+   * "max-width-chars" User specified maximum size requisition
+   *    - minimum size should be MAX (width-chars, 0)
+   *    - natural size should be MIN (max-width-chars, strlen (label->text))
    *
-   * Instead of trying to detect changes to these quantities, if we
-   * are wrapping, we just rewrap for each size request. Since
-   * size requisitions are cached by the GTK+ core, this is not
-   * expensive.
    */
 
+  /* When calculating ->wrap sometimes we need to invent a size; Ideally we should be doing
+   * that stuff here instead of inside gtk_label_ensure_layout() */
   if (label->wrap)
     gtk_label_clear_layout (label);
+  gtk_label_ensure_layout (label, TRUE);
 
-  gtk_label_ensure_layout (label);
-
-  aux_info = _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE);
+  angle = gtk_label_get_angle (label);
 
+  /* Start off with the pixel extents of the rendered layout */
   pango_layout_get_extents (label->layout, NULL, &required_rect);
   required_rect.x = required_rect.y = 0;
-  
-  if (label->ellipsize || priv->width_chars > 0 || priv->max_width_chars > 0)
-    {
-      /* backup the Pango layout, as get_label_char_width() scrambles it */
-      
-      PangoLayout *backup = label->layout;
-      label->layout = pango_layout_copy (label->layout);
-      
-      required_rect.width = get_label_char_width (label);
-      
-      g_object_unref (label->layout);
-      label->layout = backup;
-    }
-  
-  if (label->single_line_mode)
+
+  if (label->single_line_mode || label->wrap)
     required_rect.height = get_single_line_height (GTK_WIDGET (label), label->layout);
-  
+
+  natural_rect = required_rect;
+
+  /* Calculate text width itself based on GtkLabel property rules */
+  get_label_width (label, &required_rect.width, &natural_rect.width);
+
+  /* Now that we have minimum and natural sizes in pango extents, apply a possible transform */
   if (label->have_transform)
     {
-      PangoContext *context = pango_layout_get_context (label->layout);
-      const PangoMatrix *matrix = pango_context_get_matrix (context);
+      PangoLayout       *layout  = pango_layout_copy (label->layout);
+      PangoContext      *context = pango_layout_get_context (label->layout);
+      const PangoMatrix *matrix  = pango_context_get_matrix (context);
+
+      pango_layout_set_width (layout, -1);
+      pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
+
+      pango_layout_get_extents (layout, NULL, &natural_rect);
+      g_object_unref (layout);
+
       pango_matrix_transform_rectangle (matrix, &required_rect);
+      pango_matrix_transform_rectangle (matrix, &natural_rect);
+
+      /* Bump the natural size in case of ellipsize to ensure pango has
+       * enough space in the angles (note, we could alternatively set the
+       * layout to not ellipsize when we know we have been allocated our
+       * full natural size, or it may be that pango needs a fix here).
+       */
+      if (label->ellipsize && angle != 0 && angle != 90 && angle != 180 && angle != 270 && angle != 360)
+        {
+          /* For some reason we only need this at about 110 degrees, and only
+           * when gaining in height
+           */
+          natural_rect.height += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE;
+          natural_rect.width  += ROTATION_ELLIPSIZE_PADDING * 2 * PANGO_SCALE;
+        }
     }
-  
-  required_rect.width = PANGO_PIXELS_CEIL (required_rect.width);
+
+  required_rect.width  = PANGO_PIXELS_CEIL (required_rect.width);
   required_rect.height = PANGO_PIXELS_CEIL (required_rect.height);
-  
 
-  /* if a width-request is set, use that as the requested label width */
-  if ((label->wrap || label->ellipsize ||
-       priv->width_chars > 0 || priv->max_width_chars > 0) &&
-      aux_info && aux_info->width > 0)
-    required_rect.width = aux_info->width;
+  natural_rect.width  = PANGO_PIXELS_CEIL (natural_rect.width);
+  natural_rect.height = PANGO_PIXELS_CEIL (natural_rect.height);
 
-  /* XXX TODO: Ideally for wrapping labels, the width should be one char or the length 
-   * of the longest word in the text depending on wrap mode.
-   */
   if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    minimum = required_rect.width + label->misc.xpad * 2;
-  else
     {
-      minimum = required_rect.height + label->misc.ypad * 2;
-    }
-
-
-  natural = minimum;
-
-#if 0
-  /* Natural size */
-  natural_layout = pango_layout_copy (label->layout);
-  pango_layout_set_width (natural_layout, -1);
-  pango_layout_set_ellipsize (natural_layout, PANGO_ELLIPSIZE_NONE);
-
-  pango_layout_get_extents (natural_layout, NULL, &required_rect);
-  required_rect.x = required_rect.y = 0;
+      /* Note, we cant use get_size_for_allocation() when rotating
+       * ellipsized labels.
+       */
+      if (!(label->ellipsize && label->have_transform) &&
+          (angle == 90 || angle == 270))
+        {
+          /* Doing a h4w request on a rotated label here, return the
+           * required width for the minimum height.
+           */
+          get_size_for_allocation (label,
+                                   GTK_ORIENTATION_VERTICAL,
+                                   required_rect.height,
+                                   minimum_size, natural_size);
 
-  if (label->single_line_mode)
-    required_rect.height = get_single_line_height (GTK_WIDGET (label), label->layout);
+        }
+      else
+        {
+          /* Normal desired width */
+          *minimum_size = required_rect.width;
+          *natural_size = natural_rect.width;
+        }
 
-  if (label->have_transform)
-    {
-      PangoContext *context = pango_layout_get_context (natural_layout);
-      const PangoMatrix *matrix = pango_context_get_matrix (context);
-      pango_matrix_transform_rectangle (matrix, &required_rect);
+      *minimum_size += label->misc.xpad * 2;
+      *natural_size += label->misc.xpad * 2;
     }
+  else /* GTK_ORIENTATION_VERTICAL */
+    {
+      /* Note, we cant use get_size_for_allocation() when rotating
+       * ellipsized labels.
+       */
+      if (!(label->ellipsize && label->have_transform) &&
+          (angle == 0 || angle == 180))
+        {
+          /* Doing a w4h request on a label here, return the required
+           * height for the minimum width.
+           */
+          get_size_for_allocation (label,
+                                   GTK_ORIENTATION_HORIZONTAL,
+                                   required_rect.width,
+                                   minimum_size, natural_size);
+        }
+      else
+        {
+          /* A vertically rotated label does w4h, so return the base
+           * desired height (text length)
+           */
+          *minimum_size = required_rect.height;
+          *natural_size = natural_rect.height;
+        }
 
-  required_rect.width = PANGO_PIXELS_CEIL (required_rect.width);
-  required_rect.height = PANGO_PIXELS_CEIL (required_rect.height);
+      *minimum_size += label->misc.ypad * 2;
+      *natural_size += label->misc.ypad * 2;
+    }
 
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    natural = required_rect.width + label->misc.xpad * 2;
-  else
-    natural = required_rect.height + label->misc.ypad * 2;
-  
-  g_object_unref (natural_layout);
-#endif
+  /* Restore real allocated size of layout; sometimes size-requests
+   * are randomly called without a following allocation; for this case
+   * we need to make sure we dont have a mucked up layout because we
+   * went and guessed the wrap-size.
+   */
+  if (label->wrap)
+    gtk_label_clear_layout (label);
+  gtk_label_ensure_layout (label, FALSE);
 
-  if (minimum_size)
-    *minimum_size = minimum;
-  
-  if (natural_size)
-    *natural_size = natural;
 }
 
 
 static void
 gtk_label_get_desired_width (GtkExtendedLayout *layout,
-                            gint              *minimum_size,
-                            gint              *natural_size)
+                             gint              *minimum_size,
+                             gint              *natural_size)
 {
-  gtk_label_get_desired_size (layout, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+  gtk_label_get_desired_size (layout,
+                              GTK_ORIENTATION_HORIZONTAL,
+                              minimum_size, natural_size);
 }
 
 static void
 gtk_label_get_desired_height (GtkExtendedLayout *layout,
-                             gint              *minimum_size,
-                             gint              *natural_size)
+                              gint              *minimum_size,
+                              gint              *natural_size)
 {
-  gtk_label_get_desired_size (layout, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
-}
-
-
-static void
-get_size_for_allocation (GtkLabel        *label,
-                        GtkOrientation   orientation,
-                        gint             allocation,
-                        gint            *minimum_size,
-                        gint            *natural_size)
-{
-  PangoLayout *layout;
-  GtkWidgetAuxInfo *aux_info = 
-    _gtk_widget_get_aux_info (GTK_WIDGET (label), FALSE);
-  gint aux_size;
-  gint text_height;
-
-  if (label->wrap)
-    gtk_label_clear_layout (label);
-
-  gtk_label_ensure_layout (label);
-  layout = pango_layout_copy (label->layout);
-
-  if (aux_info)
-    {
-      if (orientation == GTK_ORIENTATION_HORIZONTAL)
-       aux_size = aux_info->width;
-      else
-       aux_size = aux_info->height;
-    }
-  else
-    aux_size = 0;
-
-  if (aux_size > 0)
-    pango_layout_set_width (layout, aux_size * PANGO_SCALE);
-  else
-    pango_layout_set_width (layout, allocation * PANGO_SCALE);
-
-  pango_layout_get_pixel_size (layout, NULL, &text_height);
-
-  if (minimum_size)
-    *minimum_size = text_height;
-
-  if (natural_size)
-    *natural_size = text_height;
-
-  g_object_unref (layout);
+  gtk_label_get_desired_size (layout,
+                              GTK_ORIENTATION_VERTICAL,
+                              minimum_size, natural_size);
 }
 
 static void
@@ -3395,8 +3520,21 @@ gtk_label_get_width_for_height (GtkExtendedLayout *layout,
   GtkLabel *label = GTK_LABEL (layout);
   gdouble angle = gtk_label_get_angle (label);
 
-  if (90 == angle || 270 == angle)
-    get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL, height, minimum_width, natural_width);
+  if (label->wrap && (angle == 90 || angle == 270))
+    {
+      if (label->wrap)
+        gtk_label_clear_layout (label);
+
+      get_size_for_allocation (label, GTK_ORIENTATION_VERTICAL,
+                               MAX (1, height - (label->misc.ypad * 2)),
+                               minimum_width, natural_width);
+
+      if (minimum_width)
+        *minimum_width += label->misc.xpad * 2;
+
+      if (natural_width)
+        *natural_width += label->misc.xpad * 2;
+    }
   else
     GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_width (layout, minimum_width, natural_width);
 }
@@ -3410,8 +3548,21 @@ gtk_label_get_height_for_width (GtkExtendedLayout *layout,
   GtkLabel *label = GTK_LABEL (layout);
   gdouble angle = gtk_label_get_angle (label);
 
-  if (0 == angle || 180 == angle)
-    get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL, width, minimum_height, natural_height);
+  if (label->wrap && (angle == 0 || angle == 180 || angle == 360))
+    {
+      if (label->wrap)
+        gtk_label_clear_layout (label);
+
+      get_size_for_allocation (label, GTK_ORIENTATION_HORIZONTAL,
+                               MAX (1, width - label->misc.xpad * 2),
+                               minimum_height, natural_height);
+
+      if (minimum_height)
+        *minimum_height += label->misc.ypad * 2;
+
+      if (natural_height)
+        *natural_height += label->misc.ypad * 2;
+    }
   else
     GTK_EXTENDED_LAYOUT_GET_IFACE (layout)->get_desired_height (layout, minimum_height, natural_height);
 }
@@ -3426,18 +3577,18 @@ gtk_label_size_allocate (GtkWidget     *widget,
 
   GTK_WIDGET_CLASS (gtk_label_parent_class)->size_allocate (widget, allocation);
 
-  /* The layout may have been recently cleared in get_size_for_orientation(), but the 
-   * width at that point may not be the same as the allocated width
+  /* The layout may have been recently cleared in get_size_for_orientation(),
+   * but the width at that point may not be the same as the allocated width
    */
   if (label->wrap)
     gtk_label_clear_layout (label);
 
-  gtk_label_ensure_layout (label);
+  gtk_label_ensure_layout (label, FALSE);
 
-  if (label->ellipsize || GTK_LABEL_GET_PRIVATE (label)->full_size)
+  if (label->ellipsize)
     {
       if (label->layout)
-       {
+        {
           PangoRectangle logical;
           PangoRectangle bounds;
 
@@ -3605,10 +3756,12 @@ get_layout_location (GtkLabel  *label,
   gint req_width, x, y;
   gint req_height;
   PangoRectangle logical;
+  gdouble angle;
 
-  misc = GTK_MISC (label);
+  misc   = GTK_MISC (label);
   widget = GTK_WIDGET (label);
-  priv = GTK_LABEL_GET_PRIVATE (label);
+  priv   = GTK_LABEL_GET_PRIVATE (label);
+  angle  = gtk_label_get_angle (label);
 
   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
     xalign = misc->xalign;
@@ -3617,6 +3770,18 @@ get_layout_location (GtkLabel  *label,
 
   pango_layout_get_extents (label->layout, NULL, &logical);
 
+  /* Do the wrap width delimiting before the transform
+   */
+  if (label->wrap || label->ellipsize || priv->width_chars > 0)
+    {
+      int width;
+
+      width = pango_layout_get_width (label->layout);
+
+      if (width != -1)
+       logical.width = MIN (width, logical.width);
+    }
+
   if (label->have_transform)
     {
       PangoContext *context = gtk_widget_get_pango_context (widget);
@@ -3626,27 +3791,11 @@ get_layout_location (GtkLabel  *label,
 
   pango_extents_to_pixels (&logical, NULL);
 
-  if (label->wrap || label->ellipsize || priv->width_chars > 0 || priv->full_size)
-    {
-      int width;
+  req_width  = logical.width;
+  req_height = logical.height;
 
-      width = pango_layout_get_width (label->layout);
-
-      req_width = logical.width;
-      req_height = logical.height;
-
-      if (width != -1)
-       req_width = MIN(PANGO_PIXELS (width), req_width);
-      req_width += 2 * misc->xpad;
-      req_height += 2 * misc->ypad;
-    }
-  else
-    {
-      req_width = logical.width;
-      req_height = logical.height;
-/*       req_width = widget->requisition.width; */
-/*       req_height = widget->requisition.height; */
-    }
+  req_width  += 2 * misc->xpad;
+  req_height += 2 * misc->ypad;
 
   x = floor (widget->allocation.x + (gint)misc->xpad +
              xalign * (widget->allocation.width - req_width));
@@ -3656,6 +3805,9 @@ get_layout_location (GtkLabel  *label,
   else
     x = MIN (x, widget->allocation.x + widget->allocation.width - misc->xpad);
 
+
+
+
   /* bgo#315462 - For single-line labels, *do* align the requisition with
    * respect to the allocation, even if we are under-allocated.  For multi-line
    * labels, always show the top of the text when they are under-allocated.  The
@@ -3711,7 +3863,7 @@ get_cursor_direction (GtkLabel *label)
 
   g_assert (label->select_info);
 
-  gtk_label_ensure_layout (label);
+  gtk_label_ensure_layout (label, FALSE);
 
   for (l = pango_layout_get_lines_readonly (label->layout); l; l = l->next)
     {
@@ -3756,7 +3908,7 @@ gtk_label_draw_cursor (GtkLabel  *label, gint xoffset, gint yoffset)
       keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gtk_widget_get_display (widget)));
       cursor_direction = get_cursor_direction (label);
 
-      gtk_label_ensure_layout (label);
+      gtk_label_ensure_layout (label, FALSE);
       
       pango_layout_get_cursor_pos (label->layout, label->select_info->selection_end,
                                   &strong_pos, &weak_pos);
@@ -3840,7 +3992,7 @@ gtk_label_expose (GtkWidget      *widget,
   GtkLabelSelectionInfo *info = label->select_info;
   gint x, y;
 
-  gtk_label_ensure_layout (label);
+  gtk_label_ensure_layout (label, FALSE);
   
   if (gtk_widget_get_visible (widget) && gtk_widget_get_mapped (widget) &&
       label->text && (*label->text != '\0'))
@@ -4253,7 +4405,7 @@ get_layout_index (GtkLabel *label,
 
   *index = 0;
 
-  gtk_label_ensure_layout (label);
+  gtk_label_ensure_layout (label, FALSE);
 
   window_to_layout_coords (label, &x, &y);
 
@@ -5297,7 +5449,7 @@ gtk_label_get_layout (GtkLabel *label)
 {
   g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
 
-  gtk_label_ensure_layout (label);
+  gtk_label_ensure_layout (label, FALSE);
 
   return label->layout;
 }
@@ -5324,7 +5476,7 @@ gtk_label_get_layout_offsets (GtkLabel *label,
 {
   g_return_if_fail (GTK_IS_LABEL (label));
 
-  gtk_label_ensure_layout (label);
+  gtk_label_ensure_layout (label, FALSE);
 
   get_layout_location (label, x, y);
 }
@@ -5384,32 +5536,6 @@ gtk_label_set_use_underline (GtkLabel *label,
   gtk_label_recalculate (label);
 }
 
-gboolean
-gtk_label_get_full_size (GtkLabel *label)
-{
-  g_return_val_if_fail (GTK_IS_LABEL (label), FALSE);
-  return GTK_LABEL_GET_PRIVATE (label)->full_size;
-}
-
-void
-gtk_label_set_full_size (GtkLabel *label,
-                        gboolean  setting)
-{
-  GtkLabelPrivate *priv;
-
-  g_return_if_fail (GTK_IS_LABEL (label));
-  priv = GTK_LABEL_GET_PRIVATE (label);
-
-  if (priv->full_size != setting)
-    {
-      priv->full_size = setting;
-
-      g_object_notify (G_OBJECT (label), "full-size");
-      gtk_label_invalidate_wrap_width (label);
-      gtk_widget_queue_resize (GTK_WIDGET (label));
-    }
-}
-
 /**
  * gtk_label_get_use_underline:
  * @label: a #GtkLabel
@@ -5495,7 +5621,7 @@ get_better_cursor (GtkLabel *label,
                "gtk-split-cursor", &split_cursor,
                NULL);
 
-  gtk_label_ensure_layout (label);
+  gtk_label_ensure_layout (label, FALSE);
   
   pango_layout_get_cursor_pos (label->layout, index,
                               &strong_pos, &weak_pos);
@@ -5535,7 +5661,7 @@ gtk_label_move_logically (GtkLabel *label,
       gint n_attrs;
       gint length;
 
-      gtk_label_ensure_layout (label);
+      gtk_label_ensure_layout (label, FALSE);
       
       length = g_utf8_strlen (label->text, -1);
 
@@ -5579,7 +5705,7 @@ gtk_label_move_visually (GtkLabel *label,
       gboolean split_cursor;
       gboolean strong;
 
-      gtk_label_ensure_layout (label);
+      gtk_label_ensure_layout (label, FALSE);
 
       g_object_get (gtk_widget_get_settings (GTK_WIDGET (label)),
                    "gtk-split-cursor", &split_cursor,
@@ -5632,7 +5758,7 @@ gtk_label_move_forward_word (GtkLabel *label,
       PangoLogAttr *log_attrs;
       gint n_attrs;
 
-      gtk_label_ensure_layout (label);
+      gtk_label_ensure_layout (label, FALSE);
       
       pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);
       
@@ -5660,7 +5786,7 @@ gtk_label_move_backward_word (GtkLabel *label,
       PangoLogAttr *log_attrs;
       gint n_attrs;
 
-      gtk_label_ensure_layout (label);
+      gtk_label_ensure_layout (label, FALSE);
       
       pango_layout_get_log_attrs (label->layout, &log_attrs, &n_attrs);