2003-09-12 Matthias Clasen <maclas@gmx.de> * gdk/gdkdraw.c (gdk_draw_string, gdk_draw_text) (gdk_draw_text_wc): Add deprecation notes. (#121955)
		
			
				
	
	
		
			930 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			930 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* GDK - The GIMP Drawing Kit
 | 
						|
 * Copyright (C) 2000 Red Hat, Inc. 
 | 
						|
 *
 | 
						|
 * This library is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU Lesser General Public
 | 
						|
 * License as published by the Free Software Foundation; either
 | 
						|
 * version 2 of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This library is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
 | 
						|
 * Lesser General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Lesser General Public
 | 
						|
 * License along with this library; if not, write to the
 | 
						|
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
						|
 * Boston, MA 02111-1307, USA.
 | 
						|
 */
 | 
						|
 | 
						|
#include "gdkcolor.h"
 | 
						|
#include "gdkgc.h"
 | 
						|
#include "gdkpango.h"
 | 
						|
#include "gdkrgb.h"
 | 
						|
#include "gdkprivate.h"
 | 
						|
#include "gdkscreen.h"
 | 
						|
 | 
						|
#define GDK_INFO_KEY "gdk-info"
 | 
						|
 | 
						|
typedef struct _GdkPangoContextInfo GdkPangoContextInfo;
 | 
						|
 | 
						|
struct _GdkPangoContextInfo
 | 
						|
{
 | 
						|
  GdkColormap *colormap;
 | 
						|
};
 | 
						|
 | 
						|
static PangoAttrType gdk_pango_attr_stipple_type;
 | 
						|
static PangoAttrType gdk_pango_attr_embossed_type;
 | 
						|
 | 
						|
static void gdk_pango_get_item_properties (PangoItem      *item,
 | 
						|
					   PangoUnderline *uline,
 | 
						|
					   gboolean       *strikethrough,
 | 
						|
                                           gint           *rise,
 | 
						|
					   PangoColor     *fg_color,
 | 
						|
					   gboolean       *fg_set,
 | 
						|
					   PangoColor     *bg_color,
 | 
						|
					   gboolean       *bg_set,
 | 
						|
                                           gboolean       *embossed,
 | 
						|
                                           GdkBitmap     **stipple,
 | 
						|
					   gboolean       *shape_set,
 | 
						|
					   PangoRectangle *ink_rect,
 | 
						|
					   PangoRectangle *logical_rect);
 | 
						|
 | 
						|
static void
 | 
						|
gdk_pango_context_destroy (GdkPangoContextInfo *info)
 | 
						|
{
 | 
						|
  if (info->colormap)
 | 
						|
    g_object_unref (info->colormap);
 | 
						|
  g_free (info);
 | 
						|
}
 | 
						|
 | 
						|
static GdkPangoContextInfo *
 | 
						|
gdk_pango_context_get_info (PangoContext *context, gboolean create)
 | 
						|
{
 | 
						|
  GdkPangoContextInfo *info =
 | 
						|
    g_object_get_qdata (G_OBJECT (context),
 | 
						|
                        g_quark_try_string (GDK_INFO_KEY));
 | 
						|
  if (!info && create)
 | 
						|
    {
 | 
						|
      info = g_new (GdkPangoContextInfo, 1);
 | 
						|
      info->colormap = NULL;
 | 
						|
 | 
						|
      g_object_set_qdata_full (G_OBJECT (context),
 | 
						|
                               g_quark_from_static_string (GDK_INFO_KEY),
 | 
						|
                               info, (GDestroyNotify)gdk_pango_context_destroy);
 | 
						|
    }
 | 
						|
 | 
						|
  return info;
 | 
						|
}
 | 
						|
 | 
						|
static GdkGC *
 | 
						|
gdk_pango_get_gc (GdkDrawable    *drawable,
 | 
						|
		  PangoContext   *context,
 | 
						|
		  PangoColor     *fg_color,
 | 
						|
                  GdkBitmap      *stipple,
 | 
						|
		  GdkGC          *base_gc)
 | 
						|
{
 | 
						|
  GdkGC *result;
 | 
						|
  GdkPangoContextInfo *info;
 | 
						|
  
 | 
						|
  g_return_val_if_fail (context != NULL, NULL);
 | 
						|
 | 
						|
  info = gdk_pango_context_get_info (context, FALSE);
 | 
						|
 | 
						|
  if (info == NULL || info->colormap == NULL)
 | 
						|
    {
 | 
						|
      g_warning ("you must set the colormap on a PangoContext before using it to draw a layout");
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  result = gdk_gc_new (drawable);
 | 
						|
  gdk_gc_copy (result, base_gc);
 | 
						|
  
 | 
						|
  if (fg_color)
 | 
						|
    {
 | 
						|
      GdkColor color;
 | 
						|
      
 | 
						|
      color.red = fg_color->red;
 | 
						|
      color.green = fg_color->green;
 | 
						|
      color.blue = fg_color->blue;
 | 
						|
 | 
						|
      gdk_rgb_find_color (info->colormap, &color);
 | 
						|
      gdk_gc_set_foreground (result, &color);
 | 
						|
    }
 | 
						|
 | 
						|
  if (stipple)
 | 
						|
    {
 | 
						|
      gdk_gc_set_fill (result, GDK_STIPPLED);
 | 
						|
      gdk_gc_set_stipple (result, stipple);
 | 
						|
    }
 | 
						|
  
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_pango_free_gc (PangoContext *context,
 | 
						|
		   GdkGC        *gc)
 | 
						|
{
 | 
						|
  g_object_unref (gc);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_pango_context_set_colormap:
 | 
						|
 * @context: a #PangoContext
 | 
						|
 * @colormap: a #GdkColormap
 | 
						|
 *
 | 
						|
 * Sets the colormap to be used for drawing with @context.
 | 
						|
 *
 | 
						|
 * If you obtained your context from gtk_widget_get_pango_context() or
 | 
						|
 * gtk_widget_create_pango_context(), the colormap will already be set
 | 
						|
 * to the colormap for the widget, so you shouldn't need this
 | 
						|
 * function.
 | 
						|
 **/
 | 
						|
void
 | 
						|
gdk_pango_context_set_colormap (PangoContext *context,
 | 
						|
				GdkColormap  *colormap)
 | 
						|
{
 | 
						|
  GdkPangoContextInfo *info;
 | 
						|
  
 | 
						|
  g_return_if_fail (context != NULL);
 | 
						|
 | 
						|
  info = gdk_pango_context_get_info (context, TRUE);
 | 
						|
  g_return_if_fail (info != NULL);
 | 
						|
  
 | 
						|
  if (info->colormap != colormap)
 | 
						|
    {
 | 
						|
      if (info->colormap)
 | 
						|
	g_object_unref (info->colormap);
 | 
						|
 | 
						|
      info->colormap = colormap;
 | 
						|
      
 | 
						|
      if (info->colormap)
 | 
						|
   	g_object_ref (info->colormap);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
draw_underline (GdkDrawable    *drawable,
 | 
						|
		GdkGC          *gc,
 | 
						|
		PangoUnderline  uline,
 | 
						|
		int             baseline_y,
 | 
						|
		int             low_y,
 | 
						|
		int             start_x,
 | 
						|
		int             end_x)
 | 
						|
{
 | 
						|
  switch (uline)
 | 
						|
    {
 | 
						|
    case PANGO_UNDERLINE_NONE:
 | 
						|
      break;
 | 
						|
    case PANGO_UNDERLINE_DOUBLE:
 | 
						|
      gdk_draw_line (drawable, gc,
 | 
						|
		     start_x, baseline_y + 3,
 | 
						|
		     end_x,   baseline_y + 3);
 | 
						|
      /* Fall through */
 | 
						|
    case PANGO_UNDERLINE_SINGLE:
 | 
						|
      gdk_draw_line (drawable, gc,
 | 
						|
		     start_x, baseline_y + 1,
 | 
						|
		     end_x,   baseline_y + 1);
 | 
						|
      break;
 | 
						|
    case PANGO_UNDERLINE_LOW:
 | 
						|
      gdk_draw_line (drawable, gc,
 | 
						|
		     start_x, low_y + 1,
 | 
						|
		     end_x,   low_y + 1);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_draw_layout_line_with_colors:
 | 
						|
 * @drawable:  the drawable on which to draw the line
 | 
						|
 * @gc:        base graphics to use
 | 
						|
 * @x:         the x position of start of string (in pixels)
 | 
						|
 * @y:         the y position of baseline (in pixels)
 | 
						|
 * @line:      a #PangoLayoutLine
 | 
						|
 * @foreground: foreground override color, or %NULL for none
 | 
						|
 * @background: background override color, or %NULL for none
 | 
						|
 *
 | 
						|
 * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the
 | 
						|
 * layout's normal colors with @foreground and/or @background.
 | 
						|
 * @foreground and @background need not be allocated.
 | 
						|
 */
 | 
						|
void 
 | 
						|
gdk_draw_layout_line_with_colors (GdkDrawable      *drawable,
 | 
						|
                                  GdkGC            *gc,
 | 
						|
                                  gint              x, 
 | 
						|
                                  gint              y,
 | 
						|
                                  PangoLayoutLine  *line,
 | 
						|
                                  GdkColor         *foreground,
 | 
						|
                                  GdkColor         *background)
 | 
						|
{
 | 
						|
  GSList *tmp_list = line->runs;
 | 
						|
  PangoRectangle overall_rect;
 | 
						|
  PangoRectangle logical_rect;
 | 
						|
  PangoRectangle ink_rect;
 | 
						|
  PangoContext *context;
 | 
						|
  gint x_off = 0;
 | 
						|
  gint rise = 0;
 | 
						|
  gboolean embossed;
 | 
						|
  GdkBitmap *stipple;
 | 
						|
  PangoUnderline last_uline = PANGO_UNDERLINE_NONE;
 | 
						|
  gint uline_start_x = 0;
 | 
						|
  gint uline_end_x = 0;
 | 
						|
  gint uline_end_x_extended = 0;
 | 
						|
  gint last_risen_y = 0;
 | 
						|
  gint low_y = G_MININT;
 | 
						|
  GdkGC *last_fg_gc = NULL;
 | 
						|
  gboolean last_fg_set = FALSE;
 | 
						|
  PangoColor last_fg_color;
 | 
						|
 | 
						|
  g_return_if_fail (GDK_IS_DRAWABLE (drawable));
 | 
						|
  g_return_if_fail (GDK_IS_GC (gc));
 | 
						|
  g_return_if_fail (line != NULL);
 | 
						|
 | 
						|
  context = pango_layout_get_context (line->layout);
 | 
						|
  
 | 
						|
  pango_layout_line_get_extents (line,NULL, &overall_rect);
 | 
						|
  
 | 
						|
  while (tmp_list)
 | 
						|
    {
 | 
						|
      PangoUnderline this_uline = PANGO_UNDERLINE_NONE;
 | 
						|
      PangoLayoutRun *run = tmp_list->data;
 | 
						|
      PangoColor fg_color, bg_color;
 | 
						|
      gboolean strike, fg_set, bg_set, shape_set;
 | 
						|
      GdkGC *fg_gc;
 | 
						|
      gint risen_y;
 | 
						|
      
 | 
						|
      tmp_list = tmp_list->next;
 | 
						|
      
 | 
						|
      gdk_pango_get_item_properties (run->item, &this_uline,
 | 
						|
				     &strike,
 | 
						|
                                     &rise,
 | 
						|
                                     &fg_color, &fg_set,
 | 
						|
                                     &bg_color, &bg_set,
 | 
						|
                                     &embossed,
 | 
						|
                                     &stipple,
 | 
						|
                                     &shape_set,
 | 
						|
                                     &ink_rect,
 | 
						|
				     &logical_rect);
 | 
						|
 | 
						|
      /* we subtract the rise because X coordinates are upside down */
 | 
						|
      risen_y = y - rise / PANGO_SCALE;
 | 
						|
      
 | 
						|
      if (!shape_set)
 | 
						|
	{
 | 
						|
	  if (this_uline == PANGO_UNDERLINE_NONE)
 | 
						|
	    pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
 | 
						|
					NULL, &logical_rect);
 | 
						|
	  else
 | 
						|
	    pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
 | 
						|
					&ink_rect, &logical_rect);
 | 
						|
	}
 | 
						|
 | 
						|
      if (bg_set || background)
 | 
						|
	{
 | 
						|
	  GdkGC *bg_gc;
 | 
						|
          PangoColor tmp = bg_color;
 | 
						|
          
 | 
						|
          if (background)
 | 
						|
            {
 | 
						|
              tmp.red = background->red;
 | 
						|
              tmp.blue = background->blue;
 | 
						|
              tmp.green = background->green;
 | 
						|
            }
 | 
						|
          
 | 
						|
          bg_gc = gdk_pango_get_gc (drawable, context, &tmp, stipple, gc);
 | 
						|
          
 | 
						|
	  gdk_draw_rectangle (drawable, bg_gc, TRUE,
 | 
						|
			      x + (x_off + logical_rect.x) / PANGO_SCALE,
 | 
						|
			      risen_y + overall_rect.y / PANGO_SCALE,
 | 
						|
			      logical_rect.width / PANGO_SCALE,
 | 
						|
			      overall_rect.height / PANGO_SCALE);
 | 
						|
 | 
						|
          if (stipple)
 | 
						|
            gdk_gc_set_fill (bg_gc, GDK_SOLID);
 | 
						|
          
 | 
						|
	  gdk_pango_free_gc (context, bg_gc);
 | 
						|
	}
 | 
						|
 | 
						|
      if (fg_set || stipple || foreground)
 | 
						|
        {
 | 
						|
          PangoColor tmp = fg_color;
 | 
						|
          
 | 
						|
          if (foreground)
 | 
						|
            {
 | 
						|
              tmp.red = foreground->red;
 | 
						|
              tmp.blue = foreground->blue;
 | 
						|
              tmp.green = foreground->green;
 | 
						|
            }
 | 
						|
          
 | 
						|
          fg_gc = gdk_pango_get_gc (drawable, context, (fg_set || foreground) ? &tmp : NULL,
 | 
						|
                                    stipple, gc);
 | 
						|
        }
 | 
						|
      else
 | 
						|
	fg_gc = gc;
 | 
						|
 | 
						|
      if (!shape_set)
 | 
						|
        {
 | 
						|
          gint gx, gy;
 | 
						|
 | 
						|
          gx = x + x_off / PANGO_SCALE;
 | 
						|
          gy = risen_y;
 | 
						|
          
 | 
						|
          if (embossed)
 | 
						|
            {
 | 
						|
              PangoColor color = { 65535, 65535, 65535 };
 | 
						|
              GdkGC *white_gc = gdk_pango_get_gc (drawable, context, &color, stipple, fg_gc);
 | 
						|
              gdk_draw_glyphs (drawable, white_gc, run->item->analysis.font,
 | 
						|
                               gx + 1,
 | 
						|
                               gy + 1,
 | 
						|
                               run->glyphs);
 | 
						|
              gdk_pango_free_gc (context, white_gc);
 | 
						|
            }
 | 
						|
          
 | 
						|
          gdk_draw_glyphs (drawable, fg_gc, run->item->analysis.font,
 | 
						|
                           gx, gy,
 | 
						|
                           run->glyphs);
 | 
						|
        }
 | 
						|
 | 
						|
      if (this_uline != last_uline ||
 | 
						|
	  risen_y != last_risen_y ||
 | 
						|
	  fg_set != last_fg_set ||
 | 
						|
	  (fg_set && (last_fg_color.red != fg_color.red ||
 | 
						|
		      last_fg_color.green != fg_color.green ||
 | 
						|
		      last_fg_color.blue != fg_color.blue)))
 | 
						|
	{
 | 
						|
	  /* If only color changes, the underlines extend to the edge
 | 
						|
	   * of the logical rectangle so they join up; otherwise they
 | 
						|
	   * go 1 pixel beyond the ink rectangle. This doesn't work
 | 
						|
	   * for low underlines (they will be at a different y anyways),
 | 
						|
	   * so they follow the normal path.
 | 
						|
	   */
 | 
						|
	  gboolean extend_uline = (this_uline == last_uline &&
 | 
						|
				   this_uline != PANGO_UNDERLINE_LOW &&
 | 
						|
				   risen_y == last_risen_y);
 | 
						|
	  
 | 
						|
	  /* Starting a new underline run
 | 
						|
	   */
 | 
						|
	  if (last_uline != PANGO_UNDERLINE_NONE)
 | 
						|
	    {
 | 
						|
	      draw_underline (drawable, last_fg_gc, last_uline,
 | 
						|
			      last_risen_y, low_y,
 | 
						|
			      uline_start_x,
 | 
						|
			      extend_uline ? uline_end_x_extended : uline_end_x);
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (this_uline != PANGO_UNDERLINE_NONE)
 | 
						|
	    {
 | 
						|
	      if (extend_uline)
 | 
						|
		uline_start_x = x + x_off / PANGO_SCALE;
 | 
						|
	      else
 | 
						|
		uline_start_x = x + (x_off + ink_rect.x) / PANGO_SCALE - 1;
 | 
						|
 | 
						|
	      low_y = G_MININT;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
      /* Update current underline segment information
 | 
						|
       */
 | 
						|
      if (this_uline != PANGO_UNDERLINE_NONE)
 | 
						|
	{
 | 
						|
	  uline_end_x = x + (x_off + ink_rect.x + ink_rect.width) / PANGO_SCALE;
 | 
						|
	  uline_end_x_extended = x + (x_off + logical_rect.x + logical_rect.width) / PANGO_SCALE - 1;
 | 
						|
	}
 | 
						|
 | 
						|
      if (this_uline == PANGO_UNDERLINE_LOW)
 | 
						|
	low_y = MAX (low_y, risen_y + (ink_rect.y + ink_rect.height) / PANGO_SCALE);
 | 
						|
 | 
						|
      if (strike)
 | 
						|
	{
 | 
						|
	  int centerline = logical_rect.y + logical_rect.height / 2;
 | 
						|
	  
 | 
						|
	  gdk_draw_line (drawable, fg_gc,
 | 
						|
			 x + (x_off + logical_rect.x) / PANGO_SCALE - 1,
 | 
						|
			 risen_y + centerline / PANGO_SCALE,
 | 
						|
			 x + (x_off + logical_rect.x + logical_rect.width) / PANGO_SCALE + 1,
 | 
						|
			 risen_y + centerline / PANGO_SCALE);
 | 
						|
	}
 | 
						|
 | 
						|
      if (last_fg_gc != gc && last_fg_gc)
 | 
						|
	gdk_pango_free_gc (context, last_fg_gc);
 | 
						|
 | 
						|
      last_risen_y = risen_y;
 | 
						|
      last_uline = this_uline;
 | 
						|
      last_fg_gc = fg_gc;
 | 
						|
      last_fg_set = fg_set;
 | 
						|
      if (fg_set)
 | 
						|
	last_fg_color = fg_color;
 | 
						|
      
 | 
						|
      x_off += logical_rect.width;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Finish off any remaining underlines
 | 
						|
   */
 | 
						|
  if (last_uline != PANGO_UNDERLINE_NONE)
 | 
						|
    draw_underline (drawable, last_fg_gc, last_uline, last_risen_y, low_y,
 | 
						|
		    uline_start_x, uline_end_x);
 | 
						|
 | 
						|
  if (last_fg_gc != gc && last_fg_gc)
 | 
						|
    gdk_pango_free_gc (context, last_fg_gc);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_draw_layout_with_colors:
 | 
						|
 * @drawable:  the drawable on which to draw string
 | 
						|
 * @gc:        base graphics context to use
 | 
						|
 * @x:         the X position of the left of the layout (in pixels)
 | 
						|
 * @y:         the Y position of the top of the layout (in pixels)
 | 
						|
 * @layout:    a #PangoLayout
 | 
						|
 * @foreground: foreground override color, or %NULL for none
 | 
						|
 * @background: background override color, or %NULL for none
 | 
						|
 *
 | 
						|
 * Render a #PangoLayout onto a #GdkDrawable, overriding the
 | 
						|
 * layout's normal colors with @foreground and/or @background.
 | 
						|
 * @foreground and @background need not be allocated.
 | 
						|
 *
 | 
						|
 * If you're using GTK+, the ususal way to obtain a #PangoLayout
 | 
						|
 * is gtk_widget_create_pango_layout().
 | 
						|
 */
 | 
						|
void 
 | 
						|
gdk_draw_layout_with_colors (GdkDrawable     *drawable,
 | 
						|
                             GdkGC           *gc,
 | 
						|
                             int              x, 
 | 
						|
                             int              y,
 | 
						|
                             PangoLayout     *layout,
 | 
						|
                             GdkColor        *foreground,
 | 
						|
                             GdkColor        *background)
 | 
						|
{
 | 
						|
  PangoLayoutIter *iter;
 | 
						|
  
 | 
						|
  g_return_if_fail (GDK_IS_DRAWABLE (drawable));
 | 
						|
  g_return_if_fail (GDK_IS_GC (gc));
 | 
						|
  g_return_if_fail (PANGO_IS_LAYOUT (layout));
 | 
						|
 | 
						|
  iter = pango_layout_get_iter (layout);
 | 
						|
  
 | 
						|
  do
 | 
						|
    {
 | 
						|
      PangoRectangle logical_rect;
 | 
						|
      PangoLayoutLine *line;
 | 
						|
      int baseline;
 | 
						|
      
 | 
						|
      line = pango_layout_iter_get_line (iter);
 | 
						|
      
 | 
						|
      pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
 | 
						|
      baseline = pango_layout_iter_get_baseline (iter);
 | 
						|
      
 | 
						|
      gdk_draw_layout_line_with_colors (drawable, gc,
 | 
						|
                                        x + logical_rect.x / PANGO_SCALE,
 | 
						|
                                        y + baseline / PANGO_SCALE,
 | 
						|
                                        line,
 | 
						|
                                        foreground,
 | 
						|
                                        background);
 | 
						|
    }
 | 
						|
  while (pango_layout_iter_next_line (iter));
 | 
						|
 | 
						|
  pango_layout_iter_free (iter);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_draw_layout_line:
 | 
						|
 * @drawable:  the drawable on which to draw the line
 | 
						|
 * @gc:        base graphics to use
 | 
						|
 * @x:         the x position of start of string (in pixels)
 | 
						|
 * @y:         the y position of baseline (in pixels)
 | 
						|
 * @line:      a #PangoLayoutLine
 | 
						|
 *
 | 
						|
 * Render a #PangoLayoutLine onto an GDK drawable
 | 
						|
 */
 | 
						|
void 
 | 
						|
gdk_draw_layout_line (GdkDrawable      *drawable,
 | 
						|
		      GdkGC            *gc,
 | 
						|
		      gint              x, 
 | 
						|
		      gint              y,
 | 
						|
		      PangoLayoutLine  *line)
 | 
						|
{
 | 
						|
  g_return_if_fail (GDK_IS_DRAWABLE (drawable));
 | 
						|
  g_return_if_fail (GDK_IS_GC (gc));
 | 
						|
  g_return_if_fail (line != NULL);
 | 
						|
  
 | 
						|
  gdk_draw_layout_line_with_colors (drawable, gc, x, y, line, NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_draw_layout:
 | 
						|
 * @drawable:  the drawable on which to draw string
 | 
						|
 * @gc:        base graphics context to use
 | 
						|
 * @x:         the X position of the left of the layout (in pixels)
 | 
						|
 * @y:         the Y position of the top of the layout (in pixels)
 | 
						|
 * @layout:    a #PangoLayout
 | 
						|
 *
 | 
						|
 * Render a #PangoLayout onto a GDK drawable
 | 
						|
 *
 | 
						|
 * If you're using GTK+, the ususal way to obtain a #PangoLayout
 | 
						|
 * is gtk_widget_create_pango_layout().
 | 
						|
 */
 | 
						|
void 
 | 
						|
gdk_draw_layout (GdkDrawable     *drawable,
 | 
						|
		 GdkGC           *gc,
 | 
						|
		 int              x, 
 | 
						|
		 int              y,
 | 
						|
		 PangoLayout     *layout)
 | 
						|
{
 | 
						|
  g_return_if_fail (GDK_IS_DRAWABLE (drawable));
 | 
						|
  g_return_if_fail (GDK_IS_GC (gc));
 | 
						|
  g_return_if_fail (PANGO_IS_LAYOUT (layout));
 | 
						|
 | 
						|
  gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_pango_get_item_properties (PangoItem      *item,
 | 
						|
			       PangoUnderline *uline,
 | 
						|
			       gboolean       *strikethrough,
 | 
						|
                               gint           *rise,
 | 
						|
			       PangoColor     *fg_color,
 | 
						|
			       gboolean       *fg_set,
 | 
						|
			       PangoColor     *bg_color,
 | 
						|
			       gboolean       *bg_set,
 | 
						|
                               gboolean       *embossed,
 | 
						|
                               GdkBitmap     **stipple,
 | 
						|
			       gboolean       *shape_set,
 | 
						|
			       PangoRectangle *ink_rect,
 | 
						|
			       PangoRectangle *logical_rect)
 | 
						|
{
 | 
						|
  GSList *tmp_list = item->analysis.extra_attrs;
 | 
						|
 | 
						|
  if (strikethrough)
 | 
						|
      *strikethrough = FALSE;
 | 
						|
  
 | 
						|
  if (fg_set)
 | 
						|
    *fg_set = FALSE;
 | 
						|
  
 | 
						|
  if (bg_set)
 | 
						|
    *bg_set = FALSE;
 | 
						|
 | 
						|
  if (shape_set)
 | 
						|
    *shape_set = FALSE;
 | 
						|
 | 
						|
  if (rise)
 | 
						|
    *rise = 0;
 | 
						|
 | 
						|
  if (embossed)
 | 
						|
    *embossed = FALSE;
 | 
						|
 | 
						|
  if (stipple)
 | 
						|
    *stipple = NULL;
 | 
						|
  
 | 
						|
  while (tmp_list)
 | 
						|
    {
 | 
						|
      PangoAttribute *attr = tmp_list->data;
 | 
						|
 | 
						|
      switch (attr->klass->type)
 | 
						|
	{
 | 
						|
	case PANGO_ATTR_UNDERLINE:
 | 
						|
	  if (uline)
 | 
						|
	    *uline = ((PangoAttrInt *)attr)->value;
 | 
						|
	  break;
 | 
						|
 | 
						|
	case PANGO_ATTR_STRIKETHROUGH:
 | 
						|
	    if (strikethrough)
 | 
						|
		*strikethrough = ((PangoAttrInt *)attr)->value;
 | 
						|
	    break;
 | 
						|
	    
 | 
						|
	case PANGO_ATTR_FOREGROUND:
 | 
						|
	  if (fg_color)
 | 
						|
	    *fg_color = ((PangoAttrColor *)attr)->color;
 | 
						|
	  if (fg_set)
 | 
						|
	    *fg_set = TRUE;
 | 
						|
	  
 | 
						|
	  break;
 | 
						|
	  
 | 
						|
	case PANGO_ATTR_BACKGROUND:
 | 
						|
	  if (bg_color)
 | 
						|
	    *bg_color = ((PangoAttrColor *)attr)->color;
 | 
						|
	  if (bg_set)
 | 
						|
	    *bg_set = TRUE;
 | 
						|
	  
 | 
						|
	  break;
 | 
						|
 | 
						|
	case PANGO_ATTR_SHAPE:
 | 
						|
	  if (shape_set)
 | 
						|
	    *shape_set = TRUE;
 | 
						|
	  if (logical_rect)
 | 
						|
	    *logical_rect = ((PangoAttrShape *)attr)->logical_rect;
 | 
						|
	  if (ink_rect)
 | 
						|
	    *ink_rect = ((PangoAttrShape *)attr)->ink_rect;
 | 
						|
	  break;
 | 
						|
 | 
						|
        case PANGO_ATTR_RISE:
 | 
						|
          if (rise)
 | 
						|
            *rise = ((PangoAttrInt *)attr)->value;
 | 
						|
          break;
 | 
						|
          
 | 
						|
	default:
 | 
						|
          /* stipple_type and embossed_type aren't necessarily
 | 
						|
           * initialized, but they are 0, which is an
 | 
						|
           * invalid type so won't occur. 
 | 
						|
           */
 | 
						|
          if (stipple && attr->klass->type == gdk_pango_attr_stipple_type)
 | 
						|
            {
 | 
						|
              *stipple = ((GdkPangoAttrStipple*)attr)->stipple;
 | 
						|
            }
 | 
						|
          else if (embossed && attr->klass->type == gdk_pango_attr_embossed_type)
 | 
						|
            {
 | 
						|
              *embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
 | 
						|
            }
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
      tmp_list = tmp_list->next;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static PangoAttribute *
 | 
						|
gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
 | 
						|
{
 | 
						|
  const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr;
 | 
						|
 | 
						|
  return gdk_pango_attr_stipple_new (src->stipple);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_pango_attr_stipple_destroy (PangoAttribute *attr)
 | 
						|
{
 | 
						|
  GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr;
 | 
						|
 | 
						|
  if (st->stipple)
 | 
						|
    g_object_unref (st->stipple);
 | 
						|
  
 | 
						|
  g_free (attr);
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
gdk_pango_attr_stipple_compare (const PangoAttribute *attr1,
 | 
						|
                                    const PangoAttribute *attr2)
 | 
						|
{
 | 
						|
  const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1;
 | 
						|
  const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2;
 | 
						|
 | 
						|
  return a->stipple == b->stipple;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_pango_attr_stipple_new:
 | 
						|
 * @stipple: a bitmap to be set as stipple
 | 
						|
 *
 | 
						|
 * Creates a new attribute containing a stipple bitmap to be used when
 | 
						|
 * rendering the text.
 | 
						|
 *
 | 
						|
 * Return value: new #PangoAttribute
 | 
						|
 **/
 | 
						|
 | 
						|
PangoAttribute *
 | 
						|
gdk_pango_attr_stipple_new (GdkBitmap *stipple)
 | 
						|
{
 | 
						|
  GdkPangoAttrStipple *result;
 | 
						|
  
 | 
						|
  static PangoAttrClass klass = {
 | 
						|
    0,
 | 
						|
    gdk_pango_attr_stipple_copy,
 | 
						|
    gdk_pango_attr_stipple_destroy,
 | 
						|
    gdk_pango_attr_stipple_compare
 | 
						|
  };
 | 
						|
 | 
						|
  if (!klass.type)
 | 
						|
    klass.type = gdk_pango_attr_stipple_type =
 | 
						|
      pango_attr_type_register ("GdkPangoAttrStipple");
 | 
						|
 | 
						|
  result = g_new (GdkPangoAttrStipple, 1);
 | 
						|
  result->attr.klass = &klass;
 | 
						|
 | 
						|
  if (stipple)
 | 
						|
    g_object_ref (stipple);
 | 
						|
  
 | 
						|
  result->stipple = stipple;
 | 
						|
 | 
						|
  return (PangoAttribute *)result;
 | 
						|
}
 | 
						|
 | 
						|
static PangoAttribute *
 | 
						|
gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
 | 
						|
{
 | 
						|
  const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr;
 | 
						|
 | 
						|
  return gdk_pango_attr_embossed_new (e->embossed);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gdk_pango_attr_embossed_destroy (PangoAttribute *attr)
 | 
						|
{
 | 
						|
  g_free (attr);
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
 | 
						|
                                 const PangoAttribute *attr2)
 | 
						|
{
 | 
						|
  const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1;
 | 
						|
  const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2;
 | 
						|
 | 
						|
  return e1->embossed == e2->embossed;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_pango_attr_embossed_new:
 | 
						|
 * @embossed: a bitmap to be set as embossed
 | 
						|
 *
 | 
						|
 * Creates a new attribute containing a embossed bitmap to be used when
 | 
						|
 * rendering the text.
 | 
						|
 *
 | 
						|
 * Return value: new #PangoAttribute
 | 
						|
 **/
 | 
						|
 | 
						|
PangoAttribute *
 | 
						|
gdk_pango_attr_embossed_new (gboolean embossed)
 | 
						|
{
 | 
						|
  GdkPangoAttrEmbossed *result;
 | 
						|
  
 | 
						|
  static PangoAttrClass klass = {
 | 
						|
    0,
 | 
						|
    gdk_pango_attr_embossed_copy,
 | 
						|
    gdk_pango_attr_embossed_destroy,
 | 
						|
    gdk_pango_attr_embossed_compare
 | 
						|
  };
 | 
						|
 | 
						|
  if (!klass.type)
 | 
						|
    klass.type = gdk_pango_attr_embossed_type =
 | 
						|
      pango_attr_type_register ("GdkPangoAttrEmbossed");
 | 
						|
 | 
						|
  result = g_new (GdkPangoAttrEmbossed, 1);
 | 
						|
  result->attr.klass = &klass;
 | 
						|
  result->embossed = embossed;
 | 
						|
  
 | 
						|
  return (PangoAttribute *)result;
 | 
						|
}
 | 
						|
 | 
						|
/* Get a clip region to draw only part of a layout. index_ranges
 | 
						|
 * contains alternating range starts/stops. The region is the
 | 
						|
 * region which contains the given ranges, i.e. if you draw with the
 | 
						|
 * region as clip, only the given ranges are drawn.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_pango_layout_line_get_clip_region:
 | 
						|
 * @line: a #PangoLayoutLine 
 | 
						|
 * @x_origin: X pixel where you intend to draw the layout line with this clip
 | 
						|
 * @y_origin: baseline pixel where you intend to draw the layout line with this clip
 | 
						|
 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
 | 
						|
 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
 | 
						|
 * 
 | 
						|
 * Obtains a clip region which contains the areas where the given
 | 
						|
 * ranges of text would be drawn. @x_origin and @y_origin are the same
 | 
						|
 * position you would pass to gdk_draw_layout_line(). @index_ranges
 | 
						|
 * should contain ranges of bytes in the layout's text. The clip
 | 
						|
 * region will include space to the left or right of the line (to the
 | 
						|
 * layout bounding box) if you have indexes above or below the indexes
 | 
						|
 * contained inside the line. This is to draw the selection all the way
 | 
						|
 * to the side of the layout. However, the clip region is in line coordinates,
 | 
						|
 * not layout coordinates.
 | 
						|
 * 
 | 
						|
 * Return value: a clip region containing the given ranges
 | 
						|
 **/
 | 
						|
GdkRegion*
 | 
						|
gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
 | 
						|
                                       gint             x_origin,
 | 
						|
                                       gint             y_origin,
 | 
						|
                                       gint            *index_ranges,
 | 
						|
                                       gint             n_ranges)
 | 
						|
{
 | 
						|
  GdkRegion *clip_region;
 | 
						|
  gint i;
 | 
						|
  PangoRectangle logical_rect;
 | 
						|
  PangoLayoutIter *iter;
 | 
						|
  gint baseline;
 | 
						|
  
 | 
						|
  g_return_val_if_fail (line != NULL, NULL);
 | 
						|
  g_return_val_if_fail (index_ranges != NULL, NULL);
 | 
						|
  
 | 
						|
  clip_region = gdk_region_new ();
 | 
						|
 | 
						|
  iter = pango_layout_get_iter (line->layout);
 | 
						|
  while (pango_layout_iter_get_line (iter) != line)
 | 
						|
    pango_layout_iter_next_line (iter);
 | 
						|
  
 | 
						|
  pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
 | 
						|
  baseline = pango_layout_iter_get_baseline (iter);
 | 
						|
  
 | 
						|
  pango_layout_iter_free (iter);
 | 
						|
  
 | 
						|
  i = 0;
 | 
						|
  while (i < n_ranges)
 | 
						|
    {  
 | 
						|
      gint *pixel_ranges = NULL;
 | 
						|
      gint n_pixel_ranges = 0;
 | 
						|
      gint j;
 | 
						|
 | 
						|
      /* Note that get_x_ranges returns layout coordinates
 | 
						|
       */
 | 
						|
      pango_layout_line_get_x_ranges (line,
 | 
						|
                                      index_ranges[i*2],
 | 
						|
                                      index_ranges[i*2+1],
 | 
						|
                                      &pixel_ranges, &n_pixel_ranges);
 | 
						|
  
 | 
						|
      for (j=0; j < n_pixel_ranges; j++)
 | 
						|
        {
 | 
						|
          GdkRectangle rect;
 | 
						|
          
 | 
						|
          rect.x = x_origin + pixel_ranges[2*j] / PANGO_SCALE - logical_rect.x / PANGO_SCALE;
 | 
						|
          rect.y = y_origin - (baseline / PANGO_SCALE - logical_rect.y / PANGO_SCALE);
 | 
						|
          rect.width = (pixel_ranges[2*j + 1] - pixel_ranges[2*j]) / PANGO_SCALE;
 | 
						|
          rect.height = logical_rect.height / PANGO_SCALE;
 | 
						|
          
 | 
						|
          gdk_region_union_with_rect (clip_region, &rect);
 | 
						|
        }
 | 
						|
 | 
						|
      g_free (pixel_ranges);
 | 
						|
      ++i;
 | 
						|
    }
 | 
						|
 | 
						|
  return clip_region;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_pango_layout_get_clip_region:
 | 
						|
 * @layout: a #PangoLayout 
 | 
						|
 * @x_origin: X pixel where you intend to draw the layout with this clip
 | 
						|
 * @y_origin: Y pixel where you intend to draw the layout with this clip
 | 
						|
 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
 | 
						|
 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
 | 
						|
 * 
 | 
						|
 * Obtains a clip region which contains the areas where the given ranges
 | 
						|
 * of text would be drawn. @x_origin and @y_origin are the same position
 | 
						|
 * you would pass to gdk_draw_layout_line(). @index_ranges should contain
 | 
						|
 * ranges of bytes in the layout's text.
 | 
						|
 * 
 | 
						|
 * Return value: a clip region containing the given ranges
 | 
						|
 **/
 | 
						|
GdkRegion*
 | 
						|
gdk_pango_layout_get_clip_region (PangoLayout *layout,
 | 
						|
                                  gint         x_origin,
 | 
						|
                                  gint         y_origin,
 | 
						|
                                  gint        *index_ranges,
 | 
						|
                                  gint         n_ranges)
 | 
						|
{
 | 
						|
  PangoLayoutIter *iter;  
 | 
						|
  GdkRegion *clip_region;
 | 
						|
  
 | 
						|
  g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
 | 
						|
  g_return_val_if_fail (index_ranges != NULL, NULL);
 | 
						|
  
 | 
						|
  clip_region = gdk_region_new ();
 | 
						|
  
 | 
						|
  iter = pango_layout_get_iter (layout);
 | 
						|
  
 | 
						|
  do
 | 
						|
    {
 | 
						|
      PangoRectangle logical_rect;
 | 
						|
      PangoLayoutLine *line;
 | 
						|
      GdkRegion *line_region;
 | 
						|
      gint baseline;
 | 
						|
      
 | 
						|
      line = pango_layout_iter_get_line (iter);      
 | 
						|
 | 
						|
      pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
 | 
						|
      baseline = pango_layout_iter_get_baseline (iter);      
 | 
						|
 | 
						|
      line_region = gdk_pango_layout_line_get_clip_region (line,
 | 
						|
                                                           x_origin + logical_rect.x / PANGO_SCALE,
 | 
						|
                                                           y_origin + baseline / PANGO_SCALE,
 | 
						|
                                                           index_ranges,
 | 
						|
                                                           n_ranges);
 | 
						|
 | 
						|
      gdk_region_union (clip_region, line_region);
 | 
						|
      gdk_region_destroy (line_region);
 | 
						|
    }
 | 
						|
  while (pango_layout_iter_next_line (iter));
 | 
						|
 | 
						|
  pango_layout_iter_free (iter);
 | 
						|
 | 
						|
  return clip_region;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gdk_pango_context_get:
 | 
						|
 * 
 | 
						|
 * Creates a #PangoContext for the default GDK screen.
 | 
						|
 *
 | 
						|
 * The context must be freed when you're finished with it.
 | 
						|
 * 
 | 
						|
 * When using GTK+, normally you should use gtk_widget_get_pango_context()
 | 
						|
 * instead of this function, to get the appropriate context for
 | 
						|
 * the widget you intend to render text onto.
 | 
						|
 * 
 | 
						|
 * Return value: a new #PangoContext for the default display
 | 
						|
 **/
 | 
						|
PangoContext *
 | 
						|
gdk_pango_context_get (void)
 | 
						|
{
 | 
						|
  return gdk_pango_context_get_for_screen (gdk_screen_get_default ());
 | 
						|
}
 |