Blame tests/testiter.c

Packit 0ec9dd
/* Pango
Packit 0ec9dd
 * testiter.c: Test pangolayoutiter.c
Packit 0ec9dd
 *
Packit 0ec9dd
 * Copyright (C) 2005 Amit Aronovitch
Packit 0ec9dd
 * Copyright (C) 2005 Red Hat, Inc
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
#undef G_DISABLE_ASSERT
Packit 0ec9dd
#undef G_LOG_DOMAIN
Packit 0ec9dd
Packit 0ec9dd
#include <stdarg.h>
Packit 0ec9dd
#include <stdio.h>
Packit 0ec9dd
#include <stdlib.h>
Packit 0ec9dd
#include <string.h>
Packit 0ec9dd
Packit 0ec9dd
#include <glib.h>
Packit 0ec9dd
Packit 0ec9dd
#include <pango/pangocairo.h>
Packit 0ec9dd
Packit 0ec9dd
static void verbose (const char *format, ...) G_GNUC_PRINTF (1, 2);
Packit 0ec9dd
static void
Packit 0ec9dd
verbose (const char *format, ...)
Packit 0ec9dd
{
Packit 0ec9dd
#ifdef VERBOSE
Packit 0ec9dd
  va_list vap;
Packit 0ec9dd
Packit 0ec9dd
  va_start (vap, format);
Packit 0ec9dd
  vfprintf (stderr, format, vap);
Packit 0ec9dd
  va_end (vap);
Packit 0ec9dd
#endif
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
#define LAYOUT_WIDTH (80 * PANGO_SCALE)
Packit 0ec9dd
Packit 0ec9dd
/* Note: The test expects that any newline sequence is of length 1
Packit 0ec9dd
 * use \n (not \r\n) in the test texts.
Packit 0ec9dd
 * I think the iterator itself should support \r\n without trouble,
Packit 0ec9dd
 * but there are comments in layout-iter.c suggesting otherwise.
Packit 0ec9dd
 */
