Code

NR::Maybe => boost::optional
[inkscape.git] / src / libnrtype / FontInstance.cpp
index d2b19d0f2255c6ec07cf6c9254c7c48b5cd381bf..4f745c0f946d85859d2829555e86e30f16c80a48 100644 (file)
 #include <libnr/nr-rect.h>
 #include <libnrtype/font-glyph.h>
 #include <libnrtype/font-instance.h>
-
-/* #include <layout/LEGlyphStorage.h> */
-
+#include <2geom/pathvector.h>
 #include <livarot/Path.h>
 
 #include "RasterFont.h"
 
 /* Freetype 2 */
-# include <freetype/ftoutln.h>
-# include <freetype/ftbbox.h>
-# include <freetype/internal/tttypes.h>
-# include <freetype/internal/ftstream.h>
-# include <freetype/tttags.h>
+# include <ft2build.h>
+# include FT_OUTLINE_H
+# include FT_BBOX_H
+# include FT_TRUETYPE_TAGS_H
+# include FT_TRUETYPE_TABLES_H
 # include <pango/pangoft2.h>
 
 
 
 size_t  font_style_hash::operator()(const font_style &x) const {
        int      h=0,n;
-       for (int i=0;i<6;i++) {
-               n=(int)floor(100*x.transform[i]);
-               h*=12186;
-               h+=n;                   
-       }
        n=(int)floor(100*x.stroke_width);
        h*=12186;
        h+=n;
@@ -66,33 +59,23 @@ size_t  font_style_hash::operator()(const font_style &x) const {
 }
 
 bool  font_style_equal::operator()(const font_style &a,const font_style &b) {
-       NR::Matrix  diff=a.transform.inverse();
-       diff*=b.transform;
-       if ( diff.is_translation(0.01) ) {
-               if ( fabs(diff[4]) < 0.01 && fabs(diff[5]) < 0.01 ) {
-               } else {
-                       return false;
-               }
-       } else {
-               return false;
-       }
+    for (int i=0;i<6;i++) {
+        if ( (int)(100*a.transform[i]) != (int)(100*b.transform[i]) ) return false;
+    }
        if ( a.vertical && b.vertical == false ) return false;
        if ( a.vertical == false && b.vertical ) return false;
        if ( a.stroke_width > 0.01 && b.stroke_width <= 0.01 ) return false;
        if ( a.stroke_width <= 0.01 && b.stroke_width > 0.01 ) return false;
        if ( a.stroke_width <= 0.01 && b.stroke_width <= 0.01 ) return true;
-       
+
        if ( a.stroke_cap != b.stroke_cap ) return false;
        if ( a.stroke_join != b.stroke_join ) return false;
-    if ( fabs(a.stroke_miter_limit-b.stroke_miter_limit) > 0.01) return false;
+    if ( (int)(a.stroke_miter_limit*100) != (int)(b.stroke_miter_limit*100) ) return false;
        if ( a.nbDash != b.nbDash ) return false;
        if ( a.nbDash <= 0 ) return true;
-       if ( fabs(a.dash_offset-b.dash_offset) < 0.01 ) {
-               for (int i=0;i<a.nbDash;i++) {
-                       if ( fabs(a.dashes[i]-b.dashes[i]) >= 0.01 ) return false;
-               }
-       } else {
-               return false;
+       if ( (int)floor(100*a.dash_offset) != (int)floor(100*b.dash_offset) ) return false;
+       for (int i=0;i<a.nbDash;i++) {
+               if ( (int)floor(100*a.dashes[i]) != (int)floor(100*b.dashes[i]) ) return false;
        }
        return true;
 }
@@ -107,9 +90,20 @@ typedef struct ft2_to_liv {
        NR::Point    last;
 } ft2_to_liv;
 
+// Note: Freetype 2.2.1 redefined function signatures for functions to be placed in an
+// FT_Outline_Funcs structure.  This is needed to keep backwards compatibility with the
+// 2.1.x series.
+
+/* *** BEGIN #if HACK *** */
+#if FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 2
+typedef FT_Vector const FREETYPE_VECTOR;
+#else
+typedef FT_Vector FREETYPE_VECTOR;
+#endif
+
 // outline as returned by freetype -> livarot Path
 // see nr-type-ft2.cpp for the freetype -> artBPath on which this code is based
-static int ft2_move_to (FT_Vector * to, void * i_user) {
+static int ft2_move_to(FREETYPE_VECTOR *to, void * i_user) {
        ft2_to_liv* user=(ft2_to_liv*)i_user;
        NR::Point   p(user->scale*to->x,user->scale*to->y);
        //      printf("m  t=%f %f\n",p[0],p[1]);
@@ -118,7 +112,7 @@ static int ft2_move_to (FT_Vector * to, void * i_user) {
        return 0;
 }
 
-static int ft2_line_to (FT_Vector * to, void * i_user)
+static int ft2_line_to(FREETYPE_VECTOR *to, void *i_user)
 {
        ft2_to_liv* user=(ft2_to_liv*)i_user;
        NR::Point   p(user->scale*to->x,user->scale*to->y);
@@ -128,10 +122,10 @@ static int ft2_line_to (FT_Vector * to, void * i_user)
        return 0;
 }
 
-static int ft2_conic_to (FT_Vector * control, FT_Vector * to, void * i_user)
+static int ft2_conic_to(FREETYPE_VECTOR *control, FREETYPE_VECTOR *to, void *i_user)
 {
        ft2_to_liv* user=(ft2_to_liv*)i_user;
-       NR::Point   p(user->scale*to->x,user->scale*to->y),c(user->scale*control->x,user->scale*control->y);  
+       NR::Point   p(user->scale*to->x,user->scale*to->y),c(user->scale*control->x,user->scale*control->y);
        //      printf("b c=%f %f  t=%f %f\n",c[0],c[1],p[0],p[1]);
        user->theP->BezierTo(p);
        user->theP->IntermBezierTo(c);
@@ -140,19 +134,21 @@ static int ft2_conic_to (FT_Vector * control, FT_Vector * to, void * i_user)
        return 0;
 }
 
-static int ft2_cubic_to (FT_Vector * control1, FT_Vector * control2, FT_Vector * to, void * i_user)
+static int ft2_cubic_to(FREETYPE_VECTOR *control1, FREETYPE_VECTOR *control2, FREETYPE_VECTOR *to, void *i_user)
 {
        ft2_to_liv* user=(ft2_to_liv*)i_user;
        NR::Point   p(user->scale*to->x,user->scale*to->y),
        c1(user->scale*control1->x,user->scale*control1->y),
-       c2(user->scale*control2->x,user->scale*control2->y);  
+       c2(user->scale*control2->x,user->scale*control2->y);
        //      printf("c c1=%f %f  c2=%f %f   t=%f %f\n",c1[0],c1[1],c2[0],c2[1],p[0],p[1]);
-       user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2)); 
+       user->theP->CubicTo(p,3*(c1-user->last),3*(p-c2));
        user->last=p;
        return 0;
 }
 #endif
 
+/* *** END #if HACK *** */
+
 /*
  *
  */
@@ -182,7 +178,7 @@ font_instance::~font_instance(void)
 
        for (int i=0;i<nbGlyph;i++) {
                if ( glyphs[i].outline ) delete glyphs[i].outline;
-               if ( glyphs[i].artbpath ) free(glyphs[i].artbpath);
+        if ( glyphs[i].pathvector ) delete glyphs[i].pathvector;
        }
        if ( glyphs ) free(glyphs);
        nbGlyph=maxGlyph=0;
@@ -233,7 +229,7 @@ unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int
        }
        char*   res=NULL;
        bool    free_res=false;
-       
+
        if ( strcmp(key,"name") == 0 ) {
                PangoFontDescription* td=pango_font_description_copy(descr);
                pango_font_description_unset_fields (td, PANGO_FONT_MASK_SIZE);
@@ -251,11 +247,11 @@ unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int
              bool o = (style == PANGO_STYLE_OBLIQUE);
              PangoWeight weight=pango_font_description_get_weight(descr);
              bool b = (weight >= PANGO_WEIGHT_BOLD);
-   
-             res = g_strdup_printf ("%s%s%s%s", 
-                                    pango_font_description_get_family(descr), 
-                                    (b || i || o) ? "-" : "", 
-                                    (b) ? "Bold" : "", 
+
+             res = g_strdup_printf ("%s%s%s%s",
+                                    pango_font_description_get_family(descr),
+                                    (b || i || o) ? "-" : "",
+                                    (b) ? "Bold" : "",
                                     (i) ? "Italic" : ((o) ? "Oblique" : "")  );
              free_res = true;
          }
@@ -265,51 +261,53 @@ unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int
        } else if ( strcmp(key,"style") == 0 ) {
                PangoStyle v=pango_font_description_get_style(descr);
                if ( v == PANGO_STYLE_ITALIC ) {
-                       res="italic";
+                       res=(char*)"italic";
                } else if ( v == PANGO_STYLE_OBLIQUE ) {
-                       res="oblique";
+                       res=(char*)"oblique";
                } else {
-                       res="normal";
+                       res=(char*)"normal";
                }
                free_res=false;
        } else if ( strcmp(key,"weight") == 0 ) {
                PangoWeight v=pango_font_description_get_weight(descr);
                if ( v <= PANGO_WEIGHT_ULTRALIGHT ) {
-                       res="200";
+                       res=(char*)"200";
                } else if ( v <= PANGO_WEIGHT_LIGHT ) {
-                       res="300";
+                       res=(char*)"300";
                } else if ( v <= PANGO_WEIGHT_NORMAL ) {
-                       res="normal";
+                       res=(char*)"normal";
                } else if ( v <= PANGO_WEIGHT_BOLD ) {
-                       res="bold";
-               } else {
-                       res="800";
+                       res=(char*)"bold";
+               } else if ( v <= PANGO_WEIGHT_ULTRABOLD ) {
+                   res=(char*)"800";
+               } else { // HEAVY
+                       res=(char*)"900";
                }
                free_res=false;
        } else if ( strcmp(key,"stretch") == 0 ) {
                PangoStretch v=pango_font_description_get_stretch(descr);
                if ( v <= PANGO_STRETCH_EXTRA_CONDENSED ) {
-                       res="extra-condensed";
+                       res=(char*)"extra-condensed";
                } else if ( v <= PANGO_STRETCH_CONDENSED ) {
-                       res="condensed";
+                       res=(char*)"condensed";
                } else if ( v <= PANGO_STRETCH_SEMI_CONDENSED ) {
-                       res="semi-condensed";
+                       res=(char*)"semi-condensed";
                } else if ( v <= PANGO_STRETCH_NORMAL ) {
-                       res="normal";
+                       res=(char*)"normal";
                } else if ( v <= PANGO_STRETCH_SEMI_EXPANDED ) {
-                       res="semi-expanded";
+                       res=(char*)"semi-expanded";
                } else if ( v <= PANGO_STRETCH_EXPANDED ) {
-                       res="expanded";
+                       res=(char*)"expanded";
                } else {
-                       res="extra-expanded";
+                       res=(char*)"extra-expanded";
                }
                free_res=false;
        } else if ( strcmp(key,"variant") == 0 ) {
                PangoVariant v=pango_font_description_get_variant(descr);
                if ( v == PANGO_VARIANT_SMALL_CAPS ) {
-                       res="small-caps";
+                       res=(char*)"small-caps";
                } else {
-                       res="normal";
+                       res=(char*)"normal";
                }
                free_res=false;
        } else {
@@ -320,7 +318,7 @@ unsigned int font_instance::Attribute(const gchar *key, gchar *str, unsigned int
                if ( size > 0 ) str[0]=0;
                return 0;
        }
-       
+
        if (res) {
                unsigned int len=strlen(res);
                unsigned int rlen=(size-1<len)?size-1:len;
@@ -349,7 +347,8 @@ void font_instance::InitTheFace()
     SelectObject(daddy->hScreenDC,theFace);
 #else
        theFace=pango_ft2_font_get_face(pFont);
-       FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol);
+    if ( theFace )
+        FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol);
 #endif
 }
 
