gtk+ r22592 - in trunk: . demos/gtk-demo gdk



Author: behdad
Date: Fri Mar 27 16:54:10 2009
New Revision: 22592
URL: http://svn.gnome.org/viewvc/gtk+?rev=22592&view=rev

Log:
2009-03-27  Behdad Esfahbod  <behdad gnome org>

        Bug 437533 â Implement draw_shape PangoRenderer method

        * gdk/gdkpango.c (gdk_pango_renderer_draw_shape),
        (gdk_pango_renderer_class_init): Implement draw_shape

        * demos/gtk-demo/rotated_text.c (fancy_shape_renderer),
        (create_fancy_attr_list_for_layout), (rotated_text_expose_event),
        (do_rotated_text):
        1) Port to pangocairo
        2) Also show a rotated label
        3) Install a custom shape renderer on both.  The second one goes
        through gdkpango and hence tests the patch above.  It's working.



Modified:
   trunk/ChangeLog
   trunk/demos/gtk-demo/rotated_text.c
   trunk/gdk/gdkpango.c

Modified: trunk/demos/gtk-demo/rotated_text.c
==============================================================================
--- trunk/demos/gtk-demo/rotated_text.c	(original)
+++ trunk/demos/gtk-demo/rotated_text.c	Fri Mar 27 16:54:10 2009
@@ -1,101 +1,173 @@
 /* Rotated Text
  *
- * This demo shows how to use GDK and Pango to draw rotated and transformed
- * text. The use of GdkPangoRenderer in this example is a somewhat advanced
- * technique; most applications can simply use gdk_draw_layout(). We use
- * it here mostly because that allows us to work in user coordinates - that is,
- * coordinates prior to the application of the transformation matrix, rather
- * than device coordinates.
+ * This demo shows how to use PangoCairo to draw rotated and transformed
+ * text.  The right pane shows a rotated GtkLabel widget.
  *
- * As of GTK+-2.6, the ability to draw transformed and anti-aliased graphics
- * as shown in this example is only present for text. With GTK+-2.8, a new
- * graphics system called "Cairo" will be introduced that provides these
- * capabilities and many more for all types of graphics.
+ * In both cases, a custom PangoCairo shape renderer is installed to draw
+ * a red heard using cairo drawing operations instead of the Unicode heart
+ * character.
  */
-#include <math.h>
+
 #include <gtk/gtk.h>
+#include <string.h>
 
 static GtkWidget *window = NULL;
 
+#define HEART "â"
+const char text[] = "I â GTK+";
+
+static void
+fancy_shape_renderer (cairo_t        *cr,
+		      PangoAttrShape *attr,
+		      gboolean        do_path,
+		      gpointer        data)
+{
+  double x, y;
+  cairo_get_current_point (cr, &x, &y);
+  cairo_translate (cr, x, y);
+
+  cairo_scale (cr,
+	       (double) attr->ink_rect.width  / PANGO_SCALE,
+	       (double) attr->ink_rect.height / PANGO_SCALE);
+
+  switch (GPOINTER_TO_UINT (attr->data))
+    {
+    case 0x2665: /* U+2665 BLACK HEART SUIT */
+      {
+        cairo_move_to (cr, .5, .0);
+        cairo_line_to (cr, .9, -.4);
+	cairo_curve_to (cr, 1.1, -.8, .5, -.9, .5, -.5);
+	cairo_curve_to (cr, .5, -.9, -.1, -.8, .1, -.4);
+	cairo_close_path (cr);
+      }
+      break;
+    }
+
+  if (!do_path) {
+    cairo_set_source_rgb (cr, 1., 0., 0.);
+    cairo_fill (cr);
+  }
+}
+
+PangoAttrList *
+create_fancy_attr_list_for_layout (PangoLayout *layout)
+{
+  PangoAttrList *attrs;
+  PangoFontMetrics *metrics;
+  int ascent;
+  PangoRectangle ink_rect, logical_rect;
+  const char *p;
+
+  /* Get font metrics and prepare fancy shape size */
+  metrics = pango_context_get_metrics (pango_layout_get_context (layout),
+				       pango_layout_get_font_description (layout),
+				       NULL);
+  ascent = pango_font_metrics_get_ascent (metrics);
+  logical_rect.x = 0;
+  logical_rect.width = ascent;
+  logical_rect.y = -ascent;
+  logical_rect.height = ascent;
+  ink_rect = logical_rect;
+  pango_font_metrics_unref (metrics);
+
+  /* Set fancy shape attributes for all hearts */
+  attrs = pango_attr_list_new ();
+  for (p = text; (p = strstr (p, HEART)); p += strlen (HEART))
+    {
+      PangoAttribute *attr;
+      
+      attr = pango_attr_shape_new_with_data (&ink_rect,
+					     &logical_rect,
+					     GUINT_TO_POINTER (g_utf8_get_char (p)),
+					     NULL, NULL);
+
+      attr->start_index = p - text;
+      attr->end_index = attr->start_index + strlen (HEART);
+
+      pango_attr_list_insert (attrs, attr);
+    }
+
+  return attrs;
+}
+
 static gboolean
 rotated_text_expose_event (GtkWidget      *widget,
 			   GdkEventExpose *event,
 			   gpointer	   data)
 {
 #define RADIUS 150
-#define N_WORDS 10
-#define FONT "Sans Bold 27"
-  
-  PangoRenderer *renderer;
-  PangoMatrix matrix = PANGO_MATRIX_INIT;
+#define N_WORDS 5
+#define FONT "Serif 18"
+
   PangoContext *context;
   PangoLayout *layout;
   PangoFontDescription *desc;
 
+  cairo_t *cr;
+  cairo_pattern_t *pattern;
+
+  PangoAttrList *attrs;
+
   int width = widget->allocation.width;
   int height = widget->allocation.height;
   double device_radius;
   int i;
 
-  /* Get the default renderer for the screen, and set it up for drawing  */
-  renderer = gdk_pango_renderer_get_default (gtk_widget_get_screen (widget));
-  gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer), widget->window);
-  gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), widget->style->black_gc);
-
-  /* Set up a transformation matrix so that the user space coordinates for
-   * the centered square where we draw are [-RADIUS, RADIUS], [-RADIUS, RADIUS]
-   * We first center, then change the scale */
+  /* Create a cairo context and set up a transformation matrix so that the user
+   * space coordinates for the centered square where we draw are [-RADIUS, RADIUS],
+   * [-RADIUS, RADIUS].
+   * We first center, then change the scale. */
+  cr = gdk_cairo_create (widget->window);
   device_radius = MIN (width, height) / 2.;
