freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[freetype2] master 9f62d2c 1/2: [cff] Implement CFF2 support (1/2).


From: Werner LEMBERG
Subject: [freetype2] master 9f62d2c 1/2: [cff] Implement CFF2 support (1/2).
Date: Thu, 15 Dec 2016 21:14:07 +0000 (UTC)

branch: master
commit 9f62d2ca061e23948fad738830f4d274abfe75e9
Author: Dave Arnold <address@hidden>
Commit: Werner Lemberg <address@hidden>

    [cff] Implement CFF2 support (1/2).
    
    This commit does not contain the blend code for font variation
    support, which follows in another commit.
    
    You should ignore whitespace while inspecting this commit.
    
    * include/freetype/internal/tttypes.h (TT_Face): Add `isCFF2'
    member.
    
    * src/cff/cf2font.h (CF2_Font): Add `isCFF2' member.
    
    * src/cff/cf2ft.c (cf2_decoder_parse_charstrings): Handle `isCFF2'
    flag.
    (cf2_getMaxstack): New function.
    * src/cff/cf2ft.h: Updated.
    
    * src/cff/cf2intrp.c (cf2_escRESERVED_38): New enum.
    (cf2_interpT2CharString): Handle CFF2 differences.
    Add tracing message for errors.
    
    * src/cff/cffdrivr.c (cff_get_glyph_name, cff_get_name_index):
    Update for CFF2.
    
    * src/cff/cffload.c (FT_FIXED_ONE): New macro.
    (cff_index_init, cff_index_load_offsets, cff_index_access_element,
    cff_index_get_name, cff_ft_select_get, cff_load_private_dict,
    cff_subfont_load, cff_font_load): Handle CFF2.
    * src/cff/cffload.h: Updated.
    
    * src/cff/cffobjs.c (cff_face_init): Handle CFF2.
    
    * src/cff/cffparse.c (cff_parse_maxstack): New function.
    (CFFCODE_TOPDICT, CFFCODE_PRIVATE): Removed
    * src/cff/cffparse.h (CFF2_MAX_STACK, CFF2_DEFAULT_STACK): New
    macros.
    (CFF2_CODE_TOPDICT, CFF2_CODE_FONTDICT, CFF2_CODE_PRIVATE): New
    macros.
    
    * src/cff/cfftoken.h: Add fields for CFF2 dictionaries (but no blend
    stuff).
    
    * src/cff/cfftypes.h (CFF_Index): Add `hdr_size' field.
    (CFF_FontRecDict): Add `maxstack' field.
    (CFF_Private): Add `subfont' field.
    (CFF_Font): Add `top_dict_length' and `cff2' fields.
    
    * src/sfnt/sfobjs.c (sfnt_load_face): Handle `CFF2' table.
---
 ChangeLog                           |   52 ++++
 include/freetype/internal/tttypes.h |    2 +
 src/cff/cf2font.c                   |    6 +-
 src/cff/cf2font.h                   |    1 +
 src/cff/cf2ft.c                     |   13 +
 src/cff/cf2ft.h                     |    4 +
 src/cff/cf2intrp.c                  |  487 +++++++++++++++++++----------------
 src/cff/cffdrivr.c                  |   54 ++++
 src/cff/cffload.c                   |  219 ++++++++++++----
 src/cff/cffload.h                   |   11 +-
 src/cff/cffobjs.c                   |   22 +-
 src/cff/cffparse.c                  |   32 ++-
 src/cff/cffparse.h                  |   13 +-
 src/cff/cfftoken.h                  |   46 +++-
 src/cff/cfftypes.h                  |   24 +-
 src/sfnt/sfobjs.c                   |   15 +-
 16 files changed, 694 insertions(+), 307 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5a1b3ac..c37cde2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+2016-12-15  Dave Arnold  <address@hidden>
+           Werner Lemberg  <address@hidden>
+
+       [cff] Implement CFF2 support (1/2).
+
+       This commit does not contain the blend code for font variation
+       support, which follows in another commit.
+
+       You should ignore whitespace while inspecting this commit.
+
+       * include/freetype/internal/tttypes.h (TT_Face): Add `isCFF2'
+       member.
+
+       * src/cff/cf2font.h (CF2_Font): Add `isCFF2' member.
+
+       * src/cff/cf2ft.c (cf2_decoder_parse_charstrings): Handle `isCFF2'
+       flag.
+       (cf2_getMaxstack): New function.
+       * src/cff/cf2ft.h: Updated.
+
+       * src/cff/cf2intrp.c (cf2_escRESERVED_38): New enum.
+       (cf2_interpT2CharString): Handle CFF2 differences.
+       Add tracing message for errors.
+
+       * src/cff/cffdrivr.c (cff_get_glyph_name, cff_get_name_index):
+       Update for CFF2.
+
+       * src/cff/cffload.c (FT_FIXED_ONE): New macro.
+       (cff_index_init, cff_index_load_offsets, cff_index_access_element,
+       cff_index_get_name, cff_ft_select_get, cff_load_private_dict,
+       cff_subfont_load, cff_font_load): Handle CFF2.
+       * src/cff/cffload.h: Updated.
+
+       * src/cff/cffobjs.c (cff_face_init): Handle CFF2.
+
+       * src/cff/cffparse.c (cff_parse_maxstack): New function.
+       (CFFCODE_TOPDICT, CFFCODE_PRIVATE): Removed
+       * src/cff/cffparse.h (CFF2_MAX_STACK, CFF2_DEFAULT_STACK): New
+       macros.
+       (CFF2_CODE_TOPDICT, CFF2_CODE_FONTDICT, CFF2_CODE_PRIVATE): New
+       macros.
+
+       * src/cff/cfftoken.h: Add fields for CFF2 dictionaries (but no blend
+       stuff).
+
+       * src/cff/cfftypes.h (CFF_Index): Add `hdr_size' field.
+       (CFF_FontRecDict): Add `maxstack' field.
+       (CFF_Private): Add `subfont' field.
+       (CFF_Font): Add `top_dict_length' and `cff2' fields.
+
+       * src/sfnt/sfobjs.c (sfnt_load_face): Handle `CFF2' table.
+
 2016-12-15  Werner Lemberg  <address@hidden>
            Dave Arnold  <address@hidden>
 
diff --git a/include/freetype/internal/tttypes.h 
b/include/freetype/internal/tttypes.h
index ee5e866..edaf113 100644
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1419,6 +1419,8 @@ FT_BEGIN_HEADER
     FT_ULong              glyf_len;
     FT_ULong              glyf_offset;    /* since 2.7.1 */
 
+    FT_Bool               isCFF2;         /* since 2.7.1 */
+
 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
     FT_Bool               doblend;
     GX_Blend              blend;
diff --git a/src/cff/cf2font.c b/src/cff/cf2font.c
index 83fd348..508b273 100644
--- a/src/cff/cf2font.c
+++ b/src/cff/cf2font.c
@@ -234,7 +234,8 @@
   }
 
 
-  /* set up values for the current FontDict and matrix */
+  /* set up values for the current FontDict and matrix; */
+  /* called for each glyph to be rendered               */
 
   /* caller's transform is adjusted for subpixel positioning */
   static void
@@ -423,7 +424,8 @@
 
       /* compute blue zones for this instance */
       cf2_blues_init( &font->blues, font );
-    }
+
+    } /* needExtraSetup */
   }
 
 
diff --git a/src/cff/cf2font.h b/src/cff/cf2font.h
index bd05e69..b1ffb79 100644
--- a/src/cff/cf2font.h
+++ b/src/cff/cf2font.h
@@ -63,6 +63,7 @@ FT_BEGIN_HEADER
     FT_Memory  memory;
     FT_Error   error;     /* shared error for this instance */
 
+    FT_Bool             isCFF2;
     CF2_RenderingFlags  renderingFlags;
 
     /* variables that depend on Transform:  */
diff --git a/src/cff/cf2ft.c b/src/cff/cf2ft.c
index edbe6a7..e35dcf6 100644
--- a/src/cff/cf2ft.c
+++ b/src/cff/cf2ft.c
@@ -366,6 +366,9 @@
                                &hinted,
                                &scaled );
 
+      /* copy isCFF2 boolean from TT_Face to CF2_Font */
+      font->isCFF2 = builder->face->isCFF2;
+
       font->renderingFlags = 0;
       if ( hinted )
         font->renderingFlags |= CF2_FlagsHinted;
@@ -413,6 +416,16 @@
   }
 
 
+  /* get maxstack value from CFF2 Top DICT */
+  FT_LOCAL_DEF( FT_UInt )
+  cf2_getMaxstack( CFF_Decoder*  decoder )
+  {
+    FT_ASSERT( decoder && decoder->cff );
+
+    return decoder->cff->top_font.font_dict.maxstack;
+  }
+
+
   /* get `y_ppem' from `CFF_Size' */
   FT_LOCAL_DEF( CF2_Fixed )
   cf2_getPpemY( CFF_Decoder*  decoder )