Packit 0ec9dd
const char *test_texts[] =
Packit 0ec9dd
  {
Packit 0ec9dd
    /* English with embedded RTL runs (from ancient-hebrew.org) */
Packit 0ec9dd
    "The Hebrew word \xd7\x90\xd7\x93\xd7\x9d\xd7\x94 (adamah) is the feminine form of \xd7\x90\xd7\x93\xd7\x9d meaning \"ground\"\n",
Packit 0ec9dd
    /* Arabic, with vowel marks (from Sura Al Fatiha) */
Packit 0ec9dd
    "\xd8\xa8\xd9\x90\xd8\xb3\xd9\x92\xd9\x85\xd9\x90 \xd8\xa7\xd9\x84\xd9\x84\xd9\x91\xd9\x87\xd9\x90 \xd8\xa7\xd9\x84\xd8\xb1\xd9\x91\xd9\x8e\xd8\xad\xd9\x92\xd9\x85\xd9\x80\xd9\x8e\xd9\x86\xd9\x90 \xd8\xa7\xd9\x84\xd8\xb1\xd9\x91\xd9\x8e\xd8\xad\xd9\x90\xd9\x8a\xd9\x85\xd9\x90\n\xd8\xa7\xd9\x84\xd9\x92\xd8\xad\xd9\x8e\xd9\x85\xd9\x92\xd8\xaf\xd9\x8f \xd9\x84\xd9\x84\xd9\x91\xd9\x87\xd9\x90 \xd8\xb1\xd9\x8e\xd8\xa8\xd9\x91\xd9\x90 \xd8\xa7\xd9\x84\xd9\x92\xd8\xb9\xd9\x8e\xd8\xa7\xd9\x84\xd9\x8e\xd9\x85\xd9\x90\xd9\x8a\xd9\x86\xd9\x8e\n",
Packit 0ec9dd
    /* Arabic, with embedded LTR runs (from a Linux guide) */
Packit 0ec9dd
    "\xd8\xa7\xd9\x84\xd9\x85\xd8\xaa\xd8\xba\xd9\x8a\xd8\xb1 LC_ALL \xd9\x8a\xd8\xba\xd9\x8a\xd9\x8a\xd8\xb1 \xd9\x83\xd9\x84 \xd8\xa7\xd9\x84\xd9\x85\xd8\xaa\xd8\xba\xd9\x8a\xd8\xb1\xd8\xa7\xd8\xaa \xd8\xa7\xd9\x84\xd8\xaa\xd9\x8a \xd8\xaa\xd8\xa8\xd8\xaf\xd8\xa3 \xd8\xa8\xd8\xa7\xd9\x84\xd8\xb1\xd9\x85\xd8\xb2 LC.",
Packit 0ec9dd
    /* Hebrew, with vowel marks (from Genesis) */
Packit 0ec9dd
    "\xd7\x91\xd6\xbc\xd6\xb0\xd7\xa8\xd6\xb5\xd7\x90\xd7\xa9\xd7\x81\xd6\xb4\xd7\x99\xd7\xaa, \xd7\x91\xd6\xbc\xd6\xb8\xd7\xa8\xd6\xb8\xd7\x90 \xd7\x90\xd6\xb1\xd7\x9c\xd6\xb9\xd7\x94\xd6\xb4\xd7\x99\xd7\x9d, \xd7\x90\xd6\xb5\xd7\xaa \xd7\x94\xd6\xb7\xd7\xa9\xd6\xbc\xd7\x81\xd6\xb8\xd7\x9e\xd6\xb7\xd7\x99\xd6\xb4\xd7\x9d, \xd7\x95\xd6\xb0\xd7\x90\xd6\xb5\xd7\xaa \xd7\x94\xd6\xb8\xd7\x90\xd6\xb8\xd7\xa8\xd6\xb6\xd7\xa5",
Packit 0ec9dd
    /* Hebrew, with embedded LTR runs (from a Linux guide) */
Packit 0ec9dd
    "\xd7\x94\xd7\xa7\xd7\x9c\xd7\x93\xd7\x94 \xd7\xa2\xd7\x9c \xd7\xa9\xd7\xa0\xd7\x99 \xd7\x94 SHIFT\xd7\x99\xd7\x9d (\xd7\x99\xd7\x9e\xd7\x99\xd7\x9f \xd7\x95\xd7\xa9\xd7\x9e\xd7\x90\xd7\x9c \xd7\x91\xd7\x99\xd7\x97\xd7\x93) \xd7\x90\xd7\x9e\xd7\x95\xd7\xa8\xd7\x99\xd7\x9d \xd7\x9c\xd7\x94\xd7\x93\xd7\x9c\xd7\x99\xd7\xa7 \xd7\x90\xd7\xaa \xd7\xa0\xd7\x95\xd7\xa8\xd7\xaa \xd7\x94 Scroll Lock , \xd7\x95\xd7\x9c\xd7\x94\xd7\xa2\xd7\x91\xd7\x99\xd7\xa8 \xd7\x90\xd7\x95\xd7\xaa\xd7\xa0\xd7\x95 \xd7\x9c\xd7\x9e\xd7\xa6\xd7\x91 \xd7\x9b\xd7\xaa\xd7\x99\xd7\x91\xd7\x94 \xd7\x91\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa.",
Packit 0ec9dd
    /* Different line terminators */
Packit 0ec9dd
    "AAAA\nBBBB\nCCCC\n",
Packit 0ec9dd
    "DDDD\rEEEE\rFFFF\r",
Packit 0ec9dd
    "GGGG\r\nHHHH\r\nIIII\r\n",
Packit 0ec9dd
    "asdf",
Packit 0ec9dd
    NULL
Packit 0ec9dd
  };
Packit 0ec9dd
Packit 0ec9dd
/* char iteration test:
Packit 0ec9dd
 *  - Total num of iterations match number of chars
Packit 0ec9dd
 *  - GlyphString's index_to_x positions match those returned by the Iter
Packit 0ec9dd
 */
Packit 0ec9dd
static void
Packit 0ec9dd
iter_char_test (PangoLayout *layout)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoRectangle   extents, run_extents;
Packit 0ec9dd
  PangoLayoutIter *iter;
Packit 0ec9dd
  PangoLayoutRun  *run;