-  pango_matrix_translate (&matrix,
-			  device_radius + (width - 2 * device_radius) / 2,
-			  device_radius + (height - 2 * device_radius) / 2);
-  pango_matrix_scale (&matrix, device_radius / RADIUS, device_radius / RADIUS);
+  cairo_translate (cr,
+		   device_radius + (width - 2 * device_radius) / 2,
+		   device_radius + (height - 2 * device_radius) / 2);
+  cairo_scale (cr, device_radius / RADIUS, device_radius / RADIUS);
+
+  /* Create and a subtle gradient source and use it. */
+  pattern = cairo_pattern_create_linear (-RADIUS, -RADIUS, RADIUS, RADIUS);
+  cairo_pattern_add_color_stop_rgb (pattern, 0., .5, .0, .0);
+  cairo_pattern_add_color_stop_rgb (pattern, 1., .0, .0, .5);
+  cairo_set_source (cr, pattern);
 
-  /* Create a PangoLayout, set the font and text */
+  /* Create a PangoContext and set up our shape renderer */
   context = gtk_widget_create_pango_context (widget);
+  pango_cairo_context_set_shape_renderer (context,
+					  fancy_shape_renderer,
+					  NULL, NULL);
+
+  /* Create a PangoLayout, set the text, font, and attributes */
   layout = pango_layout_new (context);
-  pango_layout_set_text (layout, "Text", -1);
+  pango_layout_set_text (layout, text, -1);
   desc = pango_font_description_from_string (FONT);
   pango_layout_set_font_description (layout, desc);
-  pango_font_description_free (desc);
+
+  attrs = create_fancy_attr_list_for_layout (layout);
+  pango_layout_set_attributes (layout, attrs);
+  pango_attr_list_unref (attrs);
 
   /* Draw the layout N_WORDS times in a circle */
   for (i = 0; i < N_WORDS; i++)
     {
-      GdkColor color;
-      PangoMatrix rotated_matrix = matrix;
       int width, height;
-      double angle = (360. * i) / N_WORDS;
 
-      /* Gradient from red at angle == 60 to blue at angle == 300 */
-      color.red   = 65535 * (1 + cos ((angle - 60) * G_PI / 180.)) / 2;
-      color.green = 0;
-      color.blue  = 65535  - color.red;
-    
-      gdk_pango_renderer_set_override_color (GDK_PANGO_RENDERER (renderer),
-					     PANGO_RENDER_PART_FOREGROUND, &color);
-                                             
-      pango_matrix_rotate (&rotated_matrix, angle);
-
-      pango_context_set_matrix (context, &rotated_matrix);
-    
       /* Inform Pango to re-layout the text with the new transformation matrix */
-      pango_layout_context_changed (layout);
+      pango_cairo_update_layout (cr, layout);
     
-      pango_layout_get_size (layout, &width, &height);
-      pango_renderer_draw_layout (renderer, layout,
-				  - width / 2, - RADIUS * PANGO_SCALE);
-    }
+      pango_layout_get_pixel_size (layout, &width, &height);
+      cairo_move_to (cr, - width / 2, - RADIUS * .9);
+      pango_cairo_show_layout (cr, layout);
 