diff --git a/src/cff/cf2ft.h b/src/cff/cf2ft.h
index 8e55e84..5ec78e4 100644
--- a/src/cff/cf2ft.h
+++ b/src/cff/cf2ft.h
@@ -65,6 +65,10 @@ FT_BEGIN_HEADER
   cf2_getSubfont( CFF_Decoder*  decoder );
 
 
+  FT_LOCAL( FT_UInt )
+  cf2_getMaxstack( CFF_Decoder*  decoder );
+
+
   FT_LOCAL( CF2_Fixed )
   cf2_getPpemY( CFF_Decoder*  decoder );
   FT_LOCAL( CF2_Fixed )
diff --git a/src/cff/cf2intrp.c b/src/cff/cf2intrp.c
index 98e73ea..a6bb929 100644
--- a/src/cff/cf2intrp.c
+++ b/src/cff/cf2intrp.c
@@ -273,7 +273,8 @@
     cf2_escHFLEX,        /* 34 */
     cf2_escFLEX,         /* 35 */
     cf2_escHFLEX1,       /* 36 */
-    cf2_escFLEX1         /* 37 */
+    cf2_escFLEX1,        /* 37 */
+    cf2_escRESERVED_38   /* 38     & all higher     */
   };
 
 
@@ -445,6 +446,7 @@
     CF2_Fixed  hintOriginY = curY;
 
     CF2_Stack  opStack = NULL;
+    FT_UInt    stackSize;
     FT_Byte    op1;                       /* first opcode byte */
 
     CF2_F16Dot16  storage[CF2_STORAGE_SIZE];    /* for `put' and `get' */
@@ -520,19 +522,24 @@
      * If one of the above operators occurs without explicitly specifying
      * a width, we assume the default width.
      *
+     * CFF2 charstrings always return the default width (0).
+     *
      */
-    haveWidth = FALSE;
+    haveWidth = font->isCFF2 ? TRUE : FALSE;
     *width    = cf2_getDefaultWidthX( decoder );
 
     /*
-     * Note: at this point, all pointers to resources must be NULL
-     * and all local objects must be initialized.
-     * There must be no branches to exit: above this point.
+     * Note: At this point, all pointers to resources must be NULL
+     *       and all local objects must be initialized.
+     *       There must be no branches to `exit:' above this point.
      *
      */
 
     /* allocate an operand stack */
-    opStack = cf2_stack_init( memory, error, CF2_OPERAND_STACK_SIZE );
+    stackSize = font->isCFF2 ? cf2_getMaxstack( decoder )
+                             : CF2_OPERAND_STACK_SIZE;
+    opStack   = cf2_stack_init( memory, error, stackSize );
+
     if ( !opStack )
     {
       lastError = FT_THROW( Out_Of_Memory );
@@ -561,14 +568,23 @@
       {
         /* If we've reached the end of the charstring, simulate a */
         /* cf2_cmdRETURN or cf2_cmdENDCHAR.                       */
+        /* We do this for both CFF and CFF2.                      */
         if ( charstringIndex )
           op1 = cf2_cmdRETURN;  /* end of buffer for subroutine */
         else
           op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
       }
       else
+      {
         op1 = (FT_Byte)cf2_buf_readByte( charstring );
 
+        /* Explicit RETURN and ENDCHAR in CFF2 should be ignored. */
+        /* Note: Trace message will report 0 instead of 11 or 14. */
+        if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) &&
+             font->isCFF2                                      )
+          op1 = cf2_cmdRESERVED_0;
+      }
+
       /* check for errors once per loop */
       if ( *error )
         goto exit;
@@ -830,6 +846,8 @@
           FT_Byte  op2 = (FT_Byte)cf2_buf_readByte( charstring );
 
 
+          /* first switch for 2-byte operators handles CFF2      */
+          /* and opcodes that are reserved for both CFF and CFF2 */
           switch ( op2 )
           {
           case cf2_escHFLEX:
@@ -928,6 +946,7 @@
             }
             continue;
 
+          /* these opcodes are reserved in both CFF & CFF2 */
           case cf2_escRESERVED_1:
           case cf2_escRESERVED_2:
           case cf2_escRESERVED_6:
@@ -944,329 +963,339 @@
             FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
             break;
 
-          case cf2_escDOTSECTION:
-            /* something about `flip type of locking' -- ignore it */
-            FT_TRACE4(( " dotsection\n" ));
-
-            break;
-
-          case cf2_escAND:
+          default:
             {
-              CF2_F16Dot16  arg1;
-              CF2_F16Dot16  arg2;
+              if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 )
+                FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
+              else
+              {
+                /* second switch for 2-byte operators handles just CFF */
+                switch ( op2 )
+                {
 
+                case cf2_escDOTSECTION:
+                  /* something about `flip type of locking' -- ignore it */
+                  FT_TRACE4(( " dotsection\n" ));
 
-              FT_TRACE4(( " and\n" ));
+                  break;
 
-              arg2 = cf2_stack_popFixed( opStack );
-              arg1 = cf2_stack_popFixed( opStack );
+                case cf2_escAND:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
 
-              cf2_stack_pushInt( opStack, arg1 && arg2 );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escOR:
-            {
-              CF2_F16Dot16  arg1;
-              CF2_F16Dot16  arg2;
+                    FT_TRACE4(( " and\n" ));
 
+                    arg2 = cf2_stack_popFixed( opStack );
+                    arg1 = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " or\n" ));
+                    cf2_stack_pushInt( opStack, arg1 && arg2 );
+                  }
+                  continue; /* do not clear the stack */
 
-              arg2 = cf2_stack_popFixed( opStack );
-              arg1 = cf2_stack_popFixed( opStack );
+                case cf2_escOR:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
 
-              cf2_stack_pushInt( opStack, arg1 || arg2 );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escNOT:
-            {
-              CF2_F16Dot16  arg;
+                    FT_TRACE4(( " or\n" ));
 
+                    arg2 = cf2_stack_popFixed( opStack );
+                    arg1 = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " not\n" ));
+                    cf2_stack_pushInt( opStack, arg1 || arg2 );
+                  }
+                  continue; /* do not clear the stack */
 
