Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenlib/intern/freetypefont.c')
-rw-r--r--source/blender/blenlib/intern/freetypefont.c634
1 files changed, 634 insertions, 0 deletions
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
new file mode 100644
index 00000000000..7fbd4bac485
--- /dev/null
+++ b/source/blender/blenlib/intern/freetypefont.c
@@ -0,0 +1,634 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is written by Rob Haarsma (phase)
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL 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
+
+#ifdef WIN32
+#pragma warning (disable:4244)
+#endif
+
+#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_vfontdata.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BIF_toolbox.h"
+
+#include "BKE_global.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 255
+
+/* local variables */
+static FT_Library library;
+static FT_Error err;
+
+
+void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
+{
+ // Blender
+ struct Nurb *nu;
+ struct VChar *che;
+ struct BezTriple *bezt;
+
+ // Freetype2
+ FT_GlyphSlot glyph;
+ FT_UInt glyph_index;
+ FT_Outline ftoutline;
+ float scale, height;
+ float dx, dy;
+ int j,k,l,m=0;
+
+ // 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") ;
+
+ // calculate total points of each contour
+ for(j = 0; j < ftoutline.n_contours; j++) {
+ if(j == 0)
+ npoints[j] = ftoutline.contours[j] + 1;
+ else
+ npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
+ }
+
+ // get number of on-curve points for beziertriples (including conic virtual on-points)
+ for(j = 0; j < ftoutline.n_contours; j++) {
+ l = 0;
+ for(k = 0; k < npoints[j]; k++) {
+ if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
+ if(ftoutline.tags[l] == FT_Curve_Tag_On)
+ onpoints[j]++;
+
+ if(k < npoints[j] - 1 )
+ if( ftoutline.tags[l] == FT_Curve_Tag_Conic &&
+ ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
+ onpoints[j]++;
+ }
+ }
+
+ //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(&che->nurbsbase, nu);
+
+ nu->type= CU_BEZIER+CU_2D;
+ nu->pntsu = onpoints[j];
+ nu->resolu= 8;
+ nu->flagu= 1;
+ 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;
+
+ //left handle
+ bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
+ bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
+
+ //midpoint (virtual on-curve point)
+ 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++;
+ }
+ }
+
+ //on-curve points
+ if(ftoutline.tags[l] == FT_Curve_Tag_On) {
+ //left handle
+ if(k > 0) {
+ if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
+ bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
+ bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
+ bezt->h1= HD_FREE;
+ } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
+ bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
+ bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
+ bezt->h1= HD_FREE;
+ } else {
+ bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
+ bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
+ bezt->h1= HD_VECT;
+ }
+ } else { //first point on curve
+ if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
+ bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
+ bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
+ bezt->h1= HD_FREE;
+ } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
+ bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
+ bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
+ bezt->h1= HD_FREE;
+ } else {
+ bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
+ bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
+ bezt->h1= HD_VECT;
+ }
+ }
+
+ //midpoint (on-curve point)
+ bezt->vec[1][0] = ftoutline.points[l].x* scale;
+ bezt->vec[1][1] = ftoutline.points[l].y* scale;
+
+ //right handle
+ if(k < (npoints[j] - 1)) {
+ if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
+ bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
+ bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
+ bezt->h2= HD_FREE;
+ } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
+ bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
+ bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
+ bezt->h2= HD_FREE;
+ } else {
+ bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
+ bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
+ bezt->h2= HD_VECT;
+ }
+ } else { //last point on curve
+ if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
+ bezt->vec[2][0] = ftoutline.points[m].x* scale;
+ bezt->vec[2][1] = ftoutline.points[m].y* scale;
+ bezt->h2= HD_FREE;
+ } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
+ bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
+ bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
+ bezt->h2= HD_FREE;
+ } else {
+ bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
+ bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
+ bezt->h2= HD_VECT;
+ }
+ }
+
+ // get the handles that are aligned, tricky...
+ // DistVL2Dfl, check if the three beztriple points are on one line
+ // VecLenf, see if there's a distance between the three points
+ // VecLenf again, to check the angle between the handles
+ // finally, check if one of them is a vector handle
+ if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
+ (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
+ (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
+ (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
+ (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
+ bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
+ {
+ bezt->h1= bezt->h2= HD_ALIGN;
+ }
+ bezt++;
+ }
+ }
+ }
+ if(npoints) MEM_freeN(npoints);
+ if(onpoints) MEM_freeN(onpoints);
+ }
+}
+
+int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
+{
+ // Freetype2
+ FT_Face face;
+ struct TmpFont *tf;
+
+ // Find the correct FreeType font
+ tf= G.ttfdata.first;
+ while(tf)
+ {
+ if(tf->vfont == vfont)
+ break;
+ tf= tf->next;
+ }
+
+ // 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;
+ }
+
+ err = FT_Set_Charmap( face, (FT_CharMap) FT_ENCODING_UNICODE );
+
+ return vfd;
+}
+
+
+static int check_freetypefont(PackedFile * pf)
+{
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_UInt glyph_index;
+/*
+ FT_CharMap charmap;
+ FT_CharMap found;
+ FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
+ FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
+ int n;
+*/
+ int success = 0;
+
+ err = FT_New_Memory_Face( library,
+ pf->data,
+ pf->size,
+ 0,
+ &face );
+ if(err) {
+ success = 0;
+ error("This is not a valid font");
+ }
+ else {
+/*
+ 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 0; }
+
+ // now, select the charmap for the face object
+ err = FT_Set_Charmap( face, found );
+ if ( err ) { return 0; }
+*/
+ glyph_index = FT_Get_Char_Index( face, 'A' );
+ 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");
+ success = 0;
+ }
+ }
+ }
+
+ return success;
+}
+
+
+VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
+{
+ VFontData *vfd= NULL;
+ int success = 0;
+
+ //init Freetype
+ err = FT_Init_FreeType( &library);
+ if(err) {
+ error("Failed to load the Freetype font library");
+ return 0;
+ }
+
+ success = check_freetypefont(pf);
+
+ if (success) {
+ vfd= objfnt_to_ftvfontdata(pf);
+ }
+
+ //free Freetype
+ FT_Done_FreeType( library);
+
+ return vfd;
+}
+
+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) {
+ 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
+
+*//****/