Blame pango/pangoft2-render.c

Packit 0ec9dd
/* Pango
Packit 0ec9dd
 * pangoft2-render.c: Rendering routines to FT_Bitmap objects
Packit 0ec9dd
 *
Packit 0ec9dd
 * Copyright (C) 2004 Red Hat Software
Packit 0ec9dd
 * Copyright (C) 2000 Tor Lillqvist
Packit 0ec9dd
 *
Packit 0ec9dd
 * This library is free software; you can redistribute it and/or
Packit 0ec9dd
 * modify it under the terms of the GNU Library General Public
Packit 0ec9dd
 * License as published by the Free Software Foundation; either
Packit 0ec9dd
 * version 2 of the License, or (at your option) any later version.
Packit 0ec9dd
 *
Packit 0ec9dd
 * This library is distributed in the hope that it will be useful,
Packit 0ec9dd
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 0ec9dd
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
Packit 0ec9dd
 * Library General Public License for more details.
Packit 0ec9dd
 *
Packit 0ec9dd
 * You should have received a copy of the GNU Library General Public
Packit 0ec9dd
 * License along with this library; if not, write to the
Packit 0ec9dd
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 0ec9dd
 * Boston, MA 02111-1307, USA.
Packit 0ec9dd
 */
Packit 0ec9dd
Packit 0ec9dd
/**
Packit 0ec9dd
 * SECTION:pango-renderer
Packit 0ec9dd
 * @short_description:Rendering driver base class
Packit 0ec9dd
 * @title:PangoRenderer
Packit 0ec9dd
 *
Packit 0ec9dd
 * #PangoRenderer is a base class that contains the necessary logic for
Packit 0ec9dd
 * rendering a #PangoLayout or #PangoLayoutLine. By subclassing
Packit 0ec9dd
 * #PangoRenderer and overriding operations such as @draw_glyphs and
Packit 0ec9dd
 * @draw_rectangle, renderers for particular font backends and
Packit 0ec9dd
 * destinations can be created.
Packit 0ec9dd
 */
Packit 0ec9dd
#include "config.h"
Packit 0ec9dd
#include <math.h>
Packit 0ec9dd
Packit 0ec9dd
#include "pangoft2-private.h"
Packit 0ec9dd
Packit 0ec9dd
/* for compatibility with older freetype versions */
Packit 0ec9dd
#ifndef FT_LOAD_TARGET_MONO
Packit 0ec9dd
#define FT_LOAD_TARGET_MONO  FT_LOAD_MONOCHROME
Packit 0ec9dd
#endif
Packit 0ec9dd
Packit 0ec9dd
typedef struct _PangoFT2RendererClass PangoFT2RendererClass;
Packit 0ec9dd
Packit 0ec9dd
#define PANGO_FT2_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass))
Packit 0ec9dd
#define PANGO_IS_FT2_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FT2_RENDERER))
Packit 0ec9dd
#define PANGO_FT2_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass))
Packit 0ec9dd
Packit 0ec9dd
struct _PangoFT2Renderer
Packit 0ec9dd
{
Packit 0ec9dd
  PangoRenderer parent_instance;
Packit 0ec9dd
Packit 0ec9dd
  FT_Bitmap *bitmap;
Packit 0ec9dd
};
Packit 0ec9dd
Packit 0ec9dd
struct _PangoFT2RendererClass
Packit 0ec9dd
{
Packit 0ec9dd
  PangoRendererClass parent_class;
Packit 0ec9dd
};
Packit 0ec9dd
Packit 0ec9dd
static void pango_ft2_renderer_draw_glyph     (PangoRenderer    *renderer,
Packit 0ec9dd
					       PangoFont        *font,
Packit 0ec9dd
					       PangoGlyph        glyph,
Packit 0ec9dd
					       double            x,
Packit 0ec9dd
					       double            y);
Packit 0ec9dd
static void pango_ft2_renderer_draw_trapezoid (PangoRenderer    *renderer,
Packit 0ec9dd
					       PangoRenderPart   part,
Packit 0ec9dd
					       double            y1,
Packit 0ec9dd
					       double            x11,
Packit 0ec9dd
					       double            x21,
Packit 0ec9dd
					       double            y2,
Packit 0ec9dd
					       double            x12,
Packit 0ec9dd
					       double            x22);