-              arg = cf2_stack_popFixed( opStack );
+                case cf2_escNOT:
+                  {
+                    CF2_F16Dot16  arg;
 
-              cf2_stack_pushInt( opStack, !arg );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escABS:
-            {
-              CF2_F16Dot16  arg;
+                    FT_TRACE4(( " not\n" ));
 
+                    arg = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " abs\n" ));
+                    cf2_stack_pushInt( opStack, !arg );
+                  }
+                  continue; /* do not clear the stack */
 
-              arg = cf2_stack_popFixed( opStack );
+                case cf2_escABS:
+                  {
+                    CF2_F16Dot16  arg;
 
-              cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escADD:
-            {
-              CF2_F16Dot16  summand1;
-              CF2_F16Dot16  summand2;
+                    FT_TRACE4(( " abs\n" ));
 
+                    arg = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " add\n" ));
+                    cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
+                  }
+                  continue; /* do not clear the stack */
 
-              summand2 = cf2_stack_popFixed( opStack );
-              summand1 = cf2_stack_popFixed( opStack );
+                case cf2_escADD:
+                  {
+                    CF2_F16Dot16  summand1;
+                    CF2_F16Dot16  summand2;
 
-              cf2_stack_pushFixed( opStack, summand1 + summand2 );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escSUB:
-            {
-              CF2_F16Dot16  minuend;
-              CF2_F16Dot16  subtrahend;
+                    FT_TRACE4(( " add\n" ));
 
+                    summand2 = cf2_stack_popFixed( opStack );
+                    summand1 = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " sub\n" ));
+                    cf2_stack_pushFixed( opStack, summand1 + summand2 );
+                  }
+                  continue; /* do not clear the stack */
 
-              subtrahend = cf2_stack_popFixed( opStack );
-              minuend    = cf2_stack_popFixed( opStack );
+                case cf2_escSUB:
+                  {
+                    CF2_F16Dot16  minuend;
+                    CF2_F16Dot16  subtrahend;
 
-              cf2_stack_pushFixed( opStack, minuend - subtrahend );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escDIV:
-            {
-              CF2_F16Dot16  dividend;
-              CF2_F16Dot16  divisor;
+                    FT_TRACE4(( " sub\n" ));
 
+                    subtrahend = cf2_stack_popFixed( opStack );
+                    minuend    = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " div\n" ));
+                    cf2_stack_pushFixed( opStack, minuend - subtrahend );
+                  }
+                  continue; /* do not clear the stack */
 
-              divisor  = cf2_stack_popFixed( opStack );
-              dividend = cf2_stack_popFixed( opStack );
+                case cf2_escDIV:
+                  {
+                    CF2_F16Dot16  dividend;
+                    CF2_F16Dot16  divisor;
 
-              cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escNEG:
-            {
-              CF2_F16Dot16  arg;
+                    FT_TRACE4(( " div\n" ));
 
+                    divisor  = cf2_stack_popFixed( opStack );
+                    dividend = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " neg\n" ));
+                    cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor 
) );
+                  }
+                  continue; /* do not clear the stack */
 
-              arg = cf2_stack_popFixed( opStack );
+                case cf2_escNEG:
+                  {
+                    CF2_F16Dot16  arg;
 
-              cf2_stack_pushFixed( opStack, -arg );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escEQ:
-            {
-              CF2_F16Dot16  arg1;
-              CF2_F16Dot16  arg2;
+                    FT_TRACE4(( " neg\n" ));
 
+                    arg = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " eq\n" ));
+                    cf2_stack_pushFixed( opStack, -arg );
+                  }
+                  continue; /* do not clear the stack */
 
-              arg2 = cf2_stack_popFixed( opStack );
-              arg1 = cf2_stack_popFixed( opStack );
+                case cf2_escEQ:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
 
-              cf2_stack_pushInt( opStack, arg1 == arg2 );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escDROP:
-            FT_TRACE4(( " drop\n" ));
+                    FT_TRACE4(( " eq\n" ));
 
-            (void)cf2_stack_popFixed( opStack );
-            continue; /* do not clear the stack */
+                    arg2 = cf2_stack_popFixed( opStack );
+                    arg1 = cf2_stack_popFixed( opStack );
 
-          case cf2_escPUT:
-            {
-              CF2_F16Dot16  val;
-              CF2_Int       idx;
+                    cf2_stack_pushInt( opStack, arg1 == arg2 );
+                  }
+                  continue; /* do not clear the stack */
 
+                case cf2_escDROP:
+                  FT_TRACE4(( " drop\n" ));
 
-              FT_TRACE4(( " put\n" ));
+                  (void)cf2_stack_popFixed( opStack );
+                  continue; /* do not clear the stack */
 
-              idx = cf2_stack_popInt( opStack );
-              val = cf2_stack_popFixed( opStack );
+                case cf2_escPUT:
+                  {
+                    CF2_F16Dot16  val;
+                    CF2_Int       idx;
 
-              if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
-                storage[idx] = val;
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escGET:
-            {
-              CF2_Int  idx;
+                    FT_TRACE4(( " put\n" ));
 
+                    idx = cf2_stack_popInt( opStack );
+                    val = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " get\n" ));
+                    if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
+                      storage[idx] = val;
+                  }
+                  continue; /* do not clear the stack */
 
-              idx = cf2_stack_popInt( opStack );
+                case cf2_escGET:
+                  {
+                    CF2_Int  idx;
 
-              if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
-                cf2_stack_pushFixed( opStack, storage[idx] );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escIFELSE:
-            {
-              CF2_F16Dot16  arg1;
-              CF2_F16Dot16  arg2;
-              CF2_F16Dot16  cond1;
-              CF2_F16Dot16  cond2;
+                    FT_TRACE4(( " get\n" ));
 
+                    idx = cf2_stack_popInt( opStack );
 
-              FT_TRACE4(( " ifelse\n" ));
+                    if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
+                    cf2_stack_pushFixed( opStack, storage[idx] );
+                  }
+                  continue; /* do not clear the stack */
 
-              cond2 = cf2_stack_popFixed( opStack );
-              cond1 = cf2_stack_popFixed( opStack );
-              arg2  = cf2_stack_popFixed( opStack );
-              arg1  = cf2_stack_popFixed( opStack );
+                case cf2_escIFELSE:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
+                    CF2_F16Dot16  cond1;
+                    CF2_F16Dot16  cond2;
 
-              cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escRANDOM: /* in spec */
-            FT_TRACE4(( " random\n" ));
+                    FT_TRACE4(( " ifelse\n" ));
 
-            CF2_FIXME;
-            break;
+                    cond2 = cf2_stack_popFixed( opStack );
+                    cond1 = cf2_stack_popFixed( opStack );
+                    arg2  = cf2_stack_popFixed( opStack );
+                    arg1  = cf2_stack_popFixed( opStack );
 
-          case cf2_escMUL:
-            {
-              CF2_F16Dot16  factor1;
-              CF2_F16Dot16  factor2;
+                    cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 
);
+                  }
+                  continue; /* do not clear the stack */
 
+                case cf2_escRANDOM: /* in spec */
+                  FT_TRACE4(( " random\n" ));
 
-              FT_TRACE4(( " mul\n" ));
+                  CF2_FIXME;
+                  break;
 
