Commit 56ddafa01ce251d2f1f3adde3b0f72dd8ff7a405

Behdad Esfahbod 2015-01-14T19:36:02

[autofit] Add embedded array of segments and edges. Avoids multiple mallocs per typical glyphs. With this and recent changes to avoid mallocs, the thread-safe stack-based loader is now as fast as the previous model that had one cached singleton. * src/autofit/afhints.h (AF_SEGMENTS_EMBEDDED, AF_EDGES_EMBEDDED): New macros. (AF_AxisHintsRec): Add two arrays for segments and edges. * src/autofit/afhints.c (af_axis_hints_new_segment): Only allocate data if number of segments exceeds given threshold value. (af_axis_hints_new_edge): Only allocate data if number of edges exceeds given threshold value. (af_glyph_hints_done): Updated.

diff --git a/ChangeLog b/ChangeLog
index 0ee008e..6eaa010 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
 2015-01-14  Behdad Esfahbod  <behdad@behdad.org>
 
+	[autofit] Add embedded array of segments and edges.
+
+	Avoids multiple mallocs per typical glyphs.
+
+	With this and recent changes to avoid mallocs, the thread-safe
+	stack-based loader is now as fast as the previous model that had one
+	cached singleton.
+
+	* src/autofit/afhints.h (AF_SEGMENTS_EMBEDDED, AF_EDGES_EMBEDDED):
+	New macros.
+	(AF_AxisHintsRec): Add two arrays for segments and edges.
+
+	* src/autofit/afhints.c (af_axis_hints_new_segment): Only allocate
+	data if number of segments exceeds given threshold value.
+	(af_axis_hints_new_edge):  Only allocate data if number of edges
+	exceeds given threshold value.
+	(af_glyph_hints_done): Updated.
+
+2015-01-14  Behdad Esfahbod  <behdad@behdad.org>
+
 	[autofit] Add embedded arrays for points and contours.
 
 	This avoids at least two malloc calls for typical glyphs.
diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c
index 32e445b..eb3b4ff 100644
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -43,7 +43,15 @@
     AF_Segment  segment = NULL;
 
 
-    if ( axis->num_segments >= axis->max_segments )
+    if ( axis->num_segments < AF_SEGMENTS_EMBEDDED )
+    {
+      if ( axis->segments == NULL )
+      {
+        axis->segments     = axis->embedded.segments;
+        axis->max_segments = AF_SEGMENTS_EMBEDDED;
+      }
+    }
+    else if ( axis->num_segments >= axis->max_segments )
     {
       FT_Int  old_max = axis->max_segments;
       FT_Int  new_max = old_max;
@@ -60,8 +68,18 @@
       if ( new_max < old_max || new_max > big_max )
         new_max = big_max;
 
-      if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
-        goto Exit;
+      if ( axis->segments == axis->embedded.segments )
+      {
+        if ( FT_NEW_ARRAY( axis->segments, new_max ) )
+          goto Exit;
+        ft_memcpy( axis->segments, axis->embedded.segments,
+                   sizeof ( axis->embedded.segments ) );
+      }
+      else
+      {
+        if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
+          goto Exit;
+      }
 
       axis->max_segments = new_max;
     }
@@ -89,7 +107,15 @@
     AF_Edge   edges;
 
 
-    if ( axis->num_edges >= axis->max_edges )
+    if ( axis->num_edges < AF_EDGES_EMBEDDED )
+    {
+      if ( axis->edges == NULL )
+      {
+        axis->edges     = axis->embedded.edges;
+        axis->max_edges = AF_EDGES_EMBEDDED;
+      }
+    }
+    else if ( axis->num_edges >= axis->max_edges )
     {
       FT_Int  old_max = axis->max_edges;
       FT_Int  new_max = old_max;
@@ -106,8 +132,18 @@
       if ( new_max < old_max || new_max > big_max )
         new_max = big_max;
 
-      if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
-        goto Exit;
+      if ( axis->edges == axis->embedded.edges )
+      {
+        if ( FT_NEW_ARRAY( axis->edges, new_max ) )
+          goto Exit;
+        ft_memcpy( axis->edges, axis->embedded.edges,
+                   sizeof ( axis->embedded.edges ) );
+      }
+      else
+      {
+        if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
+          goto Exit;
+      }
 
       axis->max_edges = new_max;
     }
@@ -515,11 +551,13 @@
 
       axis->num_segments = 0;
       axis->max_segments = 0;
-      FT_FREE( axis->segments );
+      if ( axis->segments != axis->embedded.segments )
+        FT_FREE( axis->segments );
 
       axis->num_edges = 0;
       axis->max_edges = 0;
-      FT_FREE( axis->edges );
+      if ( axis->edges != axis->embedded.edges )
+        FT_FREE( axis->edges );
     }
 
     if ( hints->contours != hints->embedded.contours )
diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h
index 01e9d70..4796466 100644
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -305,6 +305,8 @@ FT_BEGIN_HEADER
 
   } AF_EdgeRec;
 
+#define AF_SEGMENTS_EMBEDDED  18   /* number of embedded segments   */
+#define AF_EDGES_EMBEDDED     12   /* number of embedded edges      */
 
   typedef struct  AF_AxisHintsRec_
   {
@@ -321,6 +323,14 @@ FT_BEGIN_HEADER
 
     AF_Direction  major_dir;    /* either vertical or horizontal */
 
+    /* two arrays to avoid allocation penalty */
+    struct
+    {
+      AF_SegmentRec  segments[AF_SEGMENTS_EMBEDDED];
+      AF_EdgeRec     edges[AF_EDGES_EMBEDDED];
+    } embedded;
+
+
   } AF_AxisHintsRec, *AF_AxisHints;