shithub: freetype+ttf2subf

Download patch

ref: 76c64f6ba1eb66cb983f38e03f39e179ceb74487
parent: e09fe4cc790086c2282313aa968dfef4a4196f91
author: Nikhil Ramakrishnan <[email protected]>
date: Sun Jun 23 21:07:18 EDT 2019

[woff2] Write SFNT Offset table.

* src/sfnt/sfwoff2.c (WRITE_USHORT, WRITE_ULONG): New macros.
(compare_tags): New function.
(woff2_open_font): Implement it.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2019-08-27  Nikhil Ramakrishnan  <[email protected]>
 
+	[woff2] Write SFNT Offset table.
+
+	* src/sfnt/sfwoff2.c (WRITE_USHORT, WRITE_ULONG): New macros.
+	(compare_tags): New function.
+	(woff2_open_font): Implement it.
+
+2019-08-27  Nikhil Ramakrishnan  <[email protected]>
+
 	* src/sfnt/sfwoff2.c: #undef macros.
 
 2019-08-27  Nikhil Ramakrishnan  <[email protected]>
--- a/src/sfnt/sfwoff2.c
+++ b/src/sfnt/sfwoff2.c
@@ -34,10 +34,50 @@
 
 
 #define READ_255USHORT( var )  Read255UShort( stream, &var )
+
 #define READ_BASE128( var )    ReadBase128( stream, &var )
+
 #define ROUND4( var )          ( var + 3 ) & ~3
 
+#define WRITE_USHORT( p, v )                \
+          do                                \
+          {                                 \
+            *(p)++ = (FT_Byte)( (v) >> 8 ); \
+            *(p)++ = (FT_Byte)( (v) >> 0 ); \
+                                            \
+          } while ( 0 )
 
+#define WRITE_ULONG( p, v )                  \
+          do                                 \
+          {                                  \
+            *(p)++ = (FT_Byte)( (v) >> 24 ); \
+            *(p)++ = (FT_Byte)( (v) >> 16 ); \
+            *(p)++ = (FT_Byte)( (v) >>  8 ); \
+            *(p)++ = (FT_Byte)( (v) >>  0 ); \
+                                             \
+          } while ( 0 )
+
+
+  FT_CALLBACK_DEF( int )
+  compare_tags( const void*  a,
+                const void*  b )
+  {
+    WOFF2_Table  table1 = *(WOFF2_Table*)a;
+    WOFF2_Table  table2 = *(WOFF2_Table*)b;
+
+    FT_ULong  tag1 = table1->Tag;
+    FT_ULong  tag2 = table2->Tag;
+
+
+    if ( tag1 > tag2 )
+      return 1;
+    else if ( tag1 < tag2 )
+      return -1;
+    else
+      return 0;
+  }
+
+
   static FT_Error
   Read255UShort( FT_Stream   stream,
                  FT_UShort*  value )
@@ -183,6 +223,10 @@
     FT_UInt64        first_table_offset;
     FT_UInt64        file_offset;
 
+    FT_Byte*         sfnt        = NULL;
+    FT_Stream        sfnt_stream = NULL;
+    FT_Byte*         sfnt_header;
+
     static const FT_Frame_Field  woff2_header_fields[] =
     {
 #undef  FT_STRUCTURE
@@ -211,6 +255,9 @@
     FT_ASSERT( stream == face->root.stream );
     FT_ASSERT( FT_STREAM_POS() == 0 );
 
+    /* DEBUG - Remove later. */
+    FT_TRACE2(( "Face index = %ld\n", face->root.face_index ));
+
     /* Read WOFF2 Header. */
     if ( FT_STREAM_READ_FIELDS( woff2_header_fields, &woff2 ) )
       return error;
@@ -408,7 +455,7 @@
             return FT_THROW( Invalid_Table );
           /* DEBUG - Remove later */
           else
-            FT_TRACE2(( "Glyf and loca are valid.\n" ));
+            FT_TRACE2(( "glyf and loca are valid.\n" ));
         }
       }
       /* Collection directory reading complete. */
@@ -444,11 +491,82 @@
     if( file_offset != ( ROUND4( woff2.length ) ) )
       return FT_THROW( Invalid_Table );
 
+    /* Redirect a TTC to exit for now. */
+    if( woff2.header_version )
+    {
+      FT_TRACE2(( "Reading TTC fonts not supported yet.\n" ));
+      error = FT_THROW( Unimplemented_Feature );
+      goto Exit;
+    }
+
+    /* Write sfnt header. */
+    if ( FT_ALLOC( sfnt, 12 + woff2.num_tables * 16UL ) ||
+         FT_NEW( sfnt_stream )                         )
+      goto Exit;
+
+    sfnt_header = sfnt;
+
+    {
+      FT_UInt  searchRange, entrySelector, rangeShift, x;
+      /* DEBUG - Remove later */
+      FT_TRACE2(( "Writing SFNT offset table.\n" ));
+
+      x             = woff2.num_tables;
+      entrySelector = 0;
+      while ( x )
+      {
+        x            >>= 1;
+        entrySelector += 1;
+      }
+      entrySelector--;
+
+      searchRange = ( 1 << entrySelector ) * 16;
+      rangeShift  = ( woff2.num_tables * 16  ) - searchRange;
+
+      WRITE_ULONG ( sfnt_header, woff2.flavor );
+      WRITE_USHORT( sfnt_header, woff2.num_tables );
+      WRITE_USHORT( sfnt_header, searchRange );
+      WRITE_USHORT( sfnt_header, entrySelector );
+      WRITE_USHORT( sfnt_header, rangeShift );
+
+    }
+
+    /* Sort tables by tag. */
+    ft_qsort( indices,
+              woff2.num_tables,
+              sizeof ( WOFF2_Table ),
+              compare_tags );
+
+    /* DEBUG - Remove later */
+    FT_TRACE2(( "Sorted table indices: \n" ));
+    for( nn = 0; nn < woff2.num_tables; ++nn )
+    {
+      WOFF2_Table  table = indices[nn];
+      /* DEBUG - Remove later */
+      FT_TRACE2(( "  Index %d", nn ));
+      FT_TRACE2(( " %c%c%c%c\n",
+                  (FT_Char)( table->Tag >> 24 ),
+                  (FT_Char)( table->Tag >> 16 ),
+                  (FT_Char)( table->Tag >> 8  ),
+                  (FT_Char)( table->Tag       )));
+    }
+
     error = FT_THROW( Unimplemented_Feature );
+    /* DEBUG - Remove later */
     FT_TRACE2(( "Reached end without errors.\n" ));
     goto Exit;
 
   Exit:
+    FT_FREE( tables );
+    FT_FREE( indices );
+
+    if( error )
+    {
+      FT_FREE( sfnt );
+      FT_Stream_Close( sfnt_stream );
+      FT_FREE( sfnt_stream );
+    }
+
     return error;
   }
 
@@ -456,6 +574,8 @@
 #undef READ_255USHORT
 #undef READ_BASE128
 #undef ROUND4
+#undef WRITE_USHORT
+#undef WRITE_ULONG
 
 
 /* END */