-              factor2 = cf2_stack_popFixed( opStack );
-              factor1 = cf2_stack_popFixed( opStack );
+                case cf2_escMUL:
+                  {
+                    CF2_F16Dot16  factor1;
+                    CF2_F16Dot16  factor2;
 
-              cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escSQRT:
-            {
-              CF2_F16Dot16  arg;
+                    FT_TRACE4(( " mul\n" ));
 
+                    factor2 = cf2_stack_popFixed( opStack );
+                    factor1 = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " sqrt\n" ));
+                    cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 
) );
+                  }
+                  continue; /* do not clear the stack */
 
-              arg = cf2_stack_popFixed( opStack );
-              if ( arg > 0 )
-              {
-                FT_Fixed  root = arg;
-                FT_Fixed  new_root;
+                case cf2_escSQRT:
+                  {
+                    CF2_F16Dot16  arg;
 
 
-                /* Babylonian method */
-                for (;;)
-                {
-                  new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
-                  if ( new_root == root )
-                    break;
-                  root = new_root;
-                }
-                arg = new_root;
-              }
-              else
-                arg = 0;
+                    FT_TRACE4(( " sqrt\n" ));
 
-              cf2_stack_pushFixed( opStack, arg );
-            }
-            continue; /* do not clear the stack */
+                    arg = cf2_stack_popFixed( opStack );
+                    if ( arg > 0 )
+                    {
+                      FT_Fixed  root = arg;
+                      FT_Fixed  new_root;
 
-          case cf2_escDUP:
-            {
-              CF2_F16Dot16  arg;
 
+                      /* Babylonian method */
+                      for (;;)
+                      {
+                        new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
+                        if ( new_root == root )
+                          break;
+                        root = new_root;
+                      }
+                      arg = new_root;
+                    }
+                    else
+                      arg = 0;
 
-              FT_TRACE4(( " dup\n" ));
+                    cf2_stack_pushFixed( opStack, arg );
+                  }
+                  continue; /* do not clear the stack */
 
-              arg = cf2_stack_popFixed( opStack );
+                case cf2_escDUP:
+                  {
+                    CF2_F16Dot16  arg;
 
-              cf2_stack_pushFixed( opStack, arg );
-              cf2_stack_pushFixed( opStack, arg );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escEXCH:
-            {
-              CF2_F16Dot16  arg1;
-              CF2_F16Dot16  arg2;
+                    FT_TRACE4(( " dup\n" ));
 
+                    arg = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " exch\n" ));
+                    cf2_stack_pushFixed( opStack, arg );
+                    cf2_stack_pushFixed( opStack, arg );
+                  }
+                  continue; /* do not clear the stack */
 
-              arg2 = cf2_stack_popFixed( opStack );
-              arg1 = cf2_stack_popFixed( opStack );
+                case cf2_escEXCH:
+                  {
+                    CF2_F16Dot16  arg1;
+                    CF2_F16Dot16  arg2;
 
-              cf2_stack_pushFixed( opStack, arg2 );
-              cf2_stack_pushFixed( opStack, arg1 );
-            }
-            continue; /* do not clear the stack */
 
-          case cf2_escINDEX:
-            {
-              CF2_Int   idx;
-              CF2_UInt  size;
+                    FT_TRACE4(( " exch\n" ));
 
+                    arg2 = cf2_stack_popFixed( opStack );
+                    arg1 = cf2_stack_popFixed( opStack );
 
-              FT_TRACE4(( " index\n" ));
+                    cf2_stack_pushFixed( opStack, arg2 );
+                    cf2_stack_pushFixed( opStack, arg1 );
+                  }
+                  continue; /* do not clear the stack */
 
-              idx  = cf2_stack_popInt( opStack );
-              size = cf2_stack_count( opStack );
+                case cf2_escINDEX:
+                  {
+                    CF2_Int   idx;
+                    CF2_UInt  size;
 
-              if ( size > 0 )
-              {
-                /* for `cf2_stack_getReal', index 0 is bottom of stack */
-                CF2_UInt  gr_idx;
 
+                    FT_TRACE4(( " index\n" ));
 
-                if ( idx < 0 )
-                  gr_idx = size - 1;
-                else if ( (CF2_UInt)idx >= size )
-                  gr_idx = 0;
-                else
-                  gr_idx = size - 1 - (CF2_UInt)idx;
+                    idx  = cf2_stack_popInt( opStack );
+                    size = cf2_stack_count( opStack );
 
-                cf2_stack_pushFixed( opStack,
-                                     cf2_stack_getReal( opStack, gr_idx ) );
-              }
-            }
-            continue; /* do not clear the stack */
+                    if ( size > 0 )
+                    {
+                      /* for `cf2_stack_getReal', index 0 is bottom of stack */
+                      CF2_UInt  gr_idx;
 
-          case cf2_escROLL:
-            {
-              CF2_Int  idx;
-              CF2_Int  count;
 
+                      if ( idx < 0 )
+                        gr_idx = size - 1;
+                      else if ( (CF2_UInt)idx >= size )
+                        gr_idx = 0;
+                      else
+                        gr_idx = size - 1 - (CF2_UInt)idx;
 
-              FT_TRACE4(( " roll\n" ));
+                      cf2_stack_pushFixed( opStack,
+                                           cf2_stack_getReal( opStack, gr_idx 
) );
+                    }
+                  }
+                  continue; /* do not clear the stack */
 
-              idx   = cf2_stack_popInt( opStack );
-              count = cf2_stack_popInt( opStack );
+                case cf2_escROLL:
+                  {
+                    CF2_Int  idx;
+                    CF2_Int  count;
 
-              cf2_stack_roll( opStack, count, idx );
-            }
-            continue; /* do not clear the stack */
 
-          default:
-            FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
+                    FT_TRACE4(( " roll\n" ));
+
+                    idx   = cf2_stack_popInt( opStack );
+                    count = cf2_stack_popInt( opStack );
 
-          }; /* end of switch statement checking `op2' */
+                    cf2_stack_roll( opStack, count, idx );
+                  }
+                  continue; /* do not clear the stack */
 
+                } /* end of 2nd switch checking op2 */
+              }
+            }
+          } /* end of 1st switch checking op2 */
         } /* case cf2_cmdESC */
+
         break;
 
       case cf2_cmdENDCHAR:
@@ -1288,7 +1317,8 @@
         /* close path if still open */
         cf2_glyphpath_closeOpenPath( &glyphPath );
 