-  /* Clean up default renderer, since it is shared */
-  gdk_pango_renderer_set_override_color (GDK_PANGO_RENDERER (renderer),
-					 PANGO_RENDER_PART_FOREGROUND, NULL);
-  gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer), NULL);
-  gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), NULL);
+      /* Rotate for the next turn */
+      cairo_rotate (cr, G_PI*2 / N_WORDS);
+    }
 
   /* free the objects we created */
+  pango_font_description_free (desc);
   g_object_unref (layout);
   g_object_unref (context);
+  cairo_pattern_destroy (pattern);
+  cairo_destroy (cr);
   
   return FALSE;
 }
@@ -103,21 +175,30 @@
 GtkWidget *
 do_rotated_text (GtkWidget *do_widget)
 {
-  GtkWidget *drawing_area;
-  
   if (!window)
     {
+      GtkWidget *box;
+      GtkWidget *drawing_area;
+      GtkWidget *label;
+      PangoLayout *layout;
+      PangoAttrList *attrs;
+
       const GdkColor white = { 0, 0xffff, 0xffff, 0xffff };
       
       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
       gtk_window_set_screen (GTK_WINDOW (window),
 			     gtk_widget_get_screen (do_widget));
       gtk_window_set_title (GTK_WINDOW (window), "Rotated Text");
-
+      gtk_window_set_default_size (GTK_WINDOW (window), 4 * RADIUS, 2 * RADIUS);
       g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
 
+      box = gtk_hbox_new (TRUE, 0);
+      gtk_container_add (GTK_CONTAINER (window), box);
+
+      /* Add a drawing area */
+
       drawing_area = gtk_drawing_area_new ();
-      gtk_container_add (GTK_CONTAINER (window), drawing_area);
+      gtk_container_add (GTK_CONTAINER (box), drawing_area);
 
       /* This overrides the background color from the theme */
       gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &white);
@@ -125,7 +206,21 @@
       g_signal_connect (drawing_area, "expose-event",
 			G_CALLBACK (rotated_text_expose_event), NULL);
 
-      gtk_window_set_default_size (GTK_WINDOW (window), 2 * RADIUS, 2 * RADIUS);
+      /* And a label */
+
+      label = gtk_label_new (text);
+      gtk_container_add (GTK_CONTAINER (box), label);
+
+      gtk_label_set_angle (label, 45);
+
+      /* Set up fancy stuff on the label */
+      layout = gtk_label_get_layout (label);
+      pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout),
+					      fancy_shape_renderer,
+					      NULL, NULL);
+      attrs = create_fancy_attr_list_for_layout (layout);
+      gtk_label_set_attributes (label, attrs);
+      pango_attr_list_unref (attrs);
     }
 
   if (!GTK_WIDGET_VISIBLE (window))

Modified: trunk/gdk/gdkpango.c
==============================================================================
--- trunk/gdk/gdkpango.c	(original)
+++ trunk/gdk/gdkpango.c	Fri Mar 27 16:54:10 2009
@@ -312,6 +312,52 @@
 }
 
 static void
+gdk_pango_renderer_draw_shape (PangoRenderer  *renderer,
+			       PangoAttrShape *attr,
+			       int             x,
+			       int             y)
+{
+  GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
+  GdkPangoRendererPrivate *priv = gdk_renderer->priv;
+  PangoLayout *layout;
+  PangoCairoShapeRendererFunc shape_renderer;
+  gpointer                    shape_renderer_data;
+  cairo_t *cr;
+  double dx = (double)x / PANGO_SCALE, dy = (double)y / PANGO_SCALE;
+
+  layout = pango_renderer_get_layout (renderer);
+
+  if (!layout)
+  	return;
+
+  shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout),
+							   &shape_renderer_data);
+
+  if (!shape_renderer)
+    return;
+
+  cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_FOREGROUND);
+  
+  cairo_save (cr);
+
+  if (priv->embossed)
+    {
+      cairo_save (cr);
+      emboss_context (gdk_renderer, cr);
+
+      cairo_move_to (cr, dx, dy);
+      shape_renderer (cr, attr, FALSE, shape_renderer_data);
+
+      cairo_restore (cr);
+    }
+
+  cairo_move_to (cr, dx, dy);
+  shape_renderer (cr, attr, FALSE, shape_renderer_data);
+
+  cairo_restore (cr);
+}
+
+static void
 gdk_pango_renderer_part_changed (PangoRenderer   *renderer,
 				 PangoRenderPart  part)
 {
@@ -474,6 +520,7 @@
   renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
   renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle;
   renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline;
+  renderer_class->draw_shape = gdk_pango_renderer_draw_shape;
   renderer_class->part_changed = gdk_pango_renderer_part_changed;
   renderer_class->begin = gdk_pango_renderer_begin;
   renderer_class->end = gdk_pango_renderer_end;



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