Blender  V2.59
freetypefont.c
Go to the documentation of this file.
00001 /*
00002  * $Id: freetypefont.c 35953 2011-04-02 02:08:33Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is written by Rob Haarsma (phase)
00021  * All rights reserved.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  *
00027  * This code parses the Freetype font outline data to chains of Blender's beziertriples.
00028  * Additional information can be found at the bottom of this file.
00029  *
00030  * Code that uses exotic character maps is present but commented out.
00031  */
00032 
00038 #ifdef WIN32
00039 #pragma warning (disable:4244)
00040 #endif
00041 
00042 #include <ft2build.h>
00043 #include FT_FREETYPE_H
00044 /* not needed yet */
00045 // #include FT_GLYPH_H
00046 // #include FT_BBOX_H
00047 // #include FT_SIZES_H
00048 // #include <freetype/ttnameid.h>
00049 
00050 #include "MEM_guardedalloc.h"
00051 
00052 #include "BLI_vfontdata.h"
00053 #include "BLI_blenlib.h"
00054 #include "BLI_math.h"
00055 #include "BLI_utildefines.h"
00056 
00057 //XXX #include "BIF_toolbox.h"
00058 
00059 #include "BKE_font.h"
00060 
00061 
00062 #include "DNA_vfont_types.h"
00063 #include "DNA_packedFile_types.h"
00064 #include "DNA_curve_types.h"
00065 
00066 #define myMIN_ASCII     32
00067 #define myMAX_ASCII     255
00068 
00069 /* local variables */
00070 static FT_Library       library;
00071 static FT_Error         err;
00072 
00073 
00074 static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
00075 {
00076         // Blender
00077         struct Nurb *nu;
00078         struct VChar *che;
00079         struct BezTriple *bezt;
00080         
00081         // Freetype2
00082         FT_GlyphSlot glyph;
00083         FT_UInt glyph_index;
00084         FT_Outline ftoutline;
00085         float scale, height;
00086         float dx, dy;
00087         int j,k,l,m=0;
00088         
00089         // adjust font size
00090         height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
00091         if(height != 0.0f)
00092                 scale = 1.0f / height;
00093         else
00094                 scale = 1.0f / 1000.0f;
00095         
00096         //      
00097         // Generate the character 3D data
00098         //
00099         // Get the FT Glyph index and load the Glyph
00100         glyph_index= FT_Get_Char_Index(face, charcode);
00101         err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
00102         
00103         // If loading succeeded, convert the FT glyph to the internal format
00104         if(!err)
00105         {
00106                 int *npoints;
00107                 int *onpoints;
00108                 
00109                 // First we create entry for the new character to the character list
00110                 che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
00111                 BLI_addtail(&vfd->characters, che);
00112                 
00113                 // Take some data for modifying purposes
00114                 glyph= face->glyph;
00115                 ftoutline= glyph->outline;
00116                 
00117                 // Set the width and character code
00118                 che->index= charcode;
00119                 che->width= glyph->advance.x * scale;
00120                 
00121                 // Start converting the FT data
00122                 npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
00123                 onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
00124 
00125                 // calculate total points of each contour
00126                 for(j = 0; j < ftoutline.n_contours; j++) {
00127                         if(j == 0)
00128                                 npoints[j] = ftoutline.contours[j] + 1;
00129                         else
00130                                 npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
00131                 }
00132 
00133                 // get number of on-curve points for beziertriples (including conic virtual on-points) 
00134                 for(j = 0; j < ftoutline.n_contours; j++) {
00135                         for(k = 0; k < npoints[j]; k++) {
00136                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
00137                                         if(ftoutline.tags[l] == FT_Curve_Tag_On)
00138                                                 onpoints[j]++;
00139 
00140                                 if(k < npoints[j] - 1 )
00141                                         if( ftoutline.tags[l]   == FT_Curve_Tag_Conic &&
00142                                                 ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
00143                                                 onpoints[j]++;
00144                         }
00145                 }
00146 
00147                 //contour loop, bezier & conic styles merged
00148                 for(j = 0; j < ftoutline.n_contours; j++) {
00149                         // add new curve
00150                         nu  =  (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
00151                         bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
00152                         BLI_addtail(&che->nurbsbase, nu);
00153 
00154                         nu->type= CU_BEZIER;
00155                         nu->pntsu = onpoints[j];
00156                         nu->resolu= 8;
00157                         nu->flag= CU_2D;
00158                         nu->flagu= CU_NURB_CYCLIC;
00159                         nu->bezt = bezt;
00160 
00161                         //individual curve loop, start-end
00162                         for(k = 0; k < npoints[j]; k++) {
00163                                 if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
00164                                 if(k == 0) m = l;
00165                                         
00166                                 //virtual conic on-curve points
00167                                 if(k < npoints[j] - 1 )
00168                                 {
00169                                         if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
00170                                                 dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0f;
00171                                                 dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0f;
00172 
00173                                                 //left handle
00174                                                 bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0f;
00175                                                 bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0f;
00176 
00177                                                 //midpoint (virtual on-curve point)
00178                                                 bezt->vec[1][0] = dx;
00179                                                 bezt->vec[1][1] = dy;
00180 
00181                                                 //right handle
00182                                                 bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0f;
00183                                                 bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0f;
00184 
00185                                                 bezt->h1= bezt->h2= HD_ALIGN;
00186                                                 bezt->radius= 1.0f;
00187                                                 bezt++;
00188                                         }
00189                                 }
00190 
00191                                 //on-curve points
00192                                 if(ftoutline.tags[l] == FT_Curve_Tag_On) {
00193                                         //left handle
00194                                         if(k > 0) {
00195                                                 if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
00196                                                         bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
00197                                                         bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
00198                                                         bezt->h1= HD_FREE;
00199                                                 } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
00200                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0f;
00201                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0f;
00202                                                         bezt->h1= HD_FREE;
00203                                                 } else {
00204                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0f;
00205                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0f;
00206                                                         bezt->h1= HD_VECT;
00207                                                 }
00208                                         } else { //first point on curve
00209                                                 if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
00210                                                         bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
00211                                                         bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
00212                                                         bezt->h1= HD_FREE;
00213                                                 } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
00214                                                         bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0f;
00215                                                         bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0f;
00216                                                         bezt->h1= HD_FREE;
00217                                                 } else {
00218                                                         bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0f;
00219                                                         bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0f;
00220                                                         bezt->h1= HD_VECT;
00221                                                 }
00222                                         }
00223 
00224                                         //midpoint (on-curve point)
00225                                         bezt->vec[1][0] = ftoutline.points[l].x* scale;
00226                                         bezt->vec[1][1] = ftoutline.points[l].y* scale;
00227 
00228                                         //right handle
00229                                         if(k < (npoints[j] - 1)) {
00230                                                 if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
00231                                                         bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
00232                                                         bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
00233                                                         bezt->h2= HD_FREE;
00234                                                 } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
00235                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0f;
00236                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0f;
00237                                                         bezt->h2= HD_FREE;
00238                                                 } else {
00239                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0f;
00240                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0f;
00241                                                         bezt->h2= HD_VECT;
00242                                                 }
00243                                         } else { //last point on curve
00244                                                 if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
00245                                                         bezt->vec[2][0] = ftoutline.points[m].x* scale;
00246                                                         bezt->vec[2][1] = ftoutline.points[m].y* scale;
00247                                                         bezt->h2= HD_FREE;
00248                                                 } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
00249                                                         bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0f;
00250                                                         bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0f;
00251                                                         bezt->h2= HD_FREE;
00252                                                 } else {
00253                                                         bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0f;
00254                                                         bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0f;
00255                                                         bezt->h2= HD_VECT;
00256                                                 }
00257                                         }
00258 
00259                                         // get the handles that are aligned, tricky...
00260                                         // dist_to_line_v2, check if the three beztriple points are on one line
00261                                         // len_squared_v2v2, see if there's a distance between the three points
00262                                         // len_squared_v2v2 again, to check the angle between the handles 
00263                                         // finally, check if one of them is a vector handle 
00264                                         if((dist_to_line_v2(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001f) &&
00265                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001f*0.0001f) &&
00266                                                 (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001f*0.0001f) &&
00267                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002f*0.0001f) &&
00268                                                 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > MAX2(len_squared_v2v2(bezt->vec[0], bezt->vec[1]), len_squared_v2v2(bezt->vec[1], bezt->vec[2]))) &&
00269                                                 bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
00270                                         {
00271                                                 bezt->h1= bezt->h2= HD_ALIGN;
00272                                         }
00273                                         bezt->radius= 1.0f;
00274                                         bezt++;
00275                                 }
00276                         }
00277                 }
00278                 if(npoints) MEM_freeN(npoints);
00279                 if(onpoints) MEM_freeN(onpoints);       
00280         }
00281 }
00282 
00283 static int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
00284 {
00285         // Freetype2
00286         FT_Face face;
00287         struct TmpFont *tf;
00288         
00289         // Find the correct FreeType font
00290         tf= vfont_find_tmpfont(vfont);
00291         
00292         // What, no font found. Something strange here
00293         if(!tf) return FALSE;
00294         
00295         // Load the font to memory
00296         if(tf->pf)
00297         {
00298                 err= FT_New_Memory_Face( library,
00299                         tf->pf->data,
00300                         tf->pf->size,
00301                         0,
00302                         &face);                 
00303                 if (err) return FALSE;
00304         }
00305         else {
00306                 err = TRUE;
00307                 return FALSE;
00308         }
00309                 
00310         // Read the char
00311         freetypechar_to_vchar(face, charcode, vfont->data);
00312         
00313         // And everything went ok
00314         return TRUE;
00315 }
00316 
00317 
00318 static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
00319 {
00320         // Variables
00321         FT_Face face;
00322         FT_ULong charcode = 0, lcode;
00323         FT_UInt glyph_index;
00324         const char *fontname;
00325         VFontData *vfd;
00326 
00327 /*
00328         FT_CharMap  found = 0;
00329         FT_CharMap  charmap;
00330         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
00331         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
00332         int         n;
00333 */
00334 
00335         // load the freetype font
00336         err = FT_New_Memory_Face( library,
00337                                                 pf->data,
00338                                                 pf->size,
00339                                                 0,
00340                                                 &face );
00341 
00342         if(err) return NULL;
00343 /*
00344         for ( n = 0; n < face->num_charmaps; n++ )
00345         {
00346                 charmap = face->charmaps[n];
00347                 if ( charmap->platform_id == my_platform_id &&
00348                         charmap->encoding_id == my_encoding_id )
00349                 {
00350                         found = charmap;
00351                         break;
00352                 }
00353         }
00354 
00355         if ( !found ) { return NULL; }
00356 
00357         // now, select the charmap for the face object
00358         err = FT_Set_Charmap( face, found );
00359         if ( err ) { return NULL; }
00360 */
00361 
00362         // allocate blender font
00363         vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
00364 
00365         // get the name
00366         fontname = FT_Get_Postscript_Name(face);
00367         strcpy(vfd->name, (fontname == NULL) ? "" : fontname);
00368 
00369         // Extract the first 256 character from TTF
00370         lcode= charcode= FT_Get_First_Char(face, &glyph_index);
00371 
00372         // No charmap found from the ttf so we need to figure it out
00373         if(glyph_index == 0)
00374         {
00375                 FT_CharMap  found = NULL;
00376                 FT_CharMap  charmap;
00377                 int n;
00378 
00379                 for ( n = 0; n < face->num_charmaps; n++ )
00380                 {
00381                         charmap = face->charmaps[n];
00382                         if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
00383                         {
00384                                 found = charmap;
00385                                 break;
00386                         }
00387                 }
00388 
00389                 err = FT_Set_Charmap( face, found );
00390 
00391                 if( err ) 
00392                         return NULL;
00393 
00394                 lcode= charcode= FT_Get_First_Char(face, &glyph_index);
00395         }
00396 
00397         // Load characters
00398         while(charcode < 256)
00399         {
00400                 // Generate the font data
00401                 freetypechar_to_vchar(face, charcode, vfd);
00402 
00403                 // Next glyph
00404                 charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
00405 
00406                 // Check that we won't start infinite loop
00407                 if(charcode <= lcode)
00408                         break;
00409                 lcode = charcode;
00410         }
00411 
00412         return vfd;     
00413 }
00414 
00415 
00416 static int check_freetypefont(PackedFile * pf)
00417 {
00418         FT_Face                 face;
00419         FT_GlyphSlot    glyph;
00420         FT_UInt                 glyph_index;
00421 /*
00422         FT_CharMap  charmap;
00423         FT_CharMap  found;
00424         FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
00425         FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
00426         int         n;
00427 */
00428         int success = 0;
00429 
00430         err = FT_New_Memory_Face( library,
00431                                                         pf->data,
00432                                                         pf->size,
00433                                                         0,
00434                                                         &face );
00435         if(err) {
00436                 success = 0;
00437                 //XXX error("This is not a valid font");
00438         }
00439         else {
00440 /*
00441                 for ( n = 0; n < face->num_charmaps; n++ )
00442                 {
00443                   charmap = face->charmaps[n];
00444                   if ( charmap->platform_id == my_platform_id &&
00445                            charmap->encoding_id == my_encoding_id )
00446                   {
00447                         found = charmap;
00448                         break;
00449                   }
00450                 }
00451 
00452                 if ( !found ) { return 0; }
00453 
00454                 // now, select the charmap for the face object 
00455                 err = FT_Set_Charmap( face, found );
00456                 if ( err ) { return 0; }
00457 */
00458                 glyph_index = FT_Get_Char_Index( face, 'A' );
00459                 err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
00460                 if(err) success = 0;
00461                 else {
00462                         glyph = face->glyph;
00463                         if (glyph->format == ft_glyph_format_outline ) {
00464                                 success = 1;
00465                         } else {
00466                                 //XXX error("Selected Font has no outline data");
00467                                 success = 0;
00468                         }
00469                 }
00470         }
00471         
00472         return success;
00473 }
00474 
00475 
00476 VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
00477 {
00478         VFontData *vfd= NULL;
00479         int success = 0;
00480 
00481         //init Freetype 
00482         err = FT_Init_FreeType( &library);
00483         if(err) {
00484                 //XXX error("Failed to load the Freetype font library");
00485                 return NULL;
00486         }
00487 
00488         success = check_freetypefont(pf);
00489         
00490         if (success) {
00491                 vfd= objfnt_to_ftvfontdata(pf);
00492         }
00493 
00494         //free Freetype
00495         FT_Done_FreeType( library);
00496         
00497         return vfd;
00498 }
00499 
00500 int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
00501 {
00502         int success = FALSE;
00503 
00504         if(!vfont) return FALSE;
00505 
00506         // Init Freetype
00507         err = FT_Init_FreeType(&library);
00508         if(err) {
00509                 //XXX error("Failed to load the Freetype font library");
00510                 return 0;
00511         }
00512 
00513         // Load the character
00514         success = objchr_to_ftvfontdata(vfont, character);
00515         if(success == FALSE) return FALSE;
00516 
00517         // Free Freetype
00518         FT_Done_FreeType(library);
00519 
00520         // Ahh everything ok
00521         return TRUE;
00522 }
00523 
00524 #if 0
00525 
00526 // Freetype2 Outline struct
00527 
00528 typedef struct  FT_Outline_
00529   {
00530         short       n_contours;      /* number of contours in glyph        */
00531         short       n_points;        /* number of points in the glyph      */
00532 
00533         FT_Vector*  points;          /* the outline's points               */
00534         char*       tags;            /* the points flags                   */
00535         short*      contours;        /* the contour end points             */
00536 
00537         int         flags;           /* outline masks                      */
00538 
00539   } FT_Outline;
00540 
00541 #endif
00542 
00543 /***//*
00544 from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
00545 
00546 Vectorial representation of Freetype glyphs
00547 
00548 The source format of outlines is a collection of closed paths called "contours". Each contour is
00549 made of a series of line segments and bezier arcs. Depending on the file format, these can be
00550 second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
00551 they come from the TrueType format. The latter are called cubic arcs and mostly come from the
00552 Type1 format.
00553 
00554 Each arc is described through a series of start, end and control points. Each point of the outline
00555 has a specific tag which indicates wether it is used to describe a line segment or an arc.
00556 
00557 
00558 The following rules are applied to decompose the contour's points into segments and arcs :
00559 
00560 # two successive "on" points indicate a line segment joining them.
00561 
00562 # one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
00563   the control point, and the "on" ones the start and end points.
00564 
00565 # Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
00566   be exactly two cubic control points and two on points for each cubic arc (using a single cubic 
00567   "off" point between two "on" points is forbidden, for example).
00568 
00569 # finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
00570   conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
00571   greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
00572   outlines are described in the TrueType specification.
00573 
00574 Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
00575 font driver produces such outlines.
00576 
00577                                                                   *            # on      
00578                                                                                            * off
00579                                                            __---__
00580   #-__                      _--       -_
00581           --__                _-            -
00582                   --__           #               \
00583                           --__                        #
00584                                   -#
00585                                                    Two "on" points
00586    Two "on" points       and one "conic" point
00587                                                         between them
00588 
00589 
00590 
00591                                 *
00592   #            __      Two "on" points with two "conic"
00593    \          -  -     points between them. The point
00594         \        /    \    marked '0' is the middle of the
00595          -      0      \   "off" points, and is a 'virtual'
00596           -_  _-       #   "on" point where the curve passes.
00597                 --             It does not appear in the point
00598                                            list.
00599                 *
00600 
00601 
00602 
00603 
00604                 *                # on
00605                                    *     * off
00606                  __---__
00607           _--       -_
00608         _-            -
00609    #               \
00610                                         #
00611 
00612          Two "on" points
00613    and two "cubic" point
00614           between them
00615 
00616 
00617 Each glyph's original outline points are located on a grid of indivisible units. The points are stored
00618 in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
00619 range from -16384 to 16383.
00620 
00621 Convert conic to bezier arcs:
00622 Conic P0 P1 P2
00623 Bezier B0 B1 B2 B3
00624 B0=P0
00625 B1=(P0+2*P1)/3
00626 B2=(P2+2*P1)/3
00627 B3=P2
00628 
00629 *//****/