2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19323...
[blender.git] / source / blender / blenlib / intern / freetypefont.c
index bc06de9db3c4871025284c06332510092b9ada0b..4b7b5914b60f6dd2fd944ebcf8e3f75c2ef6fd43 100644 (file)
@@ -1,15 +1,12 @@
 /**
  * $Id$
  *
- * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version. The Blender
- * Foundation also sells licenses for use in proprietary software under
- * the Blender License.  See http://www.blender.org/BL/ for information
- * about this.
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * The Original Code is written by Rob Haarsma (phase)
  * All rights reserved.
  *
- *
  * Contributor(s): none yet.
  *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * This code parses the Freetype font outline data to chains of Blender's beziertriples.
+ * Additional information can be found at the bottom of this file.
+ *
+ * Code that uses exotic character maps is present but commented out.
  */
 
 #ifdef WITH_FREETYPE2
@@ -38,6 +39,8 @@
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
+#include FT_BBOX_H
+#include FT_SIZES_H
 #include <freetype/ttnameid.h>
 
 #include "MEM_guardedalloc.h"
 #include "BLI_blenlib.h"
 #include "BLI_arithb.h"  
 
-#include "BIF_toolbox.h"
+//XXX #include "BIF_toolbox.h"
 
+#include "BKE_global.h"
+#include "BKE_font.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_vfont_types.h"
 #include "DNA_packedFile_types.h"
 #include "DNA_curve_types.h"
 
 #define myMIN_ASCII    32
-#define myMAX_ASCII    126
-
-// should come from arithb.c
-#define MIN2(x,y)               ( (x)<(y) ? (x) : (y) )
-#define MAX2(x,y)               ( (x)>(y) ? (x) : (y) )
+#define myMAX_ASCII    255
 
 /* local variables */
 static FT_Library      library;
 static FT_Error                err;
 
-#if 0
-// Freetype2 Outline struct
-
-typedef struct  FT_Outline_
-  {
-    short       n_contours;      /* number of contours in glyph        */
-    short       n_points;        /* number of points in the glyph      */
-
-    FT_Vector*  points;          /* the outline's points               */
-    char*       tags;            /* the points flags                   */
-    short*      contours;        /* the contour end points             */
-
-    int         flags;           /* outline masks                      */
-
-  } FT_Outline;
-#endif
-
-/***//*
-from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
-
-Vectorial representation of Freetype glyphs
-
-The source format of outlines is a collection of closed paths called "contours". Each contour is
-made of a series of line segments and bezier arcs. Depending on the file format, these can be
-second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
-they come from the TrueType format. The latter are called cubic arcs and mostly come from the
-Type1 format.
-
-Each arc is described through a series of start, end and control points. Each point of the outline
-has a specific tag which indicates wether it is used to describe a line segment or an arc.
-
-
-The following rules are applied to decompose the contour's points into segments and arcs :
-
-# two successive "on" points indicate a line segment joining them.
-
-# one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
-  the control point, and the "on" ones the start and end points.
-
-# Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
-  be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
-  "off" point between two "on" points is forbidden, for example).
-
-# finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
-  conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
-  greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
-  outlines are described in the TrueType specification.
-
-Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
-font driver produces such outlines.
-
-                                  *            # on      
-                                               * off
-                               __---__
-  #-__                      _--       -_
-      --__                _-            -
-          --__           #               \
-              --__                        #
-                  -#
-                           Two "on" points
-   Two "on" points       and one "conic" point
-                            between them
-
-
-
-                *
-  #            __      Two "on" points with two "conic"
-   \          -  -     points between them. The point
-    \        /    \    marked '0' is the middle of the
-     -      0      \   "off" points, and is a 'virtual'
-      -_  _-       #   "on" point where the curve passes.
-        --             It does not appear in the point
-                       list.
-        *
-
-
-
-
-        *                # on
-                   *     * off
-         __---__
-      _--       -_
-    _-            -
-   #               \
-                    #
-
-     Two "on" points
-   and two "cubic" point
-      between them
-
-
-Each glyph's original outline points are located on a grid of indivisible units. The points are stored
-in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
-range from -16384 to 16383.
-
-
-Convert conic to bezier arcs:
-Conic P0 P1 P2
-Bezier B0 B1 B2 B3
-B0=P0
-B1=(P0+2*P1)/3
-B2=(P2+2*P1)/3
-B3=P2
-
-*//****/
 