@@ -383,7 +382,7 @@ bool        font_instance::IsOutlineFont(void)
     InitTheFace();
 #ifdef USE_PANGO_WIN32
     TEXTMETRIC tm;
-    return GetTextMetrics(daddy->hScreenDC,&tm) && tm.tmPitchAndFamily&TMPF_TRUETYPE;
+    return GetTextMetrics(daddy->hScreenDC,&tm) && tm.tmPitchAndFamily&(TMPF_TRUETYPE|TMPF_DEVICE);
 #else
        return FT_IS_SCALABLE(theFace);
 #endif
@@ -420,7 +419,7 @@ void font_instance::LoadGlyph(int glyph_id)
        if ( pFont == NULL ) return;
     InitTheFace();
 #ifndef USE_PANGO_WIN32
-       if ( theFace->units_per_EM == 0 ) return; // bitmap font
+       if ( !FT_IS_SCALABLE(theFace) ) return; // bitmap font
 #endif
 
        if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
@@ -430,11 +429,16 @@ void font_instance::LoadGlyph(int glyph_id)
                }
                font_glyph  n_g;
                n_g.outline=NULL;
-               n_g.artbpath=NULL;
+        n_g.pathvector=NULL;
                n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0;
                bool   doAdd=false;
 
 #ifdef USE_PANGO_WIN32