-        if ( cf2_stack_count( opStack ) > 1 )
+        /* disable seac for CFF2 (charstring ending with args on stack) */
+        if ( !font->isCFF2 && cf2_stack_count( opStack ) > 1 )
         {
           /* must be either 4 or 5 --                       */
           /* this is a (deprecated) implied `seac' operator */
@@ -1760,6 +1790,9 @@
     /* check whether last error seen is also the first one */
     cf2_setError( error, lastError );
 
+    if ( *error )
+      FT_TRACE4(( "charstring error %d\n", *error ));
+
     /* free resources from objects we've used */
     cf2_glyphpath_finalize( &glyphPath );
     cf2_arrstack_finalize( &vStemHintArray );
diff --git a/src/cff/cffdrivr.c b/src/cff/cffdrivr.c
index 8be7eaf..c6d228f 100644
--- a/src/cff/cffdrivr.c
+++ b/src/cff/cffdrivr.c
@@ -295,6 +295,35 @@
     FT_Error    error;
 
 
+    /* CFF2 table does not have glyph names; */
+    /* we need to use `post' table method    */
+    if ( font->version_major == 2 )
+    {
+      FT_Library            library     = FT_FACE_LIBRARY( face );
+      FT_Module             sfnt_module = FT_Get_Module( library, "sfnt" );
+      FT_Service_GlyphDict  service     =
+        (FT_Service_GlyphDict)ft_module_get_service(
+                                 sfnt_module,
+                                 FT_SERVICE_ID_GLYPH_DICT,
+                                 0 );
+
+
+      if ( service && service->get_name )
+        return service->get_name( FT_FACE( face ),
+                                  glyph_index,
+                                  buffer,
+                                  buffer_max );
+      else
+      {
+        FT_ERROR(( "cff_get_glyph_name:"
+                   " cannot get glyph name from a CFF2 font\n"
+                   "                   "
+                   " without the `PSNames' module\n" ));
+        error = FT_THROW( Missing_Module );
+        goto Exit;
+      }
+    }
+
     if ( !font->psnames )
     {
       FT_ERROR(( "cff_get_glyph_name:"
@@ -336,6 +365,31 @@
     cff     = (CFF_FontRec *)face->extra.data;
     charset = &cff->charset;
 
+    /* CFF2 table does not have glyph names; */
+    /* we need to use `post' table method    */
+    if ( cff->version_major == 2 )
+    {
+      FT_Library            library     = FT_FACE_LIBRARY( face );
+      FT_Module             sfnt_module = FT_Get_Module( library, "sfnt" );
+      FT_Service_GlyphDict  service     =
+        (FT_Service_GlyphDict)ft_module_get_service(
+                                 sfnt_module,
+                                 FT_SERVICE_ID_GLYPH_DICT,
+                                 0 );
+
+
+      if ( service && service->name_index )
+        return service->name_index( FT_FACE( face ), glyph_name );
+      else
+      {
+        FT_ERROR(( "cff_get_name_index:"
+                   " cannot get glyph index from a CFF2 font\n"
+                   "                   "
+                   " without the `PSNames' module\n" ));
+        return 0;
+      }
+    }
+
     FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
     if ( !psnames )
       return 0;
diff --git a/src/cff/cffload.c b/src/cff/cffload.c
index 968a6f8..e61dfc2 100644
--- a/src/cff/cffload.c
+++ b/src/cff/cffload.c
@@ -29,6 +29,9 @@
 #include "cfferrs.h"
 
 
+#define FT_FIXED_ONE  ( (FT_Fixed)0x10000 )
+
+
 #if 1
 
   static const FT_UShort  cff_isoadobe_charset[229] =
@@ -225,19 +228,33 @@
   static FT_Error
   cff_index_init( CFF_Index  idx,
                   FT_Stream  stream,
-                  FT_Bool    load )
+                  FT_Bool    load,
+                  FT_Bool    cff2 )
   {
     FT_Error   error;
     FT_Memory  memory = stream->memory;
-    FT_UShort  count;
+    FT_UInt    count;
 
 
     FT_ZERO( idx );
 
     idx->stream = stream;
     idx->start  = FT_STREAM_POS();
-    if ( !FT_READ_USHORT( count ) &&
-         count > 0                )
+
+    if ( cff2 )
+    {
+      if ( FT_READ_ULONG( count ) )
+        goto Exit;
+      idx->hdr_size = 5;
+    }
+    else
+    {
+      if ( FT_READ_USHORT( count ) )
+        goto Exit;
+      idx->hdr_size = 3;
+    }
+
+    if ( count > 0 )
     {
       FT_Byte   offsize;
       FT_ULong  size;
@@ -258,7 +275,7 @@
       idx->off_size = offsize;
       size          = (FT_ULong)( count + 1 ) * offsize;
 
-      idx->data_offset = idx->start + 3 + size;
+      idx->data_offset = idx->start + idx->hdr_size + size;
 
       if ( FT_STREAM_SKIP( size - offsize ) )
         goto Exit;
@@ -335,7 +352,7 @@
       data_size = (FT_ULong)( idx->count + 1 ) * offsize;
 
       if ( FT_NEW_ARRAY( idx->offsets, idx->count + 1 ) ||
-           FT_STREAM_SEEK( idx->start + 3 )             ||
+           FT_STREAM_SEEK( idx->start + idx->hdr_size ) ||
            FT_FRAME_ENTER( data_size )                  )
         goto Exit;
 
@@ -493,7 +510,7 @@
         FT_ULong  pos = element * idx->off_size;
 
 
-        if ( FT_STREAM_SEEK( idx->start + 3 + pos ) )
+        if ( FT_STREAM_SEEK( idx->start + idx->hdr_size + pos ) )
           goto Exit;
 
         off1 = cff_index_read_offset( idx, &error );
@@ -589,13 +606,18 @@
                       FT_UInt   element )
   {
     CFF_Index   idx = &font->name_index;
-    FT_Memory   memory = idx->stream->memory;
+    FT_Memory   memory;
     FT_Byte*    bytes;
     FT_ULong    byte_len;
     FT_Error    error;
     FT_String*  name = 0;
 
 
+    if ( !idx->stream )  /* CFF2 does not include a name index */
+      goto Exit;
+
+    memory = idx->stream->memory;
+
     error = cff_index_access_element( idx, element, &bytes, &byte_len );
     if ( error )
       goto Exit;
@@ -724,6 +746,10 @@
   {
     FT_Byte  fd = 0;
 
+    /* if there is no FDSelect, return zero               */
+    /* Note: CFF2 with just one Font Dict has no FDSelect */
+    if ( fdselect->data == NULL )
+      goto Exit;
 
     switch ( fdselect->format )
     {
@@ -777,6 +803,7 @@
       ;
     }
 
+  Exit:
     return fd;
   }
 
@@ -1356,10 +1383,13 @@
     priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
     priv->blue_scale       = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
 
-    stackSize = CFF_MAX_STACK_DEPTH + 1;
+    priv->subfont = subfont;
+
+    stackSize = font->cff2 ? font->top_font.font_dict.maxstack
+                           : CFF_MAX_STACK_DEPTH + 1;
 
     if ( cff_parser_init( &parser,
-                          CFF_CODE_PRIVATE,
+                          font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE,
                           priv,
                           font->library,
                           stackSize,
@@ -1393,12 +1423,19 @@
   }
 
 
+  /* There are 3 ways to call this function, distinguished by code.  */
+  /*                                                                 */
+  /* . CFF_CODE_TOPDICT for either a CFF Top DICT or a CFF Font DICT */
+  /* . CFF2_CODE_TOPDICT for CFF2 Top DICT                           */
+  /* . CFF2_CODE_FONTDICT for CFF2 Font DICT                         */
+
   static FT_Error
   cff_subfont_load( CFF_SubFont  subfont,
                     CFF_Index    idx,
                     FT_UInt      font_index,
                     FT_Stream    stream,
                     FT_ULong     base_offset,
+                    FT_UInt      code,
                     CFF_Font     font )
   {
     FT_Error         error;
@@ -1408,11 +1445,16 @@
     CFF_FontRecDict  top  = &subfont->font_dict;
     CFF_Private      priv = &subfont->private_dict;
 
-    FT_UInt  stackSize = CFF_MAX_STACK_DEPTH;
+    FT_Bool  cff2      = ( code == CFF2_CODE_TOPDICT  ||
+                           code == CFF2_CODE_FONTDICT );
+    FT_UInt  stackSize = cff2 ? CFF2_DEFAULT_STACK
+                              : CFF_MAX_STACK_DEPTH;
 
 
+    /* Note: We use default stack size for CFF2 Font DICT because        */
+    /*       Top and Font DICTs are not allowed to have blend operators. */
     if ( cff_parser_init( &parser,
-                          CFF_CODE_TOPDICT,
+                          code,
                           &subfont->font_dict,
                           font->library,
                           stackSize,
@@ -1444,14 +1486,35 @@
     top->cid_ordering        = 0xFFFFU;
     top->cid_font_name       = 0xFFFFU;
 
-    error = cff_index_access_element( idx, font_index, &dict, &dict_len );
+    /* set default stack size */
+    top->maxstack            = cff2 ? CFF2_DEFAULT_STACK : 48;
+
+    if ( idx->count )   /* count is nonzero for a real index */
+      error = cff_index_access_element( idx, font_index, &dict, &dict_len );
+    else
+    {
+      /* CFF2 has a fake top dict index;     */
+      /* simulate `cff_index_access_element' */
+
+      /* Note: macros implicitly use `stream' and set `error' */
+      if ( FT_STREAM_SEEK( idx->data_offset )       ||
+           FT_FRAME_EXTRACT( idx->data_size, dict ) )
+        goto Exit;
+
+      dict_len = idx->data_size;
+    }
+
     if ( !error )
     {
       FT_TRACE4(( " top dictionary:\n" ));
       error = cff_parser_run( &parser, dict, dict + dict_len );
     }
 
-    cff_index_forget_element( idx, &dict );
+    /* clean up regardless of error */
+    if ( idx->count )
+      cff_index_forget_element( idx, &dict );
+    else
+      FT_FRAME_RELEASE( dict );
 
     if ( error )
       goto Exit;
@@ -1460,7 +1523,11 @@
     if ( top->cid_registry != 0xFFFFU )
       goto Exit;
 
-    /* parse the private dictionary, if any */
+    /* Parse the private dictionary, if any.                   */
+    /*                                                         */
+    /* CFF2 does not have a private dictionary in the Top DICT */
+    /* but may have one in a Font DICT.  We need to parse      */
+    /* the latter here in order to load any local subrs.       */
     error = cff_load_private_dict( font, subfont );
     if ( error )
       goto Exit;
@@ -1472,7 +1539,7 @@
                            priv->local_subrs_offset ) )
         goto Exit;
 
-      error = cff_index_init( &subfont->local_subrs_index, stream, 1 );
+      error = cff_index_init( &subfont->local_subrs_index, stream, 1, cff2 );
       if ( error )
         goto Exit;
 
@@ -1506,18 +1573,18 @@
                  FT_Stream  stream,
                  FT_Int     face_index,
                  CFF_Font   font,
-                 FT_Bool    pure_cff )
+                 FT_Bool    pure_cff,
+                 FT_Bool    cff2 )
   {
     static const FT_Frame_Field  cff_header_fields[] =
     {
 #undef  FT_STRUCTURE
 #define FT_STRUCTURE  CFF_FontRec
 
-      FT_FRAME_START( 4 ),
+      FT_FRAME_START( 3 ),
         FT_FRAME_BYTE( version_major ),
         FT_FRAME_BYTE( version_minor ),
         FT_FRAME_BYTE( header_size ),
-        FT_FRAME_BYTE( absolute_offsize ),
       FT_FRAME_END
     };
 
@@ -1538,40 +1605,80 @@
     font->library     = library;
     font->stream      = stream;
     font->memory      = memory;
+    font->cff2        = cff2;
     font->base_offset = base_offset;
 
     /* read CFF font header */
     if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) )
       goto Exit;
 
-    /* check format */
-    if ( font->version_major   != 1 ||
-         font->header_size      < 4 ||
-         font->absolute_offsize > 4 )
+    if ( cff2 )
     {
-      FT_TRACE2(( "  not a CFF font header\n" ));
-      error = FT_THROW( Unknown_File_Format );
-      goto Exit;
+      if ( font->version_major != 2 ||
+           font->header_size < 5    )
+      {
+        FT_TRACE2(( "  not a CFF2 font header\n" ));
+        error = FT_THROW( Unknown_File_Format );
+        goto Exit;
+      }
+
+      if ( FT_READ_USHORT( font->top_dict_length ) )
+        goto Exit;
+    }
+    else
+    {
+      if ( font->version_major != 1 ||
+           font->header_size < 4    )
+      {
+        FT_TRACE2(( "  not a CFF font header\n" ));
+        error = FT_THROW( Unknown_File_Format );
+        goto Exit;
+      }
     }
 
     /* skip the rest of the header */
-    if ( FT_STREAM_SKIP( font->header_size - 4 ) )
+    if ( FT_STREAM_SEEK( base_offset + font->header_size ) )
       goto Exit;
 
-    /* read the name, top dict, string and global subrs index */
-    if ( FT_SET_ERROR( cff_index_init( &font->name_index,
-                                       stream, 0 ) )                       ||
-         FT_SET_ERROR( cff_index_init( &font->font_dict_index,
-                                       stream, 0 ) )                       ||
-         FT_SET_ERROR( cff_index_init( &string_index,
-                                       stream, 1 ) )                       ||
-         FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
-                                       stream, 1 ) )                       ||
-         FT_SET_ERROR( cff_index_get_pointers( &string_index,
-                                               &font->strings,
-                                               &font->string_pool,
-                                               &font->string_pool_size ) ) )
-      goto Exit;
+    if ( cff2 )
+    {
+      /* For CFF2, the top dict data immediately follow the header    */
+      /* and the length is stored in the header `offSize' field;      */
+      /* there is no index for it.                                    */
+      /*                                                              */
+      /* Use the `font_dict_index' to save the current position       */
+      /* and length of data, but leave count at zero as an indicator. */
+      FT_ZERO( &font->font_dict_index );
+
+      font->font_dict_index.data_offset = FT_STREAM_POS();
+      font->font_dict_index.data_size   = font->top_dict_length;
+
+      /* skip the top dict data for now, we will parse it later */
+      if ( FT_STREAM_SKIP( font->top_dict_length ) )
+        goto Exit;
+
+      /* next, read the global subrs index */
+      if ( FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
+                                         stream, 1, cff2 ) ) )
+        goto Exit;
+    }
+    else
+    {
+      /* for CFF, read the name, top dict, string and global subrs index */
+      if ( FT_SET_ERROR( cff_index_init( &font->name_index,
+                                         stream, 0, cff2 ) )                 ||
+           FT_SET_ERROR( cff_index_init( &font->font_dict_index,
+                                         stream, 0, cff2 ) )                 ||
+           FT_SET_ERROR( cff_index_init( &string_index,
+                                         stream, 1, cff2 ) )                 ||
+           FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
+                                         stream, 1, cff2 ) )                 ||
+           FT_SET_ERROR( cff_index_get_pointers( &string_index,
+                                                 &font->strings,
+                                                 &font->string_pool,
+                                                 &font->string_pool_size ) ) )
+        goto Exit;
+    }
 
     font->num_strings = string_index.count;
 
