Blender V2.61 - r43446

freetypefont.c

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