[HB] Improve buffer. Don't dup out buffer unless out is longer than in
authorBehdad Esfahbod <behdad@behdad.org>
Sat, 30 May 2009 16:02:46 +0000 (12:02 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Mon, 2 Nov 2009 19:40:22 +0000 (14:40 -0500)
That is, we work in-place even for ligatures now.

src/hb-buffer.c
src/hb-buffer.h

index 0fec18c..308fb70 100644 (file)
  *
  * As an optimization, both in_string and out_string may point to the
  * same piece of memory, which is owned by in_string.  This remains the
- * case as long as:
+ * case as long as out_length doesn't exceed in_length at any time.
+ * In that case, swap() is no-op and the glyph operations operate mostly
+ * in-place.
  *
- *   - copy_glyph() is called
- *   - replace_glyph() is called with inplace=TRUE
- *   - add_output_glyph() and add_output_glyphs() are not called
- *
- * In that case swap(), and copy_glyph(), and replace_glyph() are all
- * mostly no-op.
- *
- * As soon an add_output_glyph[s]() or replace_glyph() with inplace=FALSE is
- * called, out_string is moved over to an alternate buffer (alt_string), and
- * its current contents (out_length entries) are copied to the alt buffer.
- * This should all remain transparent to the user.  swap() then switches
- * in_string and alt_string.  alt_string is not allocated until its needed,
- * but after that it's grown with in_string unconditionally.
- *
- * The buffer->separate_out boolean keeps status of whether out_string points
- * to in_string (FALSE) or alt_string (TRUE).
+ * As soon as out_string gets longer than in_string, out_string is moved over
+ * to an alternate buffer (alt_string), and its current contents (out_length
+ * entries) are copied to the alt buffer.  This should all remain transparent
+ * to the user.  swap() then switches in_string and alt_string.  alt_string is
+ * not allocated until its needed, but after that it's grown with in_string
+ * unconditionally.
  */
 
 /* XXX err handling */
@@ -66,52 +58,47 @@ hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
   unsigned int new_allocated = buffer->allocated;
 
   if (size > new_allocated)
+  {
+    while (size > new_allocated)
+      new_allocated += (new_allocated >> 1) + 8;
+
+    if (buffer->positions)
+      buffer->positions = realloc (buffer->positions, new_allocated * sizeof (buffer->positions[0]));
+
+    buffer->in_string = realloc (buffer->in_string, new_allocated * sizeof (buffer->in_string[0]));
+
+    if (buffer->out_string != buffer->in_string)
     {
-      while (size > new_allocated)
-       new_allocated += (new_allocated >> 1) + 8;
-
-      if (buffer->positions)
-       buffer->positions = realloc (buffer->positions, new_allocated * sizeof (buffer->positions[0]));
-
-      buffer->in_string = realloc (buffer->in_string, new_allocated * sizeof (buffer->in_string[0]));
-
-      if (buffer->separate_out)
-        {
-         buffer->alt_string = realloc (buffer->alt_string, new_allocated * sizeof (buffer->alt_string[0]));
-         buffer->out_string = buffer->alt_string;
-       }
-      else
-        {
-         buffer->out_string = buffer->in_string;
-
-         if (buffer->alt_string)
-           {
-             free (buffer->alt_string);
-             buffer->alt_string = NULL;
-           }
-       }
-
-      buffer->allocated = new_allocated;
+      buffer->alt_string = realloc (buffer->alt_string, new_allocated * sizeof (buffer->alt_string[0]));
+      buffer->out_string = buffer->alt_string;
     }
-}
+    else
+    {
+      buffer->out_string = buffer->in_string;
 
-static void
-hb_buffer_duplicate_out_buffer (hb_buffer_t *buffer)
-{
-  if (!buffer->alt_string)
-    buffer->alt_string = malloc (buffer->allocated * sizeof (buffer->alt_string[0]));
+      if (buffer->alt_string)
+      {
+       free (buffer->alt_string);
+       buffer->alt_string = NULL;
+      }
+    }
 
-  buffer->out_string = buffer->alt_string;
-  memcpy (buffer->out_string, buffer->in_string, buffer->out_length * sizeof (buffer->out_string[0]));
-  buffer->separate_out = TRUE;
+    buffer->allocated = new_allocated;
+  }
 }
 
 static void
 hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
 {
   hb_buffer_ensure (buffer, size);
-  if ( !buffer->separate_out )
-    hb_buffer_duplicate_out_buffer (buffer);
+  if (buffer->out_string == buffer->in_string)
+  {
+    if (!buffer->alt_string)
+      buffer->alt_string = malloc (buffer->allocated * sizeof (buffer->alt_string[0]));
+
+    buffer->out_string = buffer->alt_string;
+    memcpy (buffer->out_string, buffer->in_string, buffer->out_length * sizeof (buffer->out_string[0]));
+  }
 }
 
 /* Public API */
@@ -152,7 +139,6 @@ hb_buffer_clear (hb_buffer_t *buffer)
   buffer->in_pos = 0;
   buffer->out_pos = 0;
   buffer->out_string = buffer->in_string;
-  buffer->separate_out = FALSE;
   buffer->max_lig_id = 0;
 }
 
@@ -185,7 +171,6 @@ _hb_buffer_clear_output (hb_buffer_t *buffer)
   buffer->out_length = 0;
   buffer->out_pos = 0;
   buffer->out_string = buffer->in_string;