@@ -1617,6 +1724,7 @@
                               subfont_index,
                               stream,
                               base_offset,
+                              cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT,
                               font );
     if ( error )
       goto Exit;
@@ -1624,12 +1732,13 @@
     if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) )
       goto Exit;
 
-    error = cff_index_init( &font->charstrings_index, stream, 0 );
+    error = cff_index_init( &font->charstrings_index, stream, 0, cff2 );
     if ( error )
       goto Exit;
 
-    /* now, check for a CID font */
-    if ( dict->cid_registry != 0xFFFFU )
+    /* now, check for a CID or CFF2 font */
+    if ( dict->cid_registry != 0xFFFFU ||
+         cff2                          )
     {
       CFF_IndexRec  fd_index;
       CFF_SubFont   sub = NULL;
@@ -1641,10 +1750,12 @@
       if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) )
         goto Exit;
 
-      error = cff_index_init( &fd_index, stream, 0 );
+      error = cff_index_init( &fd_index, stream, 0, cff2 );
       if ( error )
         goto Exit;
 
+      /* Font Dicts are not limited to 256 for CFF2. */
+      /* TODO: support this for CFF2                 */
       if ( fd_index.count > CFF_MAX_CID_FONTS )
       {
         FT_TRACE0(( "cff_font_load: FD array too large in CID font\n" ));
@@ -1670,16 +1781,20 @@
                                   idx,
                                   stream,
                                   base_offset,
+                                  cff2 ? CFF2_CODE_FONTDICT
+                                       : CFF_CODE_TOPDICT,
                                   font );
         if ( error )
           goto Fail_CID;
       }
 