Packit 0ec9dd
Packit 0ec9dd
G_DEFINE_TYPE (PangoFT2Renderer, pango_ft2_renderer, PANGO_TYPE_RENDERER)
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
pango_ft2_renderer_init (PangoFT2Renderer *renderer G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
pango_ft2_renderer_class_init (PangoFT2RendererClass *klass)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
Packit 0ec9dd
Packit 0ec9dd
  renderer_class->draw_glyph = pango_ft2_renderer_draw_glyph;
Packit 0ec9dd
  renderer_class->draw_trapezoid = pango_ft2_renderer_draw_trapezoid;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
pango_ft2_renderer_set_bitmap (PangoFT2Renderer *renderer,
Packit 0ec9dd
			      FT_Bitmap         *bitmap)
Packit 0ec9dd
{
Packit 0ec9dd
  renderer->bitmap = bitmap;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
typedef struct
Packit 0ec9dd
{
Packit 0ec9dd
  FT_Bitmap bitmap;
Packit 0ec9dd
  int bitmap_left;
Packit 0ec9dd
  int bitmap_top;
Packit 0ec9dd
} PangoFT2RenderedGlyph;
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
pango_ft2_free_rendered_glyph (PangoFT2RenderedGlyph *rendered)
Packit 0ec9dd
{
Packit 0ec9dd
  g_free (rendered->bitmap.buffer);
Packit 0ec9dd
  g_slice_free (PangoFT2RenderedGlyph, rendered);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static PangoFT2RenderedGlyph *
Packit 0ec9dd
pango_ft2_font_render_box_glyph (int      width,
Packit 0ec9dd
				 int      height,
Packit 0ec9dd
				 int      top,
Packit 0ec9dd
				 gboolean invalid)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFT2RenderedGlyph *box;
Packit 0ec9dd
  int i, j, offset1, offset2, line_width;
Packit 0ec9dd
Packit 0ec9dd
  line_width = MAX ((height + 43) / 44, 1);
Packit 0ec9dd
  if (width < 1 || height < 1)
Packit 0ec9dd
    line_width = 0;
Packit 0ec9dd
Packit 0ec9dd
  box = g_slice_new (PangoFT2RenderedGlyph);
Packit 0ec9dd
Packit 0ec9dd
  box->bitmap_left = 0;
Packit 0ec9dd
  box->bitmap_top = top;
Packit 0ec9dd
Packit 0ec9dd
  box->bitmap.pixel_mode = ft_pixel_mode_grays;
Packit 0ec9dd
Packit 0ec9dd
  box->bitmap.width = width;
Packit 0ec9dd
  box->bitmap.rows = height;
Packit 0ec9dd
  box->bitmap.pitch = width;
Packit 0ec9dd
Packit 0ec9dd
  box->bitmap.buffer = g_malloc0_n (box->bitmap.rows, box->bitmap.pitch);
Packit 0ec9dd
Packit 0ec9dd
  if (G_UNLIKELY (!box->bitmap.buffer)) {
Packit 0ec9dd
    g_slice_free (PangoFT2RenderedGlyph, box);
Packit 0ec9dd
    return NULL;
Packit 0ec9dd
  }
Packit 0ec9dd
Packit 0ec9dd
  /* draw the box */
Packit 0ec9dd
  for (j = 0; j < line_width; j++)
Packit 0ec9dd
    {
Packit 0ec9dd
      offset1 = box->bitmap.pitch * (MIN (1 + j, height - 1));
Packit 0ec9dd
      offset2 = box->bitmap.pitch * (MAX (box->bitmap.rows - 2 - j, 0));
Packit 0ec9dd
      for (i = 1;
Packit 0ec9dd
	   i < (int) box->bitmap.width - 1;
Packit 0ec9dd
	   i++)
Packit 0ec9dd
	{
Packit 0ec9dd
	  box->bitmap.buffer[offset1 + i] = 0xff;
Packit 0ec9dd
	  box->bitmap.buffer[offset2 + i] = 0xff;
Packit 0ec9dd
	}
Packit 0ec9dd
    }
Packit 0ec9dd
  for (j = 0; j < line_width; j++)
Packit 0ec9dd
    {
Packit 0ec9dd
      offset1 = MIN (1 + j, width - 1);
Packit 0ec9dd
      offset2 = MAX ((int) box->bitmap.width - 2 - j, 0);
Packit 0ec9dd
      for (i = box->bitmap.pitch;
Packit 0ec9dd
	   i < (int) (box->bitmap.rows - 1) * box->bitmap.pitch;
Packit 0ec9dd
	   i += box->bitmap.pitch)
Packit 0ec9dd
	{
Packit 0ec9dd
	  box->bitmap.buffer[offset1 + i] = 0xff;
Packit 0ec9dd
	  box->bitmap.buffer[offset2 + i] = 0xff;
Packit 0ec9dd
	}
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  if (invalid)
Packit 0ec9dd
    {
Packit 0ec9dd
      /* XXX This may scrabble memory.  Didn't check close enough */
Packit 0ec9dd
      int inc = PANGO_SCALE * MAX (width - line_width, 0) / (height + 1);
Packit 0ec9dd
      offset1 = PANGO_SCALE;
Packit 0ec9dd
      offset2 = PANGO_SCALE * MAX (width - line_width - 1, 0) ;
Packit 0ec9dd
      for (i = box->bitmap.pitch;
Packit 0ec9dd
	   i < (int) (box->bitmap.rows - 1) * box->bitmap.pitch;
Packit 0ec9dd
	   i += box->bitmap.pitch)
Packit 0ec9dd
        {
Packit 0ec9dd
	  for (j = 0; j < line_width; j++)
Packit 0ec9dd
	    {
Packit 0ec9dd
	      box->bitmap.buffer[PANGO_PIXELS (offset1) + i + j] = 0xff;
Packit 0ec9dd
	      box->bitmap.buffer[PANGO_PIXELS (offset2) + i + j] = 0xff;
Packit 0ec9dd
	    }
Packit 0ec9dd
	  offset1 += inc;
Packit 0ec9dd
	  offset2 -= inc;
Packit 0ec9dd
	}
Packit 0ec9dd
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  return box;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static PangoFT2RenderedGlyph *
Packit 0ec9dd
pango_ft2_font_render_glyph (PangoFont *font,
Packit 0ec9dd
			     PangoGlyph glyph_index)
Packit 0ec9dd
{
Packit 0ec9dd
  FT_Face face;
Packit 0ec9dd
  gboolean invalid_input;
Packit 0ec9dd
Packit 0ec9dd
  invalid_input = glyph_index == PANGO_GLYPH_INVALID_INPUT || (glyph_index & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0x10FFFF;
Packit 0ec9dd
Packit 0ec9dd
  if (glyph_index & PANGO_GLYPH_UNKNOWN_FLAG)
Packit 0ec9dd
    {
Packit 0ec9dd
      PangoFT2RenderedGlyph *box;
Packit 0ec9dd
      PangoFontMetrics *metrics;
Packit 0ec9dd
Packit 0ec9dd
      if (!font)
Packit 0ec9dd
	goto generic_box;
Packit 0ec9dd
Packit 0ec9dd
      metrics = pango_font_get_metrics (font, NULL);
Packit 0ec9dd
      if (!metrics)
Packit 0ec9dd
	goto generic_box;
Packit 0ec9dd
Packit 0ec9dd
      box = pango_ft2_font_render_box_glyph (PANGO_PIXELS (metrics->approximate_char_width),
Packit 0ec9dd
					     PANGO_PIXELS (metrics->ascent + metrics->descent),
Packit 0ec9dd
					     PANGO_PIXELS (metrics->ascent),
Packit 0ec9dd
					     invalid_input);
Packit 0ec9dd
      pango_font_metrics_unref (metrics);
Packit 0ec9dd
Packit 0ec9dd
      return box;
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  face = pango_ft2_font_get_face (font);
Packit 0ec9dd
Packit 0ec9dd
  if (face)
Packit 0ec9dd
    {
Packit 0ec9dd
      PangoFT2RenderedGlyph *rendered;
Packit 0ec9dd
      PangoFT2Font *ft2font = (PangoFT2Font *) font;
Packit 0ec9dd
Packit 0ec9dd
      rendered = g_slice_new (PangoFT2RenderedGlyph);
Packit 0ec9dd
Packit 0ec9dd
      /* Draw glyph */
Packit 0ec9dd
      FT_Load_Glyph (face, glyph_index, ft2font->load_flags);
Packit 0ec9dd
      FT_Render_Glyph (face->glyph,
Packit 0ec9dd
		       (ft2font->load_flags & FT_LOAD_TARGET_MONO ?
Packit 0ec9dd
			ft_render_mode_mono : ft_render_mode_normal));
Packit 0ec9dd
Packit 0ec9dd
      rendered->bitmap = face->glyph->bitmap;
Packit 0ec9dd
      rendered->bitmap.buffer = g_memdup (face->glyph->bitmap.buffer,
Packit 0ec9dd
					  face->glyph->bitmap.rows * face->glyph->bitmap.pitch);
Packit 0ec9dd
      rendered->bitmap_left = face->glyph->bitmap_left;
Packit 0ec9dd
      rendered->bitmap_top = face->glyph->bitmap_top;
Packit 0ec9dd
Packit 0ec9dd
      if (G_UNLIKELY (!rendered->bitmap.buffer)) {
Packit 0ec9dd
        g_slice_free (PangoFT2RenderedGlyph, rendered);
Packit 0ec9dd
	return NULL;
Packit 0ec9dd
      }
Packit 0ec9dd
Packit 0ec9dd
      return rendered;
Packit 0ec9dd
    }
Packit 0ec9dd
  else
Packit 0ec9dd
    {
Packit 0ec9dd
generic_box:
Packit 0ec9dd
      return  pango_ft2_font_render_box_glyph (PANGO_UNKNOWN_GLYPH_WIDTH,
Packit 0ec9dd
					       PANGO_UNKNOWN_GLYPH_HEIGHT,
Packit 0ec9dd
					       PANGO_UNKNOWN_GLYPH_HEIGHT,
Packit 0ec9dd
					       invalid_input);
Packit 0ec9dd
    }
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
pango_ft2_renderer_draw_glyph (PangoRenderer *renderer,
Packit 0ec9dd
			       PangoFont     *font,
Packit 0ec9dd
			       PangoGlyph     glyph,
Packit 0ec9dd
			       double         x,
Packit 0ec9dd
			       double         y)
Packit 0ec9dd
{
Packit 0ec9dd
  FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap;
Packit 0ec9dd
  PangoFT2RenderedGlyph *rendered_glyph;
Packit 0ec9dd
  gboolean add_glyph_to_cache;
Packit 0ec9dd
  guchar *src, *dest;
Packit 0ec9dd
Packit 0ec9dd
  int x_start, x_limit;
Packit 0ec9dd
  int y_start, y_limit;
Packit 0ec9dd
  int ixoff = floor (x + 0.5);
Packit 0ec9dd
  int iyoff = floor (y + 0.5);
Packit 0ec9dd
  int ix, iy;
Packit 0ec9dd
Packit 0ec9dd
  if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
Packit 0ec9dd
    {
Packit 0ec9dd
      /* Since we don't draw hexbox for FT2 renderer,
Packit 0ec9dd
       * unifiy the rendered bitmap in the cache by converting
Packit 0ec9dd
       * all missing glyphs to either INVALID_INPUT or UNKNOWN_FLAG.
Packit 0ec9dd
       */
Packit 0ec9dd
Packit 0ec9dd
      gunichar wc = glyph & (~PANGO_GLYPH_UNKNOWN_FLAG);
Packit 0ec9dd
Packit 0ec9dd
      if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || wc > 0x10FFFF))
Packit 0ec9dd
	glyph = PANGO_GLYPH_INVALID_INPUT;
Packit 0ec9dd
      else
Packit 0ec9dd
	glyph = PANGO_GLYPH_UNKNOWN_FLAG;
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  rendered_glyph = _pango_ft2_font_get_cache_glyph_data (font, glyph);
Packit 0ec9dd
  add_glyph_to_cache = FALSE;
Packit 0ec9dd
  if (rendered_glyph == NULL)
Packit 0ec9dd
    {
Packit 0ec9dd
      rendered_glyph = pango_ft2_font_render_glyph (font, glyph);
Packit 0ec9dd
      if (rendered_glyph == NULL)
Packit 0ec9dd
        return;
Packit 0ec9dd
      add_glyph_to_cache = TRUE;
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  x_start = MAX (0, - (ixoff + rendered_glyph->bitmap_left));
Packit 0ec9dd
  x_limit = MIN ((int) rendered_glyph->bitmap.width,
Packit 0ec9dd
		 (int) (bitmap->width - (ixoff + rendered_glyph->bitmap_left)));
Packit 0ec9dd
Packit 0ec9dd
  y_start = MAX (0,  - (iyoff - rendered_glyph->bitmap_top));
Packit 0ec9dd
  y_limit = MIN ((int) rendered_glyph->bitmap.rows,
Packit 0ec9dd
		 (int) (bitmap->rows - (iyoff - rendered_glyph->bitmap_top)));
Packit 0ec9dd
Packit 0ec9dd
  src = rendered_glyph->bitmap.buffer +
Packit 0ec9dd
    y_start * rendered_glyph->bitmap.pitch;
Packit 0ec9dd
Packit 0ec9dd
  dest = bitmap->buffer +
Packit 0ec9dd
    (y_start + iyoff - rendered_glyph->bitmap_top) * bitmap->pitch +
Packit 0ec9dd
    x_start + ixoff + rendered_glyph->bitmap_left;
Packit 0ec9dd
Packit 0ec9dd
  switch (rendered_glyph->bitmap.pixel_mode)
Packit 0ec9dd
    {
Packit 0ec9dd
    case ft_pixel_mode_grays:
Packit 0ec9dd
      src += x_start;
Packit 0ec9dd
      for (iy = y_start; iy < y_limit; iy++)
Packit 0ec9dd
	{
Packit 0ec9dd
	  guchar *s = src;
Packit 0ec9dd
	  guchar *d = dest;
Packit 0ec9dd
Packit 0ec9dd
	  for (ix = x_start; ix < x_limit; ix++)
Packit 0ec9dd
	    {
Packit 0ec9dd
	      switch (*s)
Packit 0ec9dd
		{
Packit 0ec9dd
		case 0:
Packit 0ec9dd
		  break;
Packit 0ec9dd
		case 0xff:
Packit 0ec9dd
		  *d = 0xff;
Packit 0ec9dd
		default:
Packit 0ec9dd
		  *d = MIN ((gushort) *d + (gushort) *s, 0xff);
Packit 0ec9dd
		  break;
Packit 0ec9dd
		}
Packit 0ec9dd
Packit 0ec9dd
	      s++;
Packit 0ec9dd
	      d++;
Packit 0ec9dd
	    }
Packit 0ec9dd
Packit 0ec9dd
	  dest += bitmap->pitch;
Packit 0ec9dd
	  src  += rendered_glyph->bitmap.pitch;
Packit 0ec9dd
	}
Packit 0ec9dd
      break;
Packit 0ec9dd
Packit 0ec9dd
    case ft_pixel_mode_mono:
Packit 0ec9dd
      src += x_start / 8;
Packit 0ec9dd
      for (iy = y_start; iy < y_limit; iy++)
Packit 0ec9dd
	{
Packit 0ec9dd
	  guchar *s = src;
Packit 0ec9dd
	  guchar *d = dest;
Packit 0ec9dd
Packit 0ec9dd
	  for (ix = x_start; ix < x_limit; ix++)
Packit 0ec9dd
	    {
Packit 0ec9dd
	      if ((*s) & (1 << (7 - (ix % 8))))
Packit 0ec9dd
		*d |= 0xff;
Packit 0ec9dd
Packit 0ec9dd
	      if ((ix % 8) == 7)
Packit 0ec9dd
		s++;
Packit 0ec9dd
	      d++;
Packit 0ec9dd
	    }
Packit 0ec9dd
Packit 0ec9dd
	  dest += bitmap->pitch;
Packit 0ec9dd
	  src  += rendered_glyph->bitmap.pitch;
Packit 0ec9dd
	}
Packit 0ec9dd
      break;
Packit 0ec9dd
Packit 0ec9dd
    default:
Packit 0ec9dd
      g_warning ("pango_ft2_render: "
Packit 0ec9dd
		 "Unrecognized glyph bitmap pixel mode %d\n",
Packit 0ec9dd
		 rendered_glyph->bitmap.pixel_mode);
Packit 0ec9dd
      break;
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  if (add_glyph_to_cache)
Packit 0ec9dd
    {
Packit 0ec9dd
      _pango_ft2_font_set_glyph_cache_destroy (font,
Packit 0ec9dd
					       (GDestroyNotify) pango_ft2_free_rendered_glyph);
Packit 0ec9dd
      _pango_ft2_font_set_cache_glyph_data (font,
Packit 0ec9dd
					    glyph, rendered_glyph);
Packit 0ec9dd
    }
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
typedef struct {
Packit 0ec9dd
  double y;
Packit 0ec9dd
  double x1;
Packit 0ec9dd
  double x2;
Packit 0ec9dd
} Position;
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
draw_simple_trap (PangoRenderer *renderer,
Packit 0ec9dd
		  Position      *t,
Packit 0ec9dd
		  Position      *b)
Packit 0ec9dd
{
Packit 0ec9dd
  FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap;
Packit 0ec9dd
  int iy = floor (t->y);
Packit 0ec9dd
  int x1, x2, x;
Packit 0ec9dd
  double dy = b->y - t->y;
Packit 0ec9dd
  guchar *dest;
Packit 0ec9dd
Packit 0ec9dd
  if (iy < 0 || iy >= (int) bitmap->rows)
Packit 0ec9dd
    return;
Packit 0ec9dd
  dest = bitmap->buffer + iy * bitmap->pitch;
Packit 0ec9dd
Packit 0ec9dd
  if (t->x1 < b->x1)
Packit 0ec9dd
    x1 = floor (t->x1);
Packit 0ec9dd
  else
Packit 0ec9dd
    x1 = floor (b->x1);
Packit 0ec9dd
Packit 0ec9dd
  if (t->x2 > b->x2)
Packit 0ec9dd
    x2 = ceil (t->x2);
Packit 0ec9dd
  else
Packit 0ec9dd
    x2 = ceil (b->x2);
Packit 0ec9dd
Packit 0ec9dd
  x1 = CLAMP (x1, 0, (int) bitmap->width);
Packit 0ec9dd
  x2 = CLAMP (x2, 0, (int) bitmap->width);
Packit 0ec9dd
Packit 0ec9dd
  for (x = x1; x < x2; x++)
Packit 0ec9dd
    {
Packit 0ec9dd
      double top_left = MAX (t->x1, x);
Packit 0ec9dd
      double top_right = MIN (t->x2, x + 1);
Packit 0ec9dd
      double bottom_left = MAX (b->x1, x);
Packit 0ec9dd
      double bottom_right = MIN (b->x2, x + 1);
Packit 0ec9dd
      double c = 0.5 * dy * ((top_right - top_left) + (bottom_right - bottom_left));
Packit 0ec9dd
Packit 0ec9dd
      /* When converting to [0,255], we round up. This is intended
Packit 0ec9dd
       * to prevent the problem of pixels that get divided into
Packit 0ec9dd
       * multiple slices not being fully black.
Packit 0ec9dd
       */
Packit 0ec9dd
      int ic = c * 256;
Packit 0ec9dd
Packit 0ec9dd
      dest[x] = MIN (dest[x] + ic, 255);
Packit 0ec9dd
    }
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
interpolate_position (Position *result,
Packit 0ec9dd
		      Position *top,
Packit 0ec9dd
		      Position *bottom,
Packit 0ec9dd
		      double    val,
Packit 0ec9dd
		      double    val1,
Packit 0ec9dd
		      double    val2)
Packit 0ec9dd
{
Packit 0ec9dd
  result->y  = (top->y *  (val2 - val) + bottom->y *  (val - val1)) / (val2 - val1);
Packit 0ec9dd
  result->x1 = (top->x1 * (val2 - val) + bottom->x1 * (val - val1)) / (val2 - val1);
Packit 0ec9dd
  result->x2 = (top->x2 * (val2 - val) + bottom->x2 * (val - val1)) / (val2 - val1);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
/* This draws a trapezoid with the parallel sides aligned with
Packit 0ec9dd
 * the X axis. We do this by subdividing the trapezoid vertically
Packit 0ec9dd
 * into thin slices (themselves trapezoids) where two edge sides are each
Packit 0ec9dd
 * contained within a single pixel and then rasterizing each
Packit 0ec9dd
 * slice. There are frequently multiple slices within a single
Packit 0ec9dd
 * line so we have to accumulate to get the final result.
Packit 0ec9dd
 */
Packit 0ec9dd
static void
Packit 0ec9dd
pango_ft2_renderer_draw_trapezoid (PangoRenderer   *renderer,
Packit 0ec9dd
				   PangoRenderPart  part G_GNUC_UNUSED,
Packit 0ec9dd
				   double           y1,
Packit 0ec9dd
				   double           x11,
Packit 0ec9dd
				   double           x21,
Packit 0ec9dd
				   double           y2,
Packit 0ec9dd
				   double           x12,
Packit 0ec9dd
				   double           x22)
Packit 0ec9dd
{
Packit 0ec9dd
  Position pos;
Packit 0ec9dd
  Position t;
Packit 0ec9dd
  Position b;
Packit 0ec9dd
  gboolean done = FALSE;
Packit 0ec9dd
Packit 0ec9dd
  if (y1 == y2)
Packit 0ec9dd
    return;
Packit 0ec9dd
Packit 0ec9dd
  pos.y = t.y = y1;
Packit 0ec9dd
  pos.x1 = t.x1 = x11;
Packit 0ec9dd
  pos.x2 = t.x2 = x21;
Packit 0ec9dd
  b.y = y2;
Packit 0ec9dd
  b.x1 = x12;
Packit 0ec9dd
  b.x2 = x22;
Packit 0ec9dd
Packit 0ec9dd
  while (!done)
Packit 0ec9dd
    {
Packit 0ec9dd
      Position pos_next;
Packit 0ec9dd
      double y_next, x1_next, x2_next;
Packit 0ec9dd
      double ix1, ix2;
Packit 0ec9dd
Packit 0ec9dd
      /* The algorithm here is written to emphasize simplicity and
Packit 0ec9dd
       * numerical stability as opposed to speed.
Packit 0ec9dd
       *
Packit 0ec9dd
       * While the end result is slicing up the polygon vertically,
Packit 0ec9dd
       * conceptually we aren't walking in the X direction, rather we
Packit 0ec9dd
       * are walking along the edges. When we compute crossing of
Packit 0ec9dd
       * horizontal pixel boundaries, we use the X coordinate as the
Packit 0ec9dd
       * interpolating variable, when we compute crossing for vertical
Packit 0ec9dd
       * pixel boundaries, we use the Y coordinate.
Packit 0ec9dd
       *
Packit 0ec9dd
       * This allows us to handle almost exactly horizontal edges without
Packit 0ec9dd
       * running into difficulties. (Almost exactly horizontal edges
Packit 0ec9dd
       * come up frequently due to inexactness in computing, say,
Packit 0ec9dd
       * a 90 degree rotation transformation)
Packit 0ec9dd
       */
Packit 0ec9dd
Packit 0ec9dd
      pos_next = b;
Packit 0ec9dd
      done = TRUE;
Packit 0ec9dd
Packit 0ec9dd
      /* Check for crossing vertical pixel boundaries */
Packit 0ec9dd
      y_next = floor (pos.y) + 1;
Packit 0ec9dd
      if (y_next < pos_next.y)
Packit 0ec9dd
	{
Packit 0ec9dd
	  interpolate_position (&pos_next, &t, &b,
Packit 0ec9dd
				y_next, t.y, b.y);
Packit 0ec9dd
	  pos_next.y = y_next;
Packit 0ec9dd
	  done = FALSE;
Packit 0ec9dd
	}
Packit 0ec9dd
Packit 0ec9dd
      /* Check left side for crossing horizontal pixel boundaries */
Packit 0ec9dd
      ix1 = floor (pos.x1);
Packit 0ec9dd
Packit 0ec9dd
      if (b.x1 < t.x1)
Packit 0ec9dd
	{
Packit 0ec9dd
	  if (ix1 == pos.x1)
Packit 0ec9dd
	    x1_next = ix1 - 1;
Packit 0ec9dd
	  else
Packit 0ec9dd
	    x1_next = ix1;
Packit 0ec9dd
Packit 0ec9dd
	  if (x1_next > pos_next.x1)
Packit 0ec9dd
	    {
Packit 0ec9dd
	      interpolate_position (&pos_next, &t, &b,
Packit 0ec9dd
				    x1_next, t.x1, b.x1);
Packit 0ec9dd
	      pos_next.x1 = x1_next;
Packit 0ec9dd
	      done = FALSE;
Packit 0ec9dd
	    }
Packit 0ec9dd
	}
Packit 0ec9dd
      else if (b.x1 > t.x1)
Packit 0ec9dd
	{
Packit 0ec9dd
	  x1_next = ix1 + 1;
Packit 0ec9dd
Packit 0ec9dd
	  if (x1_next < pos_next.x1)
Packit 0ec9dd
	    {
Packit 0ec9dd
	      interpolate_position (&pos_next, &t, &b,
Packit 0ec9dd
				    x1_next, t.x1, b.x1);
Packit 0ec9dd
	      pos_next.x1 = x1_next;
Packit 0ec9dd
	      done = FALSE;
Packit 0ec9dd
	    }
Packit 0ec9dd
	}
Packit 0ec9dd
Packit 0ec9dd
      /* Check right side for crossing horizontal pixel boundaries */
Packit 0ec9dd
      ix2 = floor (pos.x2);
Packit 0ec9dd
Packit 0ec9dd
      if (b.x2 < t.x2)
Packit 0ec9dd
	{
Packit 0ec9dd
	  if (ix2 == pos.x2)
Packit 0ec9dd
	    x2_next = ix2 - 1;
Packit 0ec9dd
	  else
Packit 0ec9dd
	    x2_next = ix2;
Packit 0ec9dd
Packit 0ec9dd
	  if (x2_next > pos_next.x2)
Packit 0ec9dd
	    {
Packit 0ec9dd
	      interpolate_position (&pos_next, &t, &b,
Packit 0ec9dd
				    x2_next, t.x2, b.x2);
Packit 0ec9dd
	      pos_next.x2 = x2_next;
Packit 0ec9dd
	      done = FALSE;
Packit 0ec9dd
	    }
Packit 0ec9dd
	}
Packit 0ec9dd
      else if (x22 > x21)
Packit 0ec9dd
	{
Packit 0ec9dd
	  x2_next = ix2 + 1;
Packit 0ec9dd
Packit 0ec9dd
	  if (x2_next < pos_next.x2)
Packit 0ec9dd
	    {
Packit 0ec9dd
	      interpolate_position (&pos_next, &t, &b,
Packit 0ec9dd
				    x2_next, t.x2, b.x2);
Packit 0ec9dd
	      pos_next.x2 = x2_next;
Packit 0ec9dd
	      done = FALSE;
Packit 0ec9dd
	    }
Packit 0ec9dd
	}
Packit 0ec9dd
Packit 0ec9dd
      draw_simple_trap (renderer, &pos, &pos_next);
Packit 0ec9dd
      pos = pos_next;
Packit 0ec9dd
    }
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
/**
Packit 0ec9dd
 * pango_ft2_render_layout_subpixel:
Packit 0ec9dd
 * @bitmap:    a <type>FT_Bitmap</type> to render the layout onto
Packit 0ec9dd
 * @layout:    a #PangoLayout
Packit 0ec9dd
 * @x:         the X position of the left of the layout (in Pango units)
Packit 0ec9dd
 * @y:         the Y position of the top of the layout (in Pango units)
Packit 0ec9dd
 *
Packit 0ec9dd
 * Render a #PangoLayout onto a FreeType2 bitmap, with he
Packit 0ec9dd
 * location specified in fixed-point Pango units rather than
Packit 0ec9dd
 * pixels. (Using this will avoid extra inaccuracies from
Packit 0ec9dd
 * rounding to integer pixels multiple times, even if the
Packit 0ec9dd
 * final glyph positions are integers.)
Packit 0ec9dd
 *
Packit 0ec9dd
 * Since: 1.6
Packit 0ec9dd
 */
Packit 0ec9dd
void
Packit 0ec9dd
pango_ft2_render_layout_subpixel (FT_Bitmap   *bitmap,
Packit 0ec9dd
				  PangoLayout *layout,
Packit 0ec9dd
				  int          x,
Packit 0ec9dd
				  int          y)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoContext *context;
Packit 0ec9dd
  PangoFontMap *fontmap;
Packit 0ec9dd
  PangoRenderer *renderer;
Packit 0ec9dd
Packit 0ec9dd
  g_return_if_fail (bitmap != NULL);
Packit 0ec9dd
  g_return_if_fail (PANGO_IS_LAYOUT (layout));
Packit 0ec9dd
Packit 0ec9dd
  context = pango_layout_get_context (layout);
Packit 0ec9dd
  fontmap = pango_context_get_font_map (context);
Packit 0ec9dd
  renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap));
Packit 0ec9dd
Packit 0ec9dd
  pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
Packit 0ec9dd
Packit 0ec9dd
  pango_renderer_draw_layout (renderer, layout, x, y);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
/**
Packit 0ec9dd
 * pango_ft2_render_layout:
Packit 0ec9dd
 * @bitmap:    a <type>FT_Bitmap</type> to render the layout onto
Packit 0ec9dd
 * @layout:    a #PangoLayout
Packit 0ec9dd
 * @x:         the X position of the left of the layout (in pixels)
Packit 0ec9dd
 * @y:         the Y position of the top of the layout (in pixels)
Packit 0ec9dd
 *
Packit 0ec9dd
 * Render a #PangoLayout onto a FreeType2 bitmap
Packit 0ec9dd
 */
Packit 0ec9dd
void
Packit 0ec9dd
pango_ft2_render_layout (FT_Bitmap   *bitmap,
Packit 0ec9dd
			 PangoLayout *layout,
Packit 0ec9dd
			 int          x,
Packit 0ec9dd
			 int          y)
Packit 0ec9dd
{
Packit 0ec9dd
  pango_ft2_render_layout_subpixel (bitmap, layout, x * PANGO_SCALE, y * PANGO_SCALE);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
/**
Packit 0ec9dd
 * pango_ft2_render_layout_line_subpixel:
Packit 0ec9dd
 * @bitmap:    a <type>FT_Bitmap</type> to render the line onto
Packit 0ec9dd
 * @line:      a #PangoLayoutLine
Packit 0ec9dd
 * @x:         the x position of start of string (in Pango units)
Packit 0ec9dd
 * @y:         the y position of baseline (in Pango units)
Packit 0ec9dd
 *
Packit 0ec9dd
 * Render a #PangoLayoutLine onto a FreeType2 bitmap, with he
Packit 0ec9dd
 * location specified in fixed-point Pango units rather than
Packit 0ec9dd
 * pixels. (Using this will avoid extra inaccuracies from
Packit 0ec9dd
 * rounding to integer pixels multiple times, even if the
Packit 0ec9dd
 * final glyph positions are integers.)
Packit 0ec9dd
 *
Packit 0ec9dd
 * Since: 1.6
Packit 0ec9dd
 */
Packit 0ec9dd
void
Packit 0ec9dd
pango_ft2_render_layout_line_subpixel (FT_Bitmap       *bitmap,
Packit 0ec9dd
				       PangoLayoutLine *line,
Packit 0ec9dd
				       int              x,
Packit 0ec9dd
				       int              y)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoContext *context;
Packit 0ec9dd
  PangoFontMap *fontmap;
Packit 0ec9dd
  PangoRenderer *renderer;
Packit 0ec9dd
Packit 0ec9dd
  g_return_if_fail (bitmap != NULL);
Packit 0ec9dd
  g_return_if_fail (line != NULL);
Packit 0ec9dd
Packit 0ec9dd
  context = pango_layout_get_context (line->layout);
Packit 0ec9dd
  fontmap = pango_context_get_font_map (context);
Packit 0ec9dd
  renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap));
Packit 0ec9dd
Packit 0ec9dd
  pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
Packit 0ec9dd
Packit 0ec9dd
  pango_renderer_draw_layout_line (renderer, line, x, y);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
/**
Packit 0ec9dd
 * pango_ft2_render_layout_line:
Packit 0ec9dd
 * @bitmap:    a <type>FT_Bitmap</type> to render the line onto
Packit 0ec9dd
 * @line:      a #PangoLayoutLine
Packit 0ec9dd
 * @x:         the x position of start of string (in pixels)
Packit 0ec9dd
 * @y:         the y position of baseline (in pixels)
Packit 0ec9dd
 *
Packit 0ec9dd
 * Render a #PangoLayoutLine onto a FreeType2 bitmap
Packit 0ec9dd
 */
Packit 0ec9dd
void
Packit 0ec9dd
pango_ft2_render_layout_line (FT_Bitmap       *bitmap,
Packit 0ec9dd
			      PangoLayoutLine *line,
Packit 0ec9dd
			      int              x,
Packit 0ec9dd
			      int              y)
Packit 0ec9dd
{
Packit 0ec9dd
  pango_ft2_render_layout_line_subpixel (bitmap, line, x * PANGO_SCALE, y * PANGO_SCALE);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
/**
Packit 0ec9dd
 * pango_ft2_render_transformed:
Packit 0ec9dd
 * @bitmap:  the FreeType2 bitmap onto which to draw the string
Packit 0ec9dd
 * @font:    the font in which to draw the string
Packit 0ec9dd
 * @matrix:  (nullable): a #PangoMatrix, or %NULL to use an identity
Packit 0ec9dd
 *           transformation
Packit 0ec9dd
 * @glyphs:  the glyph string to draw
Packit 0ec9dd
 * @x:       the x position of the start of the string (in Pango
Packit 0ec9dd
 *           units in user space coordinates)
Packit 0ec9dd
 * @y:       the y position of the baseline (in Pango units
Packit 0ec9dd
 *           in user space coordinates)
Packit 0ec9dd
 *
Packit 0ec9dd
 * Renders a #PangoGlyphString onto a FreeType2 bitmap, possibly
Packit 0ec9dd
 * transforming the layed-out coordinates through a transformation
Packit 0ec9dd
 * matrix. Note that the transformation matrix for @font is not
Packit 0ec9dd
 * changed, so to produce correct rendering results, the @font
Packit 0ec9dd
 * must have been loaded using a #PangoContext with an identical
Packit 0ec9dd
 * transformation matrix to that passed in to this function.
Packit 0ec9dd
 *
Packit 0ec9dd
 * Since: 1.6
Packit 0ec9dd
 **/
Packit 0ec9dd
void
Packit 0ec9dd
pango_ft2_render_transformed (FT_Bitmap         *bitmap,
Packit 0ec9dd
			      const PangoMatrix *matrix,
Packit 0ec9dd
			      PangoFont         *font,
Packit 0ec9dd
			      PangoGlyphString  *glyphs,
Packit 0ec9dd
			      int                x,
Packit 0ec9dd
			      int                y)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFontMap *fontmap;
Packit 0ec9dd
  PangoRenderer *renderer;
Packit 0ec9dd
Packit 0ec9dd
  g_return_if_fail (bitmap != NULL);
Packit 0ec9dd
  g_return_if_fail (glyphs != NULL);
Packit 0ec9dd
  g_return_if_fail (PANGO_FT2_IS_FONT (font));
Packit 0ec9dd
Packit 0ec9dd
  fontmap = PANGO_FC_FONT (font)->fontmap;
Packit 0ec9dd
  renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap));
Packit 0ec9dd
Packit 0ec9dd
  pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
Packit 0ec9dd
  pango_renderer_set_matrix (renderer, matrix);
Packit 0ec9dd
Packit 0ec9dd
  pango_renderer_draw_glyphs (renderer, font, glyphs, x, y);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
/**
Packit 0ec9dd
 * pango_ft2_render:
Packit 0ec9dd
 * @bitmap:  the FreeType2 bitmap onto which to draw the string
Packit 0ec9dd
 * @font:    the font in which to draw the string
Packit 0ec9dd
 * @glyphs:  the glyph string to draw
Packit 0ec9dd
 * @x:       the x position of the start of the string (in pixels)
Packit 0ec9dd
 * @y:       the y position of the baseline (in pixels)
Packit 0ec9dd
 *
Packit 0ec9dd
 * Renders a #PangoGlyphString onto a FreeType2 bitmap.
Packit 0ec9dd
 **/
Packit 0ec9dd
void
Packit 0ec9dd
pango_ft2_render (FT_Bitmap        *bitmap,
Packit 0ec9dd
		  PangoFont        *font,
Packit 0ec9dd
		  PangoGlyphString *glyphs,
Packit 0ec9dd
		  int               x,
Packit 0ec9dd
		  int               y)
Packit 0ec9dd
{
Packit 0ec9dd
  pango_ft2_render_transformed (bitmap, NULL, font, glyphs, x * PANGO_SCALE, y * PANGO_SCALE);
Packit 0ec9dd
}
Packit 0ec9dd