+
+#ifndef GGO_UNHINTED         // For compatibility with old SDKs.
+#define GGO_UNHINTED 0x0100
+#endif
+
         MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
         OUTLINETEXTMETRIC otm;
         GetOutlineTextMetrics(daddy->hScreenDC, sizeof(otm), &otm);
@@ -552,7 +556,7 @@ void font_instance::LoadGlyph(int glyph_id)
                if ( doAdd ) {
                        if ( n_g.outline ) {
                                n_g.outline->FastBBox(n_g.bbox[0],n_g.bbox[1],n_g.bbox[2],n_g.bbox[3]);
-                               n_g.artbpath=n_g.outline->MakeArtBPath();
+                n_g.pathvector=n_g.outline->MakePathVector();
                        }
                        glyphs[nbGlyph]=n_g;
                        id_to_no[glyph_id]=nbGlyph;
@@ -599,8 +603,8 @@ bool font_instance::FontSlope(double &run, double &rise)
     run=otm.otmsCharSlopeRun;
     rise=otm.otmsCharSlopeRise;
 #else
-       if ( theFace->units_per_EM == 0 ) return false; // bitmap font
-       
+       if ( !FT_IS_SCALABLE(theFace) ) return false; // bitmap font
+
     TT_HoriHeader *hhea = (TT_HoriHeader*)FT_Get_Sfnt_Table(theFace, ft_sfnt_hhea);
     if (hhea == NULL) return false;
     run = hhea->caret_Slope_Run;
@@ -609,7 +613,7 @@ bool font_instance::FontSlope(double &run, double &rise)
        return true;
 }
 