-      /* now load the FD Select array */
-      error = CFF_Load_FD_Select( &font->fd_select,
-                                  font->charstrings_index.count,
-                                  stream,
-                                  base_offset + dict->cid_fd_select_offset );
+      /* now load the FD Select array;               */
+      /* CFF2 omits FDSelect if there is only one FD */
+      if ( !cff2 || fd_index.count > 1 )
+        error = CFF_Load_FD_Select( &font->fd_select,
+                                    font->charstrings_index.count,
+                                    stream,
+                                    base_offset + dict->cid_fd_select_offset );
 
     Fail_CID:
       cff_index_done( &fd_index );
@@ -1707,7 +1822,7 @@
       goto Exit;
 
     /* read the Charset and Encoding tables if available */
-    if ( font->num_glyphs > 0 )
+    if ( !cff2 && font->num_glyphs > 0 )
     {
       FT_Bool  invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff );
 
@@ -1755,7 +1870,7 @@
     cff_index_done( &font->charstrings_index );
 
     /* release font dictionaries, but only if working with */
-    /* a CID keyed CFF font                                */
+    /* a CID keyed CFF font or a CFF2 font                 */
     if ( font->num_subfonts > 0 )
     {
       for ( idx = 0; idx < font->num_subfonts; idx++ )
diff --git a/src/cff/cffload.h b/src/cff/cffload.h
index ed3af7a..e087fcd 100644
--- a/src/cff/cffload.h
+++ b/src/cff/cffload.h
@@ -60,11 +60,12 @@ FT_BEGIN_HEADER
 
 
   FT_LOCAL( FT_Error )
-  cff_font_load( FT_Library library,
-                 FT_Stream  stream,
-                 FT_Int     face_index,
-                 CFF_Font   font,
-                 FT_Bool    pure_cff );
+  cff_font_load( FT_Library  library,
+                 FT_Stream   stream,
+                 FT_Int      face_index,
+                 CFF_Font    font,
+                 FT_Bool     pure_cff,
+                 FT_Bool     cff2 );
 
   FT_LOCAL( void )
   cff_font_done( CFF_Font  font );
diff --git a/src/cff/cffobjs.c b/src/cff/cffobjs.c
index 126bbee..7302e03 100644
--- a/src/cff/cffobjs.c
+++ b/src/cff/cffobjs.c
@@ -491,6 +491,7 @@
     FT_Service_PsCMaps  psnames;
     PSHinter_Service    pshinter;
     FT_Bool             pure_cff    = 1;
+    FT_Bool             cff2        = 0;
     FT_Bool             sfnt_format = 0;
     FT_Library          library     = cffface->driver->root.library;
 
@@ -553,8 +554,18 @@
           goto Exit;
       }
 
-      /* now load the CFF part of the file */
-      error = face->goto_table( face, TTAG_CFF, stream, 0 );
+      /* now load the CFF part of the file; */
+      /* give priority to CFF2              */
+      error = face->goto_table( face, TTAG_CFF2, stream, 0 );
+      if ( !error )
+      {
+        cff2         = 1;
+        face->isCFF2 = cff2;
+      }
+
+      if ( FT_ERR_EQ( error, Table_Missing ) )
+        error = face->goto_table( face, TTAG_CFF, stream, 0 );
+
       if ( error )
         goto Exit;
     }
@@ -579,7 +590,12 @@
         goto Exit;
 
       face->extra.data = cff;
-      error = cff_font_load( library, stream, face_index, cff, pure_cff );
+      error = cff_font_load( library,
+                             stream,
+                             face_index,
+                             cff,
+                             pure_cff,
+                             cff2 );
       if ( error )
         goto Exit;
 
diff --git a/src/cff/cffparse.c b/src/cff/cffparse.c
index 9f1cc63..4a81230 100644
--- a/src/cff/cffparse.c
+++ b/src/cff/cffparse.c
@@ -823,6 +823,35 @@
   }
 
 
+  /* maxstack operator increases parser and operand stacks for CFF2 */
+  static FT_Error
+  cff_parse_maxstack( CFF_Parser  parser )
+  {
+    /* maxstack operator can only be used in a Top DICT */
+    CFF_FontRecDict  dict  = (CFF_FontRecDict)parser->object;
+    FT_Byte**        data  = parser->stack;
+    FT_Error         error = FT_Err_Ok;
+
+
+    if ( !dict )
+    {
+      error = FT_THROW( Invalid_File_Format );
+      goto Exit;
+    }
+
+    dict->maxstack = (FT_UInt)cff_parse_num( parser, data++ );
+    if ( dict->maxstack > CFF2_MAX_STACK )
+      dict->maxstack = CFF2_MAX_STACK;
+    if ( dict->maxstack < CFF2_DEFAULT_STACK )
+      dict->maxstack = CFF2_DEFAULT_STACK;
+
+    FT_TRACE4(( " %d\n", dict->maxstack ));
+
+  Exit:
+    return error;
+  }
+
+
 #define CFF_FIELD_NUM( code, name, id )             \
           CFF_FIELD( code, name, id, cff_kind_num )
 #define CFF_FIELD_FIXED( code, name, id )             \
@@ -834,9 +863,6 @@
 #define CFF_FIELD_BOOL( code, name, id )             \
           CFF_FIELD( code, name, id, cff_kind_bool )
 
-#define CFFCODE_TOPDICT  0x1000
-#define CFFCODE_PRIVATE  0x2000
-
 
 #ifndef FT_CONFIG_OPTION_PIC
 
diff --git a/src/cff/cffparse.h b/src/cff/cffparse.h
index 777446e..939e551 100644
--- a/src/cff/cffparse.h
+++ b/src/cff/cffparse.h
@@ -28,10 +28,17 @@
 FT_BEGIN_HEADER
 
 
+  /* CFF uses constant parser stack size; */
+  /* CFF2 can increase from default 193   */
 #define CFF_MAX_STACK_DEPTH  96
-
-#define CFF_CODE_TOPDICT  0x1000
-#define CFF_CODE_PRIVATE  0x2000
+#define CFF2_MAX_STACK      513
+#define CFF2_DEFAULT_STACK  193
+
+#define CFF_CODE_TOPDICT    0x1000
+#define CFF_CODE_PRIVATE    0x2000
+#define CFF2_CODE_TOPDICT   0x3000
+#define CFF2_CODE_FONTDICT  0x4000
+#define CFF2_CODE_PRIVATE   0x5000
 
 
   typedef struct  CFF_ParserRec_
diff --git a/src/cff/cfftoken.h b/src/cff/cfftoken.h
index 22637c7..6e671b9 100644
--- a/src/cff/cfftoken.h
+++ b/src/cff/cfftoken.h
@@ -20,7 +20,7 @@
 #define FT_STRUCTURE  CFF_FontRecDictRec
 
 #undef  CFFCODE