-static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
+void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
 {
        // Blender
-       VFontData *vfd;
        struct Nurb *nu;
+       struct VChar *che;
        struct BezTriple *bezt;
-
+       
        // Freetype2
-       FT_Face         face;
-       FT_GlyphSlot  glyph;
-       FT_UInt         glyph_index;
-       FT_Outline      ftoutline;
-/*
-    FT_CharMap  found = 0;
-       FT_CharMap  charmap;
-       FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
-       FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
-       int         n;
-*/
-
-       float scale= 1. / 1024.; //needs text_height from metrics to make a standard linedist
+       FT_GlyphSlot glyph;
+       FT_UInt glyph_index;
+       FT_Outline ftoutline;
+       float scale, height;
        float dx, dy;
-       int i, j, k, l, m; /* uhoh, kiddie C loops */
-       /* i = characters, j = curves/contours, k = points, l = curvepoint, m = first point on curve */
-
-       // test is used for BIF_printf
-       char test[2];
-
+       int j,k,l,m=0;
        
-       // load the freetype font
-       err = FT_New_Memory_Face( library,
-                                               pf->data,
-                                               pf->size,
-                                               0,
-                                               &face );
-
-       if(err) return NULL;
-/*
-    for ( n = 0; n < face->num_charmaps; n++ )
-    {
-      charmap = face->charmaps[n];
-      if ( charmap->platform_id == my_platform_id &&
-           charmap->encoding_id == my_encoding_id )
-      {
-        found = charmap;
-        break;
-      }
-    }
-
-    if ( !found ) { return NULL; }
-
-    // now, select the charmap for the face object
-    err = FT_Set_Charmap( face, found );
-    if ( err ) { return NULL; }
-*/
-
-       // allocate blender font
-       vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
-
-       // extract generic ascii character range (needs international support, dynamic loading of chars, etcetc)
-       for(i = myMIN_ASCII; i <= myMAX_ASCII; i++) {
-               int  *npoints;  //total points of each contour
-               int  *onpoints; //num points on curve
-
-               test[0] = i;
-               test[1] = '\0'; //to print character
-
-               glyph_index = FT_Get_Char_Index( face, i );
-               err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE);
-               glyph = face->glyph;
-               ftoutline = glyph->outline;
-
-               vfd->width[i] = glyph->advance.x* scale;
-//             BIF_printf("sx %d sy %d", glyph->advance.x, face->glyph->metrics->text_height);
-
+       // adjust font size
+       height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
+       if(height != 0.0)
+               scale = 1.0 / height;
+       else
+               scale = 1.0 / 1000.0;
+       
+       //      
+       // Generate the character 3D data
+       //
+       // Get the FT Glyph index and load the Glyph
+       glyph_index= FT_Get_Char_Index(face, charcode);
+       err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
+       
+       // If loading succeeded, convert the FT glyph to the internal format
+       if(!err)
+       {
+               int *npoints;
+               int *onpoints;
+               
+               // First we create entry for the new character to the character list
+               che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
+               BLI_addtail(&vfd->characters, che);
+               
+               // Take some data for modifying purposes
+               glyph= face->glyph;
+               ftoutline= glyph->outline;
+               
+               // Set the width and character code
+               che->index= charcode;
+               che->width= glyph->advance.x * scale;
+               
+               // Start converting the FT data
                npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
                onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
 
@@ -259,11 +131,8 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
                        l = 0;
                        for(k = 0; k < npoints[j]; k++) {
                                if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
-
-//                             if(i == 67) BIF_printf("%d->%s : |k %2d|l %2d|t %2d|", i, test, k, l, ftoutline.n_points);
-
-                               if(ftoutline.tags[l] == FT_Curve_Tag_On)
-                                       onpoints[j]++;
+                                       if(ftoutline.tags[l] == FT_Curve_Tag_On)
+                                               onpoints[j]++;
 
                                if(k < npoints[j] - 1 )
                                        if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
@@ -272,25 +141,27 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
                        }
                }
 
-               //final contour loop, bezier & conic styles merged
+               //contour loop, bezier & conic styles merged
                for(j = 0; j < ftoutline.n_contours; j++) {
                        // add new curve
                        nu  =  (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
                        bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
-                       BLI_addtail(&vfd->nurbsbase[i], nu);
+                       BLI_addtail(&che->nurbsbase, nu);
+
                        nu->type= CU_BEZIER+CU_2D;
                        nu->pntsu = onpoints[j];
                        nu->resolu= 8;
-                       nu->flagu= 1;
+                       nu->flagu= CU_CYCLIC;
                        nu->bezt = bezt;
 
                        //individual curve loop, start-end
                        for(k = 0; k < npoints[j]; k++) {
                                if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
                                if(k == 0) m = l;
-                               
+                                       
                                //virtual conic on-curve points
                                if(k < npoints[j] - 1 )
+                               {
                                        if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
                                                dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
                                                dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
@@ -300,16 +171,18 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
                                                bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
 
                                                //midpoint (virtual on-curve point)
-                                               bezt->vec[1][0] = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
-                                               bezt->vec[1][1] = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
+                                               bezt->vec[1][0] = dx;
+                                               bezt->vec[1][1] = dy;
 
                                                //right handle
                                                bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
                                                bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
 
                                                bezt->h1= bezt->h2= HD_ALIGN;
+                                               bezt->radius= 1.0f;
                                                bezt++;
                                        }
+                               }
 
                                //on-curve points
                                if(ftoutline.tags[l] == FT_Curve_Tag_On) {
@@ -365,7 +238,6 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
                                                }
                                        } else { //last point on curve
                                                if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
-//                                                     okee("hhuh");
                                                        bezt->vec[2][0] = ftoutline.points[m].x* scale;
                                                        bezt->vec[2][1] = ftoutline.points[m].y* scale;
                                                        bezt->h2= HD_FREE;
@@ -394,15 +266,143 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
                                        {
                                                bezt->h1= bezt->h2= HD_ALIGN;
                                        }
+                                       bezt->radius= 1.0f;
                                        bezt++;
                                }
                        }
                }