-NR::Rect font_instance::BBox(int glyph_id)
+boost::optional<NR::Rect> font_instance::BBox(int glyph_id)
 {
        int no=-1;
        if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
@@ -622,11 +626,13 @@ NR::Rect font_instance::BBox(int glyph_id)
        } else {
                no=id_to_no[glyph_id];
        }
-       if ( no < 0 ) return NR::Rect(NR::Point(0,0),NR::Point(0,0));
-       NR::Point rmin(glyphs[no].bbox[0],glyphs[no].bbox[1]);
-       NR::Point rmax(glyphs[no].bbox[2],glyphs[no].bbox[3]);
-       NR::Rect  res(rmin,rmax);
-       return res;
+       if ( no < 0 ) {
+            return boost::optional<NR::Rect>();
+        } else {
+           NR::Point rmin(glyphs[no].bbox[0],glyphs[no].bbox[1]);
+           NR::Point rmax(glyphs[no].bbox[2],glyphs[no].bbox[3]);
+           return NR::Rect(rmin, rmax);
+        }
 }
 
 Path* font_instance::Outline(int glyph_id,Path* copyInto)
@@ -652,21 +658,21 @@ Path* font_instance::Outline(int glyph_id,Path* copyInto)
        return src_o;
 }
 
-void* font_instance::ArtBPath(int glyph_id)
+Geom::PathVector* font_instance::PathVector(int glyph_id)
 {
-       int no=-1;
-       if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
-               LoadGlyph(glyph_id);
-               if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
-                       // didn't load
-               } else {
-                       no=id_to_no[glyph_id];
-               }
-       } else {
-               no=id_to_no[glyph_id];
-       }
-       if ( no < 0 ) return NULL;
-       return glyphs[no].artbpath;
+    int no = -1;
+    if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
+        LoadGlyph(glyph_id);
+        if ( id_to_no.find(glyph_id) == id_to_no.end() ) {
+            // didn't load
+        } else {
+            no = id_to_no[glyph_id];
+        }
+    } else {
+        no = id_to_no[glyph_id];
+    }
+    if ( no < 0 ) return NULL;
+    return glyphs[no].pathvector;
 }
 
 double font_instance::Advance(int glyph_id,bool vertical)
@@ -690,10 +696,10 @@ double font_instance::Advance(int glyph_id,bool vertical)
                }
        }
        return 0;
-}      
+}
 
 
-raster_font* font_instance::RasterFont(const NR::Matrix &trs,double stroke_width,bool vertical,JoinType stroke_join,ButtType stroke_cap,float miter_limit)
+raster_font* font_instance::RasterFont(const NR::Matrix &trs, double stroke_width, bool vertical, JoinType stroke_join, ButtType stroke_cap, float /*miter_limit*/)
 {
        font_style  nStyle;
        nStyle.transform=trs;