Packit 0ec9dd
  int              num_chars;
Packit 0ec9dd
  int              i, index, offset;
Packit 0ec9dd
  int              leading_x, trailing_x, x0, x1;
Packit 0ec9dd
  gboolean         iter_next_ok, rtl;
Packit 0ec9dd
  const char      *text, *ptr;
Packit 0ec9dd
Packit 0ec9dd
  text = pango_layout_get_text (layout);
Packit 0ec9dd
  num_chars = g_utf8_strlen (text, -1);
Packit 0ec9dd
Packit 0ec9dd
  iter = pango_layout_get_iter (layout);
Packit 0ec9dd
  iter_next_ok = TRUE;
Packit 0ec9dd
Packit 0ec9dd
  for (i = 0 ; i < num_chars; ++i)
Packit 0ec9dd
    {
Packit 0ec9dd
      gchar *char_str;
Packit 0ec9dd
      g_assert (iter_next_ok);
Packit 0ec9dd
Packit 0ec9dd
      index = pango_layout_iter_get_index (iter);
Packit 0ec9dd
      ptr = text + index;
Packit 0ec9dd
      char_str = g_strndup (ptr, g_utf8_next_char (ptr) - ptr);
Packit 0ec9dd
      verbose ("i=%d (visual), index = %d '%s':\n",
Packit 0ec9dd
	       i, index, char_str);
Packit 0ec9dd
      g_free (char_str);
Packit 0ec9dd
Packit 0ec9dd
      pango_layout_iter_get_char_extents (iter, &extents);
Packit 0ec9dd
      verbose ("  char extents: x=%d,y=%d w=%d,h=%d\n",
Packit 0ec9dd
	       extents.x, extents.y,
Packit 0ec9dd
	       extents.width, extents.height);
Packit 0ec9dd
Packit 0ec9dd
      run = pango_layout_iter_get_run (iter);
Packit 0ec9dd
Packit 0ec9dd
      if (run)
Packit 0ec9dd
	{
Packit 0ec9dd
	  /* Get needed data for the GlyphString */
Packit 0ec9dd
	  pango_layout_iter_get_run_extents(iter, NULL, &run_extents);
Packit 0ec9dd
	  offset = run->item->offset;
Packit 0ec9dd
	  rtl = run->item->analysis.level%2;
Packit 0ec9dd
	  verbose ("  (current run: offset=%d,x=%d,len=%d,rtl=%d)\n",
Packit 0ec9dd
		   offset, run_extents.x, run->item->length, rtl);
Packit 0ec9dd
Packit 0ec9dd
	  /* Calculate expected x result using index_to_x */
Packit 0ec9dd
	  pango_glyph_string_index_to_x (run->glyphs,
Packit 0ec9dd
					 (char *)(text + offset), run->item->length,
Packit 0ec9dd
					 &run->item->analysis,
Packit 0ec9dd
					 index - offset, FALSE, &leading_x);
Packit 0ec9dd
	  pango_glyph_string_index_to_x (run->glyphs,
Packit 0ec9dd
					 (char *)(text + offset), run->item->length,
Packit 0ec9dd
					 &run->item->analysis,
Packit 0ec9dd
					 index - offset, TRUE, &trailing_x);
Packit 0ec9dd
Packit 0ec9dd
	  x0 = run_extents.x + MIN (leading_x, trailing_x);
Packit 0ec9dd
	  x1 = run_extents.x + MAX (leading_x, trailing_x);
Packit 0ec9dd
Packit 0ec9dd
	  verbose ("  (index_to_x ind=%d: expected x=%d, width=%d)\n",
Packit 0ec9dd
		   index - offset, x0, x1 - x0);
Packit 0ec9dd
Packit 0ec9dd
	  g_assert (extents.x == x0);
Packit 0ec9dd
	  g_assert (extents.width == x1 - x0);
Packit 0ec9dd
	}
Packit 0ec9dd
      else
Packit 0ec9dd
	{
Packit 0ec9dd
	  /* We're on a line terminator */
Packit 0ec9dd
	}
Packit 0ec9dd
Packit 0ec9dd
      iter_next_ok = pango_layout_iter_next_char (iter);
Packit 0ec9dd
      verbose ("more to go? %d\n", iter_next_ok);
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  /* There should be one character position iterator for each character in the
Packit 0ec9dd
   * input string */
Packit 0ec9dd
  g_assert (!iter_next_ok);
Packit 0ec9dd
Packit 0ec9dd
  pango_layout_iter_free (iter);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
iter_cluster_test (PangoLayout *layout)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoRectangle   extents;
Packit 0ec9dd
  PangoLayoutIter *iter;
Packit 0ec9dd
  int              index;
Packit 0ec9dd
  gboolean         iter_next_ok;
Packit 0ec9dd
  PangoLayoutLine *last_line = NULL;
Packit 0ec9dd
  int              expected_next_x = 0;
Packit 0ec9dd
Packit 0ec9dd
  iter = pango_layout_get_iter (layout);
Packit 0ec9dd
  iter_next_ok = TRUE;
Packit 0ec9dd
Packit 0ec9dd
  while (iter_next_ok)
Packit 0ec9dd
    {
Packit 0ec9dd
      PangoLayoutLine *line = pango_layout_iter_get_line (iter);
Packit 0ec9dd
Packit 0ec9dd
      /* Every cluster is part of a run */
Packit 0ec9dd
      g_assert (pango_layout_iter_get_run (iter));
Packit 0ec9dd
Packit 0ec9dd
      index = pango_layout_iter_get_index (iter);
Packit 0ec9dd
Packit 0ec9dd
      pango_layout_iter_get_cluster_extents (iter, NULL, &extents);
Packit 0ec9dd
Packit 0ec9dd
      iter_next_ok = pango_layout_iter_next_cluster (iter);
Packit 0ec9dd
Packit 0ec9dd
      verbose ("index = %d:\n", index);
Packit 0ec9dd
      verbose ("  cluster extents: x=%d,y=%d w=%d,h=%d\n",
Packit 0ec9dd
	       extents.x, extents.y,
Packit 0ec9dd
	       extents.width, extents.height);
Packit 0ec9dd
      verbose ("more to go? %d\n", iter_next_ok);
Packit 0ec9dd
Packit 0ec9dd
      /* All the clusters on a line should be next to each other and occupy
Packit 0ec9dd
       * the entire line. They advance linearly from left to right */
Packit 0ec9dd
      g_assert (extents.width >= 0);
Packit 0ec9dd
Packit 0ec9dd
      if (last_line == line)
Packit 0ec9dd
	g_assert (extents.x == expected_next_x);
Packit 0ec9dd
Packit 0ec9dd
      expected_next_x = extents.x + extents.width;
Packit 0ec9dd
Packit 0ec9dd
      last_line = line;
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  g_assert (!iter_next_ok);
Packit 0ec9dd
Packit 0ec9dd
  pango_layout_iter_free (iter);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
test_layout_iter (void)
Packit 0ec9dd
{
Packit 0ec9dd
  const char  **ptext;
Packit 0ec9dd
  PangoFontMap *fontmap;
Packit 0ec9dd
  PangoContext *context;
Packit 0ec9dd
  PangoFontDescription *font_desc;
Packit 0ec9dd
  PangoLayout  *layout;
Packit 0ec9dd
Packit 0ec9dd
  fontmap = pango_cairo_font_map_get_default ();
Packit 0ec9dd
  context = pango_font_map_create_context (fontmap);
Packit 0ec9dd
  font_desc = pango_font_description_from_string ("cantarell 11");
Packit 0ec9dd
  pango_context_set_font_description (context, font_desc);
Packit 0ec9dd
Packit 0ec9dd
  layout = pango_layout_new (context);
Packit 0ec9dd
  pango_layout_set_width (layout, LAYOUT_WIDTH);
Packit 0ec9dd
Packit 0ec9dd
  for (ptext = test_texts; *ptext != NULL; ++ptext)
Packit 0ec9dd
    {
Packit 0ec9dd
      verbose ("--------- checking next text ----------\n");
Packit 0ec9dd
      verbose (" <%s>\n", *ptext);
Packit 0ec9dd
      verbose ( "len=%ld, bytes=%ld\n",
Packit 0ec9dd
		(long)g_utf8_strlen (*ptext, -1), (long)strlen (*ptext));
Packit 0ec9dd
Packit 0ec9dd
      pango_layout_set_text (layout, *ptext, -1);
Packit 0ec9dd
      iter_char_test (layout);
Packit 0ec9dd
      iter_cluster_test (layout);
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  g_object_unref (layout);
Packit 0ec9dd
  g_object_unref (context);
Packit 0ec9dd
  pango_font_description_free (font_desc);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
test_glyphitem_iter (void)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFontMap *fontmap;
Packit 0ec9dd
  PangoContext *context;
Packit 0ec9dd
  PangoFontDescription *font_desc;
Packit 0ec9dd
  PangoLayout  *layout;
Packit 0ec9dd
  PangoLayoutLine *line;
Packit 0ec9dd
  const char *text;
Packit 0ec9dd
  GSList *l;
Packit 0ec9dd
Packit 0ec9dd
  fontmap = pango_cairo_font_map_get_default ();
Packit 0ec9dd
  context = pango_font_map_create_context (fontmap);
Packit 0ec9dd
  font_desc = pango_font_description_from_string ("cantarell 11");
Packit 0ec9dd
  pango_context_set_font_description (context, font_desc);
Packit 0ec9dd
Packit 0ec9dd
  layout = pango_layout_new (context);
Packit 0ec9dd
  /* This shouldn't form any ligatures. */
Packit 0ec9dd
  pango_layout_set_text (layout, "test تست", -1);
Packit 0ec9dd
  text = pango_layout_get_text (layout);
Packit 0ec9dd
Packit 0ec9dd
  line = pango_layout_get_line (layout, 0);
Packit 0ec9dd
  for (l = line->runs; l; l = l->next)
Packit 0ec9dd
  {
Packit 0ec9dd
    PangoGlyphItem *run = l->data;
Packit 0ec9dd
    int direction;
Packit 0ec9dd
Packit 0ec9dd
    for (direction = 0; direction < 2; direction++)
Packit 0ec9dd
    {
Packit 0ec9dd
      PangoGlyphItemIter iter;
Packit 0ec9dd
      gboolean have_cluster;
Packit 0ec9dd
Packit 0ec9dd
Packit 0ec9dd
      for (have_cluster = direction ?
Packit 0ec9dd
	     pango_glyph_item_iter_init_start (&iter, run, text) :
Packit 0ec9dd
	     pango_glyph_item_iter_init_end (&iter, run, text);
Packit 0ec9dd
	   have_cluster;
Packit 0ec9dd
	   have_cluster = direction ?
Packit 0ec9dd
	     pango_glyph_item_iter_next_cluster (&iter) :
Packit 0ec9dd
	     pango_glyph_item_iter_prev_cluster (&iter))
Packit 0ec9dd
      {
Packit 0ec9dd
        verbose ("start index %d end index %d\n", iter.start_index, iter.end_index);
Packit 0ec9dd
        g_assert (iter.start_index < iter.end_index);
Packit 0ec9dd
        g_assert (iter.start_index + 2 >= iter.end_index);
Packit 0ec9dd
        g_assert (iter.start_char + 1 == iter.end_char);
Packit 0ec9dd
      }
Packit 0ec9dd
    }
Packit 0ec9dd
  }
Packit 0ec9dd
Packit 0ec9dd
  g_object_unref (layout);
Packit 0ec9dd
  g_object_unref (context);
Packit 0ec9dd
  pango_font_description_free (font_desc);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
int
Packit 0ec9dd
main (int argc, char *argv[])
Packit 0ec9dd
{
Packit 0ec9dd
  g_test_init (&argc, &argv, NULL);
Packit 0ec9dd
Packit 0ec9dd
  g_test_add_func ("/layout/iter", test_layout_iter);
Packit 0ec9dd
  g_test_add_func ("/layout/glyphitem-iter", test_glyphitem_iter);
Packit 0ec9dd
Packit 0ec9dd
  return g_test_run ();
Packit 0ec9dd
}