-
                if(npoints) MEM_freeN(npoints);
-               if(onpoints) MEM_freeN(onpoints);
+               if(onpoints) MEM_freeN(onpoints);       
        }
-       return vfd;
+}
+
+int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
+{
+       // Freetype2
+       FT_Face face;
+       struct TmpFont *tf;
+       
+       // Find the correct FreeType font
+       tf= vfont_find_tmpfont(vfont);
+       
+       // What, no font found. Something strange here
+       if(!tf) return FALSE;
+       
+       // Load the font to memory
+       if(tf->pf)
+       {
+               err= FT_New_Memory_Face( library,
+                       tf->pf->data,
+                       tf->pf->size,
+                       0,
+                       &face);                 
+       }
+       else
+               err= TRUE;
+               
+       // Read the char
+       freetypechar_to_vchar(face, charcode, vfont->data);
+       
+       // And everything went ok
+       return TRUE;
+}
+
+
+static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
+{
+       // Variables
+       FT_Face face;
+       FT_ULong charcode = 0, lcode;
+       FT_UInt glyph_index;
+       const char *fontname;
+       VFontData *vfd;
+
+/*
+       FT_CharMap  found = 0;
+       FT_CharMap  charmap;
+       FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
+       FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
+       int         n;
+*/
+
+       // load the freetype font
+       err = FT_New_Memory_Face( library,
+                                               pf->data,
+                                               pf->size,
+                                               0,
+                                               &face );
+
+       if(err) return NULL;
+/*
+       for ( n = 0; n < face->num_charmaps; n++ )
+       {
+               charmap = face->charmaps[n];
+               if ( charmap->platform_id == my_platform_id &&
+                       charmap->encoding_id == my_encoding_id )
+               {
+                       found = charmap;
+                       break;
+               }
+       }
+
+       if ( !found ) { return NULL; }
+
+       // now, select the charmap for the face object
+       err = FT_Set_Charmap( face, found );
+       if ( err ) { return NULL; }
+*/
+
+       // allocate blender font
+       vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
+
+       // get the name
+       fontname = FT_Get_Postscript_Name(face);
+       strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
+
+       // Extract the first 256 character from TTF
+       lcode= charcode= FT_Get_First_Char(face, &glyph_index);
+
+       // No charmap found from the ttf so we need to figure it out
+       if(glyph_index == 0)
+       {
+               FT_CharMap  found = 0;
+               FT_CharMap  charmap;
+               int n;
+
+               for ( n = 0; n < face->num_charmaps; n++ )
+               {
+                       charmap = face->charmaps[n];
+                       if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
+                       {
+                               found = charmap;
+                               break;
+                       }
+               }
+
+               err = FT_Set_Charmap( face, found );
+
+               if( err ) 
+                       return NULL;
+
+               lcode= charcode= FT_Get_First_Char(face, &glyph_index);
+       }
+
+       // Load characters
+       while(charcode < 256)
+       {
+               // Generate the font data
+               freetypechar_to_vchar(face, charcode, vfd);
+
+               // Next glyph
+               charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
+
+               // Check that we won't start infinite loop
+               if(charcode <= lcode)
+                       break;
+               lcode = charcode;
+       }
+
+       return vfd;     
 }
 
 
