octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

TeX interpreter for FLTK backend


From: David Bateman
Subject: TeX interpreter for FLTK backend
Date: Thu, 11 Nov 2010 23:03:22 +0100
User-agent: Mozilla-Thunderbird 2.0.0.22 (X11/20090706)

One of the last missing features of the FLTK backend that makes me want
to stick with the gnuplot backend, is that when the "interpreter"
property is set to "tex", a simple interpreter for symbols, subscripts,
superscripts, etc allows for simple equations to be used in plots. The
attached changeset is a first attempt at adding this feature to the FLTK
backend. The only sub-feature I think is missing is that something like

text (0,0, "{\fontsize{32}\int_{\fontsize{16}0}^{\fontsize{16}x}}")

is supposed to have the x above the 0 and it doesn't yet. Though I'm not
quite sure of the best way of implementing this.

Also I'd prefer that the "face_stacked_elem" class and the variable
"lst" of type std::list<face_stacked_elem> was in the ft_render class,
though when I do that I get a segfault I can't trackdown. The code could
also perhaps be simplified in other ways and I'd be happy to hear any
ideas, bugs that you've found, a way of getting the stack into the
ft_render class, etc before I push this as a changeset

Enjoy
David

PS : The feature that this changeset adds to the FLTK backend appears to
be broken in the gnuplot backend in the development sources for my test
cases. I'll look at fixing it soon.

diff --git a/src/txt-eng-ft.cc b/src/txt-eng-ft.cc
--- a/src/txt-eng-ft.cc
+++ b/src/txt-eng-ft.cc
@@ -35,6 +35,7 @@
 #include "error.h"
 #include "pr-output.h"
 #include "txt-eng-ft.h"
+#include "oct-map.h"
 
 class
 ft_manager
@@ -209,12 +210,20 @@
     FT_Done_Face (face);
 
   // FIXME: take "fontunits" into account
-  double font_size = props.get ("fontsize").double_value ();
+  font_size = props.get ("fontsize").double_value ();
+  fontname = props.get ("fontname").string_value ();
+  fontweight = props.get ("fontweight").string_value ();
+  fontangle = props.get ("fontangle").string_value ();
 
-  face = ft_manager::get_font (props.get ("fontname").string_value (),
-                               props.get ("fontweight").string_value (),
-                               props.get ("fontangle").string_value (),
-                               font_size);
+  face = ft_manager::get_font (fontname, fontweight, fontangle, font_size);
+
+  std::string interp = props.get ("interpreter").string_value ();
+  if (interp.compare ("tex") == 0)
+    interpreter = INTERPRETER_TEX;
+  else if (interp.compare ("latex") == 0)
+    interpreter = INTERPRETER_LATEX;
+  else
+    interpreter = INTERPRETER_NONE;
 
   if (face)
     {
@@ -258,30 +267,601 @@
     }
 }
 