-  buffer->separate_out = FALSE;
 }
 
 HB_INTERNAL void
@@ -207,14 +192,14 @@ _hb_buffer_swap (hb_buffer_t *buffer)
 {
   unsigned int tmp;
 
-  if (buffer->separate_out)
-    {
-      hb_glyph_info_t *tmp_string;
-      tmp_string = buffer->in_string;
-      buffer->in_string = buffer->out_string;
-      buffer->out_string = tmp_string;
-      buffer->alt_string = buffer->out_string;
-    }
+  if (buffer->out_string != buffer->in_string)
+  {
+    hb_glyph_info_t *tmp_string;
+    tmp_string = buffer->in_string;
+    buffer->in_string = buffer->out_string;
+    buffer->out_string = tmp_string;
+    buffer->alt_string = buffer->out_string;
+  }
 
   tmp = buffer->in_length;
   buffer->in_length = buffer->out_length;
@@ -256,7 +241,11 @@ _hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
   unsigned int properties;
   unsigned int cluster;
 
-  hb_buffer_ensure_separate (buffer, buffer->out_pos + num_out);
+  if (buffer->out_string == buffer->in_string &&
+      buffer->out_pos + num_out > buffer->in_pos + num_in)
+  {
+    hb_buffer_ensure_separate (buffer, buffer->out_pos + num_out);
+  }
 
   properties = buffer->in_string[buffer->in_pos].properties;
   cluster = buffer->in_string[buffer->in_pos].cluster;
@@ -268,7 +257,6 @@ _hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
   for (i = 0; i < num_out; i++)
   {
     hb_glyph_info_t *info = &buffer->out_string[buffer->out_pos + i];
-
     info->gindex = hb_be_uint16_t (glyph_data_be[i]);
     info->properties = properties;
     info->cluster = cluster;
@@ -279,7 +267,6 @@ _hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
 
   buffer->in_pos  += num_in;
   buffer->out_pos += num_out;
-
   buffer->out_length = buffer->out_pos;
 }
 
@@ -292,11 +279,15 @@ _hb_buffer_add_output_glyph (hb_buffer_t *buffer,
 {
   hb_glyph_info_t *info;
 
-  hb_buffer_ensure_separate (buffer, buffer->out_pos + 1);
+  if (buffer->out_string != buffer->in_string)
+  {
+    hb_buffer_ensure (buffer, buffer->out_pos + 1);
+    buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos];
+  }
+  else if (buffer->out_pos != buffer->in_pos)
+    buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos];
 
   info = &buffer->out_string[buffer->out_pos];
-  *info = buffer->in_string[buffer->in_pos];
-
   info->gindex = glyph_index;
   if (component != 0xFFFF)
     info->component = component;
@@ -306,19 +297,19 @@ _hb_buffer_add_output_glyph (hb_buffer_t *buffer,
 
   buffer->in_pos++;
   buffer->out_pos++;
-
   buffer->out_length = buffer->out_pos;
 }
 
 HB_INTERNAL void
 _hb_buffer_next_glyph (hb_buffer_t *buffer)
 {
-  if (buffer->separate_out)
-    {
-      hb_buffer_ensure (buffer, buffer->out_pos + 1);
-
-      buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos];
-    }
+  if (buffer->out_string != buffer->in_string)
+  {
+    hb_buffer_ensure (buffer, buffer->out_pos + 1);
+    buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos];
+  }
+  else if (buffer->out_pos != buffer->in_pos)
+    buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos];
 
   buffer->in_pos++;
   buffer->out_pos++;
@@ -329,18 +320,7 @@ HB_INTERNAL void
 _hb_buffer_replace_glyph (hb_buffer_t *buffer,
                          hb_codepoint_t glyph_index)
 {
-  if (!buffer->separate_out)
-    {
-      buffer->out_string[buffer->out_pos].gindex = glyph_index;
-
-      buffer->in_pos++;
-      buffer->out_pos++;
-      buffer->out_length = buffer->out_pos;
-    }
-  else
-    {
-      return _hb_buffer_add_output_glyph (buffer, glyph_index, 0xFFFF, 0xFFFF);
-    }
+  _hb_buffer_add_output_glyph (buffer, glyph_index, 0xFFFF, 0xFFFF);
 }
 
 HB_INTERNAL unsigned short
index 64debde..afdf642 100644 (file)
@@ -49,14 +49,14 @@ typedef struct _hb_glyph_position_t {
   hb_position_t  x_advance;
   hb_position_t  y_advance;
   unsigned short back;         /* number of glyphs to go back
-                                  for drawing current glyph   */
+                                  for drawing current glyph */
   hb_bool_t      new_advance;  /* if set, the advance width values are
                                   absolute, i.e., they won't be
                                   added to the original glyph's value
-                                  but rather replace them.            */
+                                  but rather replace them */
   short          cursive_chain; /* character to which this connects,
                                   may be positive or negative; used
-                                  only internally                     */
+                                  only internally */
 } hb_glyph_position_t;
 
 
@@ -68,7 +68,6 @@ typedef struct _hb_buffer_t {
   unsigned int in_pos;
   unsigned int out_pos;
 
-  hb_bool_t            separate_out;
   hb_glyph_info_t     *in_string;
   hb_glyph_info_t     *out_string;
   hb_glyph_info_t     *alt_string;