@@ -427,7 +427,7 @@ static int check_freetypefont(PackedFile * pf)
                                                        &face );
        if(err) {
                success = 0;
-           error("This is not a valid font");
+           //XXX error("This is not a valid font");
        }
        else {
 /*
@@ -449,14 +449,14 @@ static int check_freetypefont(PackedFile * pf)
                if ( err ) { return 0; }
 */
                glyph_index = FT_Get_Char_Index( face, 'A' );
-               err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP );
+               err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
                if(err) success = 0;
                else {
                        glyph = face->glyph;
                        if (glyph->format == ft_glyph_format_outline ) {
                                success = 1;
                        } else {
-                               error("Selected Font has no outline data");
+                               //XXX error("Selected Font has no outline data");
                                success = 0;
                        }
                }
@@ -474,7 +474,7 @@ VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
        //init Freetype 
        err = FT_Init_FreeType( &library);
        if(err) {
-           error("Failed loading Freetype font library");
+               //XXX error("Failed to load the Freetype font library");
                return 0;
        }
 
@@ -490,4 +490,137 @@ VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
        return vfd;
 }
 
-#endif // WITH_FREETYPE2
\ No newline at end of file
+int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
+{
+       int success = FALSE;
+
+       if(!vfont) return FALSE;
+
+       // Init Freetype
+       err = FT_Init_FreeType(&library);
+       if(err) {
+               //XXX error("Failed to load the Freetype font library");
+               return 0;
+       }
+
+       // Load the character
+       success = objchr_to_ftvfontdata(vfont, character);
+       if(success == FALSE) return FALSE;
+
+       // Free Freetype
+       FT_Done_FreeType(library);
+
+       // Ahh everything ok
+       return TRUE;
+}
+
+#endif // WITH_FREETYPE2
+
+
+
+#if 0
+
+// Freetype2 Outline struct
+
+typedef struct  FT_Outline_
+  {
+    short       n_contours;      /* number of contours in glyph        */
+    short       n_points;        /* number of points in the glyph      */
+
+    FT_Vector*  points;          /* the outline's points               */
+    char*       tags;            /* the points flags                   */
+    short*      contours;        /* the contour end points             */
+
+    int         flags;           /* outline masks                      */
+
+  } FT_Outline;
+
+#endif
+
+/***//*
+from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
+
+Vectorial representation of Freetype glyphs
+
+The source format of outlines is a collection of closed paths called "contours". Each contour is
+made of a series of line segments and bezier arcs. Depending on the file format, these can be
+second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
+they come from the TrueType format. The latter are called cubic arcs and mostly come from the
+Type1 format.
+
+Each arc is described through a series of start, end and control points. Each point of the outline
+has a specific tag which indicates wether it is used to describe a line segment or an arc.
+
+
+The following rules are applied to decompose the contour's points into segments and arcs :
+
+# two successive "on" points indicate a line segment joining them.
+
+# one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
+  the control point, and the "on" ones the start and end points.
+
+# Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
+  be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
+  "off" point between two "on" points is forbidden, for example).
+
+# finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
+  conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
+  greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
+  outlines are described in the TrueType specification.
+
+Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
+font driver produces such outlines.
+
+                                  *            # on      
+                                               * off
+                               __---__
+  #-__                      _--       -_
+      --__                _-            -
+          --__           #               \
+              --__                        #
+                  -#
+                           Two "on" points
+   Two "on" points       and one "conic" point
+                            between them
+
+
+
+                *
+  #            __      Two "on" points with two "conic"
+   \          -  -     points between them. The point
+    \        /    \    marked '0' is the middle of the
+     -      0      \   "off" points, and is a 'virtual'
+      -_  _-       #   "on" point where the curve passes.
+        --             It does not appear in the point
+                       list.
+        *
+
+
+
+
+        *                # on
+                   *     * off
+         __---__
+      _--       -_
+    _-            -
+   #               \
+                    #
+
+     Two "on" points
+   and two "cubic" point
+      between them
+
+
+Each glyph's original outline points are located on a grid of indivisible units. The points are stored
+in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
+range from -16384 to 16383.
+
+Convert conic to bezier arcs:
+Conic P0 P1 P2
+Bezier B0 B1 B2 B3
+B0=P0
+B1=(P0+2*P1)/3
+B2=(P2+2*P1)/3
+B3=P2
+
+*//****/