+class face_stacked_elem
+{
+public:
+  face_stacked_elem (const FT_Face &_face, double _font_size,
+                     const std::string &_fontname,
+                     const std::string &_fontweight,
+                     const std::string &_fontangle, int _suboffset,
+                     bool _pop_immediate = false,
+                     bool _bracket = false,
+                     double _red = -1.0,
+                     double _green = -1.0,
+                     double _blue = -1.0) :
+      face (_face), font_size (_font_size), fontname (_fontname), 
+      fontweight (_fontweight), fontangle (_fontangle),
+      suboffset (_suboffset), pop_immediate (_pop_immediate),
+      bracket (_bracket), red (_red), green (_green), blue (_blue) { }
+
+  face_stacked_elem (const face_stacked_elem &a) :
+      face (a.face), font_size (a.font_size), fontname (a.fontname), 
+      fontweight (a.fontweight), fontangle (a.fontangle),
+      suboffset (a.suboffset), pop_immediate (a.pop_immediate),
+      bracket (a.bracket), red (a.red), green (a.green), blue (a.blue) { }
+
+  FT_Face face;
+  double font_size;
+  std::string fontname;
+  std::string fontweight;
+  std::string fontangle;
+  int suboffset;
+  bool pop_immediate;
+  bool bracket;
+  double red;
+  double green;
+  double blue;
+};
+
+void
+ft_render::push_font (void *lst, const std::string &_fontname,
+                      const std::string &_fontweight, 
+                      const std::string &_fontangle,
+                      const double &_font_size,
+                      const int &suboffset, 
+                      const bool &pop_immediate,
+                      bool bracket, double _red,
+                      double _green, double _blue)
+{
+  face_stacked_elem elem (face, font_size, fontname, fontweight, fontangle,
+                          suboffset, pop_immediate, bracket, red, green, blue);
+
+  reinterpret_cast<std::list<face_stacked_elem> *>(lst)->push_back (elem);
+
+  fontname = _fontname;
+  fontweight = _fontweight;
+  fontangle = _fontangle;
+  font_size = _font_size;
+
+  if (_red >= 0.0 && _red <= 1.0)
+      red = static_cast<uint8_t> (_red * 255);
+  if (_green >= 0.0 && _green <= 1.0)
+      green = static_cast<uint8_t> (_green * 255);
+  if (_blue >= 0.0 && _blue <= 1.0)
+      blue = static_cast<uint8_t> (_blue * 255);
+
+  face = ft_manager::get_font (fontname, fontweight, fontangle, font_size);
+
+  if (face)
+    {
+      if (FT_Set_Char_Size (face, 0, font_size*64, 0, 0))
+        ::warning ("ft_render: unable to set font size to %d", font_size);
+    }
+  else
+    ::warning ("ft_render: unable to load appropriate font");
+}
+
+void
+ft_render::pop_font (void *lst, int &suboffset, bool &pop_immediate, 
+                     bool bracket)
+{    
+  while (! reinterpret_cast<std::list<face_stacked_elem> *>(lst)->empty ()) 
+    {
+      FT_Done_Face (face);
+      face_stacked_elem elem = 
+        reinterpret_cast<std::list<face_stacked_elem> *>(lst)->back ();
+      face = elem.face; 
+      font_size = elem.font_size;
+      fontname = elem.fontname;
+      fontweight = elem.fontweight;
+      fontangle = elem.fontangle;
+      red = elem.red;
+      green = elem.green;
+      blue = elem.blue;
+      suboffset = elem.suboffset;
+      pop_immediate = elem.pop_immediate;
+
+      reinterpret_cast<std::list<face_stacked_elem> *>(lst)->pop_back ();
+
+      if (bracket)
+        {
+          if (elem.bracket)
+            bracket = false;
+          else
+            continue;
+        }
+
+      if (! pop_immediate)
+        break;
+    }
+}
+
+static void
+setup_symbol_map (octave_scalar_map& map)
+{
+  // Create lookup table from the TeX code for a character to the
+  // corresponding Unicode charcode. The codes from the site
+  //
+  // http://www.alanwood.net/unicode/index.html
+  //
+  // was used in the construction of this table
+
+  map.setfield ("copyright", octave_uint32(0xa9));
+  map.setfield ("neg", octave_uint32(0xac));
+  map.setfield ("circ", octave_uint32(0xb0));
+  map.setfield ("pm", octave_uint32(0xb1));
+  map.setfield ("times", octave_uint32(0xd7));
+  map.setfield ("div", octave_uint32(0xf7));
+  map.setfield ("Alpha", octave_uint32(0x391));
+  map.setfield ("Beta", octave_uint32(0x392));
+  map.setfield ("Gamma", octave_uint32(0x393));
+  map.setfield ("Delta", octave_uint32(0x394));
+  map.setfield ("Epsilon", octave_uint32(0x395));
+  map.setfield ("Zeta", octave_uint32(0x396));
+  map.setfield ("Eta", octave_uint32(0x397));
+  map.setfield ("Theta", octave_uint32(0x398));
+  map.setfield ("Iota", octave_uint32(0x399));
+  map.setfield ("Kappa", octave_uint32(0x39a));
+  map.setfield ("Lambda", octave_uint32(0x39b));
+  map.setfield ("Mu", octave_uint32(0x39c));
+  map.setfield ("Nu", octave_uint32(0x39d));
+  map.setfield ("Xi", octave_uint32(0x39e));
+  map.setfield ("Omicron", octave_uint32(0x39f));
+  map.setfield ("Pi", octave_uint32(0x3a0));
+  map.setfield ("Rho", octave_uint32(0x3a1));
+  map.setfield ("Sigma", octave_uint32(0x3a3));
+  map.setfield ("Tau", octave_uint32(0x3a4));
+  map.setfield ("Upsilon", octave_uint32(0x3a5));
+  map.setfield ("Phi", octave_uint32(0x3a6));
+  map.setfield ("Chi", octave_uint32(0x3a7));
+  map.setfield ("Psi", octave_uint32(0x3a8));
+  map.setfield ("Omega", octave_uint32(0x3a9));
+  map.setfield ("alpha", octave_uint32(0x3b1));
+  map.setfield ("beta", octave_uint32(0x3b2));
+  map.setfield ("gamma", octave_uint32(0x3b3));
+  map.setfield ("delta", octave_uint32(0x3b4));
+  map.setfield ("epsilon", octave_uint32(0x3b5));
+  map.setfield ("zeta", octave_uint32(0x3b6));
+  map.setfield ("eta", octave_uint32(0x3b7));
+  map.setfield ("theta", octave_uint32(0x3b8));
+  map.setfield ("iota", octave_uint32(0x3b9));
+  map.setfield ("kappa", octave_uint32(0x3ba));
+  map.setfield ("lambda", octave_uint32(0x3bb));
+  map.setfield ("mu", octave_uint32(0x3bc));
+  map.setfield ("nu", octave_uint32(0x3bd));
+  map.setfield ("xi", octave_uint32(0x3be));
+  map.setfield ("omicron", octave_uint32(0x3bf));
+  map.setfield ("pi", octave_uint32(0x3c0));
+  map.setfield ("rho", octave_uint32(0x3c1));
+  map.setfield ("varsigma", octave_uint32(0x3c2));
+  map.setfield ("sigma", octave_uint32(0x3c3));
+  map.setfield ("tau", octave_uint32(0x3c4));
+  map.setfield ("upsilon", octave_uint32(0x3c5));
+  map.setfield ("phi", octave_uint32(0x3c6));
+  map.setfield ("chi", octave_uint32(0x3c7));
+  map.setfield ("psi", octave_uint32(0x3c8));
+  map.setfield ("omega", octave_uint32(0x3c9));
+  map.setfield ("vartheta", octave_uint32(0x3d1));
+  map.setfield ("varphi", octave_uint32(0x3d5));
+  map.setfield ("varpi", octave_uint32(0x3d6));
+  map.setfield ("ldots", octave_uint32(0x2026));
+  map.setfield ("prime", octave_uint32(0x2032));
+  map.setfield ("Im", octave_uint32(0x2111));
+  map.setfield ("wp", octave_uint32(0x2118));
+  map.setfield ("Re", octave_uint32(0x211c));
+  map.setfield ("aleph", octave_uint32(0x2135));
+  map.setfield ("leftarrow", octave_uint32(0x2190));
+  map.setfield ("uparrow", octave_uint32(0x2191));
+  map.setfield ("rightarrow", octave_uint32(0x2192));
+  map.setfield ("downarrow", octave_uint32(0x2193));
+  map.setfield ("leftrightarrow", octave_uint32(2194));
+  map.setfield ("Leftarrow", octave_uint32(0x21d0));
+  map.setfield ("Uparrow", octave_uint32(0x21d1));
+  map.setfield ("Rightarrow", octave_uint32(0x21d2));
+  map.setfield ("Downarrow", octave_uint32(0x21d3));
+  map.setfield ("Leftrightarrow", octave_uint32(0x21d4));
+  map.setfield ("forall", octave_uint32(0x2200));
+  map.setfield ("partial", octave_uint32(0x2202));
+  map.setfield ("exists", octave_uint32(0x2203));
+  map.setfield ("nabla", octave_uint32(0x2207));
+  map.setfield ("in", octave_uint32(0x2208));
+  map.setfield ("notin", octave_uint32(0x2209));
+  map.setfield ("ni", octave_uint32(0x220b));
+  map.setfield ("prod", octave_uint32(0x220f));
+  map.setfield ("o", octave_uint32(0x2218));
+  map.setfield ("surd", octave_uint32(0x221a));
+  map.setfield ("propto", octave_uint32(0x221d));
+  map.setfield ("infty", octave_uint32(0x221e));
+  map.setfield ("angle", octave_uint32(0x2220));
+  map.setfield ("mid", octave_uint32(0x2223));
+  map.setfield ("wedge", octave_uint32(0x2227));
+  map.setfield ("vee", octave_uint32(0x2228));
+  map.setfield ("cap", octave_uint32(0x2229));
+  map.setfield ("cup", octave_uint32(0x222a));
+  map.setfield ("int", octave_uint32(0x222b));
+  map.setfield ("sim", octave_uint32(0x223C));
+  map.setfield ("cong", octave_uint32(0x2245));
+  map.setfield ("approx", octave_uint32(0x2248));
+  map.setfield ("neq", octave_uint32(0x2260));
+  map.setfield ("equiv", octave_uint32(0x2261));
+  map.setfield ("leq", octave_uint32(0x2264));
+  map.setfield ("geq", octave_uint32(0x2265));
+  map.setfield ("subset", octave_uint32(0x2282));
+  map.setfield ("supset", octave_uint32(0x2283));
+  map.setfield ("supseteq", octave_uint32(0x2286));
+  map.setfield ("subseteq", octave_uint32(0x2287));
+  map.setfield ("oplus", octave_uint32(0x2295));
+  map.setfield ("ominus", octave_uint32(0x2296));
+  map.setfield ("otimes", octave_uint32(0x2297));
+  map.setfield ("oslash", octave_uint32(0x2298));
+  map.setfield ("odot", octave_uint32(0x2299));
+  map.setfield ("perp", octave_uint32(0x22A5));
+  map.setfield ("diamond", octave_uint32(0x22c4));
+  map.setfield ("cdot", octave_uint32(0x22c5));
+  map.setfield ("lceil ", octave_uint32(0x2308));
+  map.setfield ("rceil ", octave_uint32(0x2309));
+  map.setfield ("lfloor", octave_uint32(0x230a));
+  map.setfield ("rfloor", octave_uint32(0x230b));
+  map.setfield ("langle", octave_uint32(0x2329));
+  map.setfield ("rangle", octave_uint32(0x232a));
+  map.setfield ("bigtriangledown", octave_uint32(0x25bd));
+  map.setfield ("spadesuit", octave_uint32(0x2660));
+  map.setfield ("clubsuit", octave_uint32(0x2663));
+  map.setfield ("heartsuit", octave_uint32(0x2665));
+  map.setfield ("diamondsuit", octave_uint32(0x2666));
+}
+
+static bool
+lookup_symbol (const std::string s, size_t &i, size_t &n, uint32_t &sym)
+{
+  bool ret = false;
+  static octave_scalar_map map;
+
+  sym = 0;
+
+  if (map.nfields () == 0)
+    setup_symbol_map (map);
+
+  if (s[i+1] == '0')
+    {
+      // Special case the \0 symbol
+      ret = true;
+      sym = 0x2205;
+      n = 2;
+    }
+  else
+    {
+      size_t j = s.find_first_not_of 
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", i + 1);
+      octave_value val = map.getfield (s.substr(i + 1, j - i - 1));
+      if (val.is_defined ())
+        {
+          ret = true;
+          sym = val.uint32_scalar_value();
+          if (j == std::string::npos)
+            n = s.length () - i;
+          else
+            n = j - i;
+        }
+      else
+        {
+          // Last desperate attempt to find symbols like "\Pix" that should
+          // be interpreted as "\Pi" followed by "x"
+          const string_vector flds = map.fieldnames ();
+
+          for (octave_idx_type k = 0; k < flds.numel (); k++) 
+            {
+              const std::string fld = flds (k);
+              if (fld.compare (s.substr (i + 1, fld.length ())) == 0)
+                {
+                  val = map.getfield (fld);
+
+                  if (val.is_defined ())
+                    {
+                      ret = true;
+                      sym = val.uint32_scalar_value();
+                      n = fld.length () + 1;
+                      break;
+                    }
+                }
+            }
+        }
+    }
+  return ret;
+}
+
 void
 ft_render::visit (text_element_string& e)
 {
   if (face)
     {
+      std::list<face_stacked_elem> lst;
+      bool pop_immediate = false;
+      int suboffset = 0;
+
       std::string str = e.string_value ();
       FT_UInt glyph_index, previous = 0;
+      size_t i = 0;
+      while (i < str.length ())
+        {
+          size_t n;
+          uint32_t sym;
 
-      for (size_t i = 0; i < str.length (); i++)
-        {
-          glyph_index = FT_Get_Char_Index (face, str[i]);
+          // FIXME: What should we do with INTERPRETER_LATEX ??
+          // For now treat it like the TeX interpreter
+          if ((is_tex() || is_latex()))
+            {
+              switch (str [i])
+                {
+                case '\\' :
+                  {
+                    if (str.substr (i + 1, 9).compare("fontname{") == 0)
+                      {
+                        size_t k = str.find_first_of ("}", i + 10);
+
+                        push_font (&lst, str.substr (i + 10, k - i - 10),
+                                   fontweight, fontangle, font_size,
+                                   suboffset, pop_immediate);
+                        i = k + 1;
+                        continue;
+                      }
+                    else if (str.substr (i + 1, 9).compare("fontsize{") == 0)
+                      {
+                        size_t k = str.find_first_of ("}", i + 10);
+
+                        double new_font_size = 
+                          atoi (str.substr (i + 10, k - i - 10).c_str ());
+
+                        push_font (&lst, fontname, fontweight, 
+                                   fontangle, new_font_size,
+                                   suboffset, pop_immediate);
+                        i = k + 1;
+                        continue;
+                      }
+                    else if (str.substr (i + 1, 6).compare("color{") == 0)
+                      {
+                        size_t k = str.find_first_of ("}", i + 7);
+                        std::string substr = str.substr (i + 7, k - i - 7);
+
+                        if (substr.length () > 0)
+                          {
+                            double new_red;
+                            double new_green;
+                            double new_blue;
+                            bool have_valid_color = false;
+
+                            std::transform (substr.begin (), substr.end (),
+                                            substr.begin (), tolower);
+
+                            char c = substr[0];
+
+                            if (c == '[')
+                              {
+                                size_t x = substr.find_first_not_of(" ", 1);
+                                size_t y = substr.find_first_of(" ,", x);
+
+                                if (x != y)
+                                  {
+                                    new_red = atof (substr.substr(x, 
+                                              y - x).c_str());
+
+                                    x = substr.find_first_not_of(" ,", y + 1);
+                                    y = substr.find_first_of(" ,", x);
+
+                                    if (x != y)
+                                      {
+                                        new_green = atof (substr.substr(x,
+                                                    y - x).c_str());
+
+                                        x = substr.find_first_not_of(" ,", 
+                                                                     y + 1);
+                                        y = substr.find_first_of(" ]", x);
+
+                                        if (x != y)
+                                          {
+                                            new_blue = atof (substr.substr(x, 
+                                                       y - x).c_str());
+                                            have_valid_color = true;
+                                          }
+                                      }
+                                  }
+                              }
+                            else if (c == 'w' || substr == "white")
+                              {
+                                new_red = 1.0;
+                                new_green = 1.0;
+                                new_blue = 1.0;
+                                have_valid_color = true;
+                              }
+                            else if (c == 'k' || substr == "black")
+                              {
+                                new_red = 0.0;
+                                new_green = 0.0;
+                                new_blue = 0.0;
+                                have_valid_color = true;
+                              }
+                            else if (c == 'r' || substr == "red")
+                              {
+                                new_red = 1.0;
+                                new_green = 0.0;
+                                new_blue = 0.0;
+                                have_valid_color = true;
+                              }
+                            else if (c == 'g' || substr == "green")
+                              {
+                                new_red = 0.0;
+                                new_green = 1.0;
+                                new_blue = 0.0;
+                                have_valid_color = true;
+                              }
+                            else if (c == 'b' || substr == "blue")
+                              {
+                                new_red = 0.0;
+                                new_green = 0.0;
+                                new_blue = 1.0;
+                                have_valid_color = true;
+                              }
+                            else if (c == 'y' || substr == "yellow")
+                              {
+                                new_red = 1.0;
+                                new_green = 1.0;
+                                new_blue = 0.0;
+                                have_valid_color = true;
+                              }
+                            else if (c == 'm' || substr == "magenta")
+                              {
+                                new_red = 1.0;
+                                new_green = 0.0;
+                                new_blue = 1.0;
+                                have_valid_color = true;
+                              }
+                            else if (c == 'c' || substr == "cyan")
+                              {
+                                new_red = 0.0;
+                                new_green = 1.0;
+                                new_blue = 1.0;
+                                have_valid_color = true;
+                                break;
+                              }
+
+                            if (have_valid_color)
+                              {
+                                push_font (&lst, fontname, fontweight, 
+                                           fontangle, font_size,
+                                           suboffset, pop_immediate, false,
+                                           new_red, new_green, new_blue);
+                              }
+                            else
+                              ::warning("ft_render: invalid color '%s' 
specified", substr.c_str());
+                          }
+                        else
+                          ::warning("ft_render: invalid color specified");
+
+                        i = k + 1;
+                        continue;
+                      }
+                    else if (str.substr (i + 1, 2).compare ("rm") == 0)
+                      {
+                        // Normal font
+                        push_font (&lst, fontname, "normal", "normal", 
font_size,
+                                   suboffset, pop_immediate);
+                        i += 3;
+                        continue;
+                      }
+                    else if (str.substr (i + 1, 2).compare ("bf") == 0)
+                      {
+                        // Bold font
+                        push_font (&lst, fontname, "bold", fontangle, 
font_size,
+                                   suboffset, pop_immediate);
+                        i += 3;
+                        continue;
+                      }
+                    else if (str.substr (i + 1, 2).compare ("it") == 0)
+                      {
+                        // Italic font
+                        push_font (&lst, fontname, fontweight, "italic", 
font_size,
+                                   suboffset, pop_immediate);
+                        i += 3;
+                        continue;
+                      }
+                    else if (lookup_symbol(str, i, n, sym))
+                      {
+                        // Symbol
+                        push_font (&lst, "symbol", fontweight, fontangle,
+                                   font_size, suboffset, pop_immediate);
+
+                        pop_immediate = true;
+                      }
+                    else
+                      {
+                        // Ok so we'll print a slash
+                        sym = str[i];
+                        n = 1;
+                      }
+                  }
+                  break;
+                case '{' :
+                  {
+                    push_font (&lst, fontname, fontweight, fontangle, 
font_size,
+                               suboffset, pop_immediate, true);
+
+                    pop_immediate = false;
+
+                    i ++;
+                    continue;
+                  }
+                  break;
+                case '}' :
+                  {
+                    pop_font (&lst, suboffset, pop_immediate, true);
+
+                    i ++;
+                    continue;
+                  }
+                  break;
+                case '^' :
+                  {
+                    push_font (&lst, fontname, fontweight, fontangle,
+                               0.60 * font_size, suboffset, pop_immediate);
+
+                    suboffset += 0.666 * font_size;
+                    pop_immediate = true;
+                    
+                    i ++;
+                    continue;
+                  }
+                  break;
+                case '_' :
+                  {
+                    push_font (&lst, fontname, fontweight, fontangle,
+                               0.60 * font_size, suboffset, pop_immediate);
+
+                    suboffset -= 0.333 * font_size;
+                    pop_immediate = true;
+                    
+                    i ++;
+                    continue;
+                  }
+                  break;
+                default :
+                  {
+                    sym = str[i];
+                    n = 1;
+                  }
+                  break;
+                }
+            }
+          else
+            {
+              sym = str[i];
+              n = 1;
+            }
+
+          glyph_index = FT_Get_Char_Index (face, sym);
 
           if (! glyph_index
               || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
-            ::warning ("ft_render: skipping missing glyph for character `%c'",
-                       str[i]);
+            {
+              if (n > 1)
+                ::warning ("ft_render: skipping missing glyph for symbol `%s'",
+                           str.substr(i, n).c_str());
+              else
+                ::warning ("ft_render: skipping missing glyph for character 
`%c'",
+                           str[i]);
+            }
           else
             {
               switch (mode)
                 {
                 case MODE_RENDER:
                   if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
-                    ::warning ("ft_render: unable to render glyph for 
character `%c'",
-                               str[i]);
+                    {
+                      if (n > 1)
+                        ::warning ("ft_render: unable to render glyph for 
symbol `%s'",
+                                   str.substr(i, n).c_str());
+                      else
+                        ::warning ("ft_render: unable to render glyph for 
character `%c'",
+                                   str[i]);
+                    }
                   else
                     {
                       FT_Bitmap& bitmap = face->glyph->bitmap;
@@ -291,12 +871,13 @@
                         {
                           FT_Vector delta;
 
-                          FT_Get_Kerning (face, previous, glyph_index, 
FT_KERNING_DEFAULT, &delta);
+                          FT_Get_Kerning (face, previous, glyph_index,
+                                          FT_KERNING_DEFAULT, &delta);
                           xoffset += (delta.x >> 6);
                         }
 
                       x0 = xoffset+face->glyph->bitmap_left;
-                      y0 = yoffset+face->glyph->bitmap_top;
+                      y0 = yoffset+suboffset+face->glyph->bitmap_top;
                       for (int r = 0; r < bitmap.rows; r++)
                         for (int c = 0; c < bitmap.width; c++)
                           {
@@ -325,7 +906,8 @@
                     {
                       FT_Vector delta;
 
-                      FT_Get_Kerning (face, previous, glyph_index, 
FT_KERNING_DEFAULT, &delta);
+                      FT_Get_Kerning (face, previous, glyph_index,
+                                      FT_KERNING_DEFAULT, &delta);
                       bbox(2) += (delta.x >> 6);
                     }
                   bbox(2) += (face->glyph->advance.x >> 6);
@@ -334,7 +916,8 @@
 
                   if (false /*tight*/)
                     {
-                      desc = face->glyph->metrics.horiBearingY - 
face->glyph->metrics.height;
+                      desc = face->glyph->metrics.horiBearingY 
+                        - face->glyph->metrics.height;
                       asc = face->glyph->metrics.horiBearingY;
                     }
                   else
@@ -343,8 +926,8 @@
                       desc = face->size->metrics.descender;
                     }
 
-                  asc = yoffset + (asc >> 6);
-                  desc = yoffset + (desc >> 6);
+                  asc = yoffset + suboffset + (asc >> 6);
+                  desc = yoffset + suboffset + (desc >> 6);
 
                   if (desc < bbox(1))
                     {
@@ -358,7 +941,18 @@
 
               previous = glyph_index;
             }
+
+          i += n;
+
+          if (pop_immediate)
+            pop_font (&lst, suboffset, pop_immediate);
         }
+
+      // Don't use lst.clear() so that the FreeType fonts are cleaned up
+      // FIXME: Should this be wrapped in an unwind_protect to ensure that 
+      // the FreeType fonts are always cleaned up?
+      while (!lst.empty ())
+        pop_font(&lst, suboffset, pop_immediate);
     }
 }
 
diff --git a/src/txt-eng-ft.h b/src/txt-eng-ft.h
--- a/src/txt-eng-ft.h
+++ b/src/txt-eng-ft.h
@@ -50,6 +50,12 @@
       ROTATION_270 = 3
   };
 
+  enum {
+      INTERPRETER_NONE = 0,  
+      INTERPRETER_TEX = 1,  
+      INTERPRETER_LATEX = 2
+  };
+
 public:
   ft_render (void);
 
@@ -74,9 +80,24 @@
 
   void set_mode (int m);
 
+  bool is_tex (void) { return (interpreter == INTERPRETER_TEX); }
+  bool is_latex (void) { return (interpreter == INTERPRETER_LATEX); }
+
 private:
   int rotation_to_mode (double rotation) const;
 
+  void push_font (void *lst, const std::string &_fontname,
+                  const std::string &_fontweight, 
+                  const std::string &_fontangle,
+                  const double &_font_size,
+                  const int &suboffset, 
+                  const bool &pop_immediate,
+                  bool bracket = false, double _red = -1.0,
+                  double _green = -1.0, double _blue = -1.0);
+
+  void pop_font (void *lst, int &suboffset, bool &pop_immeditate,
+                 bool bracket = false);
+
 private:
   FT_Face face;
   Matrix bbox;
@@ -84,7 +105,12 @@
   int xoffset;
   int yoffset;  
   int mode;
+  int interpreter;
   uint8_t red, green, blue;
+  double font_size;
+  std::string fontname;
+  std::string fontweight;
+  std::string fontangle;
 };
 
 #endif // HAVE_FREETYPE

reply via email to

[Prev in Thread] Current Thread [Next in Thread]