-#define CFFCODE       CFFCODE_TOPDICT
+#define CFFCODE       CFF_CODE_TOPDICT
 
   CFF_FIELD_STRING  ( 0,     version,             "Version" )
   CFF_FIELD_STRING  ( 1,     notice,              "Notice" )
@@ -78,7 +78,7 @@
 #undef  FT_STRUCTURE
 #define FT_STRUCTURE  CFF_PrivateRec
 #undef  CFFCODE
-#define CFFCODE       CFFCODE_PRIVATE
+#define CFFCODE       CFF_CODE_PRIVATE
 
   CFF_FIELD_DELTA     ( 6,     blue_values, 14,        "BlueValues" )
   CFF_FIELD_DELTA     ( 7,     other_blues, 10,        "OtherBlues" )
@@ -102,4 +102,46 @@
   CFF_FIELD_NUM       ( 21,    nominal_width,          "nominalWidthX" )
 
 
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  CFF_FontRecDictRec
+#undef  CFFCODE
+#define CFFCODE       CFF2_CODE_TOPDICT
+
+  CFF_FIELD_CALLBACK( 0x107, font_matrix,          "FontMatrix" )
+  CFF_FIELD_NUM     ( 17,    charstrings_offset,   "CharStrings" )
+  CFF_FIELD_NUM     ( 0x124, cid_fd_array_offset,  "FDArray" )
+  CFF_FIELD_NUM     ( 0x125, cid_fd_select_offset, "FDSelect" )
+  CFF_FIELD_CALLBACK( 25,    maxstack,             "maxstack" )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  CFF_FontRecDictRec
+#undef  CFFCODE
+#define CFFCODE       CFF2_CODE_FONTDICT
+
+  CFF_FIELD_CALLBACK( 18,    private_dict, "Private" )
+  CFF_FIELD_CALLBACK( 0x107, font_matrix,  "FontMatrix" )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  CFF_PrivateRec
+#undef  CFFCODE
+#define CFFCODE       CFF2_CODE_PRIVATE
+
+  CFF_FIELD_DELTA     ( 6,     blue_values, 14,        "BlueValues" )
+  CFF_FIELD_DELTA     ( 7,     other_blues, 10,        "OtherBlues" )
+  CFF_FIELD_DELTA     ( 8,     family_blues, 14,       "FamilyBlues" )
+  CFF_FIELD_DELTA     ( 9,     family_other_blues, 10, "FamilyOtherBlues" )
+  CFF_FIELD_FIXED_1000( 0x109, blue_scale,             "BlueScale" )
+  CFF_FIELD_NUM       ( 0x10A, blue_shift,             "BlueShift" )
+  CFF_FIELD_NUM       ( 0x10B, blue_fuzz,              "BlueFuzz" )
+  CFF_FIELD_NUM       ( 10,    standard_width,         "StdHW" )
+  CFF_FIELD_NUM       ( 11,    standard_height,        "StdVW" )
+  CFF_FIELD_DELTA     ( 0x10C, snap_widths, 13,        "StemSnapH" )
+  CFF_FIELD_DELTA     ( 0x10D, snap_heights, 13,       "StemSnapV" )
+  CFF_FIELD_NUM       ( 0x111, language_group,         "LanguageGroup" )
+  CFF_FIELD_FIXED     ( 0x112, expansion_factor,       "ExpansionFactor" )
+  CFF_FIELD_NUM       ( 19,    local_subrs_offset,     "Subrs" )
+
+
 /* END */
diff --git a/src/cff/cfftypes.h b/src/cff/cfftypes.h
index a679c6a..97534af 100644
--- a/src/cff/cfftypes.h
+++ b/src/cff/cfftypes.h
@@ -64,6 +64,7 @@ FT_BEGIN_HEADER
   {
     FT_Stream  stream;
     FT_ULong   start;
+    FT_UInt    hdr_size;
     FT_UInt    count;
     FT_Byte    off_size;
     FT_ULong   data_offset;
@@ -151,9 +152,16 @@ FT_BEGIN_HEADER
     FT_UShort  num_designs;
     FT_UShort  num_axes;
 
+    /* fields for CFF2 */
+    FT_UInt    maxstack;
+
   } CFF_FontRecDictRec, *CFF_FontRecDict;
 
 
+  /* forward reference */
+  typedef struct CFF_SubFontRec_*  CFF_SubFont;
+
+
   typedef struct  CFF_PrivateRec_
   {
     FT_Byte   num_blue_values;
@@ -186,6 +194,9 @@ FT_BEGIN_HEADER
     FT_Pos    default_width;
     FT_Pos    nominal_width;
 
+    /* fields for CFF2 */
+    CFF_SubFont  subfont;
+
   } CFF_PrivateRec, *CFF_Private;
 
 
@@ -213,10 +224,11 @@ FT_BEGIN_HEADER
     CFF_FontRecDictRec  font_dict;
     CFF_PrivateRec      private_dict;
 
-    CFF_IndexRec        local_subrs_index;
-    FT_Byte**           local_subrs; /* array of pointers into Local Subrs 
INDEX data */
+    CFF_IndexRec  local_subrs_index;
+    FT_Byte**     local_subrs; /* array of pointers           */
+                               /* into Local Subrs INDEX data */
 
-  } CFF_SubFontRec, *CFF_SubFont;
+  } CFF_SubFontRec;
 
 
 #define CFF_MAX_CID_FONTS  256
@@ -226,7 +238,7 @@ FT_BEGIN_HEADER
   {
     FT_Library       library;
     FT_Stream        stream;
-    FT_Memory        memory;
+    FT_Memory        memory;        /* TODO: take this from stream->memory? */
     FT_ULong         base_offset;   /* offset to start of CFF */
     FT_UInt          num_faces;
     FT_UInt          num_glyphs;
@@ -234,8 +246,10 @@ FT_BEGIN_HEADER
     FT_Byte          version_major;
     FT_Byte          version_minor;
     FT_Byte          header_size;
-    FT_Byte          absolute_offsize;
 
+    FT_UInt          top_dict_length;   /* cff2 only */
+
+    FT_Bool          cff2;
 
     CFF_IndexRec     name_index;
     CFF_IndexRec     top_dict_index;
diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c
index b5eb18b..60bfda9 100644
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -1106,12 +1106,14 @@
 
     /* do we have outlines in there? */
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
-    has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
-                           tt_face_lookup_table( face, TTAG_glyf )    != 0 ||
-                           tt_face_lookup_table( face, TTAG_CFF )     != 0 );
+    has_outline = FT_BOOL( face->root.internal->incremental_interface      ||
+                           tt_face_lookup_table( face, TTAG_glyf ) != NULL ||
+                           tt_face_lookup_table( face, TTAG_CFF ) != NULL  ||
+                           tt_face_lookup_table( face, TTAG_CFF2 ) != NULL );
 #else
-    has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
-                           tt_face_lookup_table( face, TTAG_CFF )  != 0 );
+    has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != NULL ||
+                           tt_face_lookup_table( face, TTAG_CFF ) != NULL  ||
+                           tt_face_lookup_table( face, TTAG_CFF2 ) != NULL );
 #endif
 
     is_apple_sbit = 0;
@@ -1354,6 +1356,9 @@
            tt_face_lookup_table( face, TTAG_fvar ) != 0 &&
            tt_face_lookup_table( face, TTAG_gvar ) != 0 )
         flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
+      if ( tt_face_lookup_table( face, TTAG_CFF2 ) != 0 &&
+           tt_face_lookup_table( face, TTAG_fvar ) != 0 )
+        flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
 #endif
 
       root->face_flags = flags;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]