changeset 16760:8ce0efb93c60

Implemented LaTeX interpreter.
author AndrejLojdl <andrej.lojdl@gmail.com>
date Mon, 29 Jul 2013 14:25:32 +0200
parents dc76e3909d36
children 8ad11cc45df6
files libinterp/interp-core/gl-render.cc libinterp/interp-core/gl-render.h libinterp/interp-core/module.mk libinterp/interp-core/txt-eng-ft.cc libinterp/interp-core/txt-eng-ft.h libinterp/interp-core/txt-eng.h libinterp/interp-core/txt-latex.cc libinterp/interp-core/txt-latex.h libinterp/interp-core/txt-render.cc libinterp/interp-core/txt-render.h libinterp/interpfcn/graphics.cc libinterp/interpfcn/graphics.in.h
diffstat 12 files changed, 597 insertions(+), 110 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/interp-core/gl-render.cc
+++ b/libinterp/interp-core/gl-render.cc
@@ -33,6 +33,7 @@
 #include "oct-refcount.h"
 #include "gl-render.h"
 #include "txt-eng.h"
+#include "txt-render.h"
 #include "txt-eng-ft.h"
 
 #define LIGHT_MODE GL_FRONT_AND_BACK
@@ -2998,10 +2999,8 @@
                                  Matrix& bbox,
                                  int halign, int valign, double rotation)
 {
-#if HAVE_FREETYPE
   text_renderer.text_to_pixels (txt, pixels, bbox,
                                 halign, valign, rotation);
-#endif
 }
 
 Matrix
@@ -3009,7 +3008,6 @@
                             double x, double y, double z,
                             int halign, int valign, double rotation)
 {
-#if HAVE_FREETYPE
   if (txt.empty ())
     return Matrix (1, 4, 0.0);
 
@@ -3030,10 +3028,10 @@
     glDisable (GL_BLEND);
 
   return bbox;
-#else
+  
   ::warning ("render_text: cannot render text, Freetype library not available");
   return Matrix (1, 4, 0.0);
-#endif
+
 }
 
 #endif
--- a/libinterp/interp-core/gl-render.h
+++ b/libinterp/interp-core/gl-render.h
@@ -41,6 +41,7 @@
 #endif
 
 #include "graphics.h"
+#include "txt-render.h"
 #include "txt-eng-ft.h"
 
 class
@@ -51,10 +52,7 @@
   opengl_renderer (void)
     : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (),
     zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (),
-    camera_pos (), camera_dir ()
-#if HAVE_FREETYPE
-    , text_renderer ()
-#endif
+    camera_pos (), camera_dir (), text_renderer ()
   { }
 
   virtual ~opengl_renderer (void) { }
@@ -140,10 +138,7 @@
   opengl_renderer (const opengl_renderer&)
     : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (),
     zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (),
-    camera_pos (), camera_dir ()
-#if HAVE_FREETYPE
-    , text_renderer ()
-#endif
+    camera_pos (), camera_dir (), text_renderer ()
     { }
 
   opengl_renderer& operator = (const opengl_renderer&)
@@ -199,10 +194,8 @@
   // camera information for primitive sorting
   ColumnVector camera_pos, camera_dir;
 
-#if HAVE_FREETYPE
-  // freetype render, used for text rendering
-  ft_render text_renderer;
-#endif
+  // freetype or latex render, used for text rendering
+  text_render text_renderer;
 
 private:
   class patch_tesselator;
--- a/libinterp/interp-core/module.mk
+++ b/libinterp/interp-core/module.mk
@@ -52,6 +52,8 @@
   interp-core/siglist.h \
   interp-core/sparse-xdiv.h \
   interp-core/sparse-xpow.h \
+  interp-core/txt-render.h \
+  interp-core/txt-latex.h \
   interp-core/txt-eng-ft.h \
   interp-core/txt-eng.h \
   interp-core/unwind-prot.h \
@@ -102,6 +104,8 @@
   interp-core/procstream.cc \
   interp-core/sparse-xdiv.cc \
   interp-core/sparse-xpow.cc \
+  interp-core/txt-render.cc \
+  interp-core/txt-latex.cc \
   interp-core/txt-eng-ft.cc \
   interp-core/unwind-prot.cc \
   interp-core/xdiv.cc \
--- a/libinterp/interp-core/txt-eng-ft.cc
+++ b/libinterp/interp-core/txt-eng-ft.cc
@@ -201,8 +201,8 @@
                 }
               else
                 ::warning ("could not match any font: %s-%s-%s-%g",
-                         name.c_str (), weight.c_str (), angle.c_str (),
-                         size);
+                           name.c_str (), weight.c_str (), angle.c_str (),
+                           size);
 
               if (match)
                 FcPatternDestroy (match);
@@ -238,10 +238,10 @@
 // ---------------------------------------------------------------------------
 
 ft_render::ft_render (void)
-    : text_processor (), face (0), bbox (1, 4, 0.0),
-      xoffset (0), yoffset (0), multiline_halign (0),
-      multiline_align_xoffsets (), mode (MODE_BBOX),
-      red (0), green (0), blue (0)
+: text_processor (), face (0), bbox (1, 4, 0.0),
+  xoffset (0), yoffset (0), multiline_halign (0),
+  multiline_align_xoffsets (), mode (MODE_BBOX),
+  red (0), green (0), blue (0)
 {
 }
 
@@ -324,7 +324,7 @@
 
           if (str[i] != '\n'
               && (! glyph_index
-              || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)))
+                  || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)))
             gripe_missing_glyph (str[i]);
           else
             {
@@ -333,17 +333,17 @@
                 case MODE_RENDER:
                   if (str[i] == '\n')
                     {
-                    glyph_index = FT_Get_Char_Index (face, ' ');
-                    if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
-                      {
-                        gripe_missing_glyph (' ');
-                      }
-                    else
-                      {
-                        line_index++;
-                        xoffset = multiline_align_xoffsets[line_index];
-                        yoffset -= (face->size->metrics.height >> 6);
-                      }
+                      glyph_index = FT_Get_Char_Index (face, ' ');
+                      if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
+                        {
+                          gripe_missing_glyph (' ');
+                        }
+                      else
+                        {
+                          line_index++;
+                          xoffset = multiline_align_xoffsets[line_index];
+                          yoffset -= (face->size->metrics.height >> 6);
+                        }
                     }
                   else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
                     {
@@ -400,66 +400,66 @@
                       glyph_index = FT_Get_Char_Index (face, ' ');
                       if (! glyph_index
                           || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
-                      {
-                        gripe_missing_glyph (' ');
-                      }
-                    else
-                      {
-                        multiline_align_xoffsets.push_back (box_line_width);
-                        // Reset the pixel width for this newline, so we don't
-                        // allocate a bounding box larger than the horizontal
-                        // width of the multi-line
-                        box_line_width = 0;
-                        bbox(1) -= (face->size->metrics.height >> 6);
-                      }
+                        {
+                          gripe_missing_glyph (' ');
+                        }
+                      else
+                        {
+                          multiline_align_xoffsets.push_back (box_line_width);
+                          // Reset the pixel width for this newline, so we don't
+                          // allocate a bounding box larger than the horizontal
+                          // width of the multi-line
+                          box_line_width = 0;
+                          bbox(1) -= (face->size->metrics.height >> 6);
+                        }
                     }
                   else
                     {
-                    // width
-                    if (previous)
-                      {
-                        FT_Vector delta;
+                      // width
+                      if (previous)
+                        {
+                          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);
 
-                        box_line_width += (delta.x >> 6);
-                      }
+                          box_line_width += (delta.x >> 6);
+                        }
 
-                    box_line_width += (face->glyph->advance.x >> 6);
+                      box_line_width += (face->glyph->advance.x >> 6);
 
-                    int asc, desc;
+                      int asc, desc;
 
-                    if (false /*tight*/)
-                      {
-                        desc = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
-                        asc = face->glyph->metrics.horiBearingY;
-                      }
-                    else
-                      {
-                        asc = face->size->metrics.ascender;
-                        desc = face->size->metrics.descender;
-                      }
+                      if (false /*tight*/)
+                        {
+                          desc = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
+                          asc = face->glyph->metrics.horiBearingY;
+                        }
+                      else
+                        {
+                          asc = face->size->metrics.ascender;
+                          desc = face->size->metrics.descender;
+                        }
 
-                    asc = yoffset + (asc >> 6);
-                    desc = yoffset + (desc >> 6);
+                      asc = yoffset + (asc >> 6);
+                      desc = yoffset + (desc >> 6);
 
-                    if (desc < bbox(1))
-                      {
-                        bbox(3) += (bbox(1) - desc);
-                        bbox(1) = desc;
-                      }
-                    if (asc > (bbox(3)+bbox(1)))
-                      bbox(3) = asc-bbox(1);
-                    if (bbox(2) < box_line_width)
-                      bbox(2) = box_line_width;
-                  }
+                      if (desc < bbox(1))
+                        {
+                          bbox(3) += (bbox(1) - desc);
+                          bbox(1) = desc;
+                        }
+                      if (asc > (bbox(3)+bbox(1)))
+                        bbox(3) = asc-bbox(1);
+                      if (bbox(2) < box_line_width)
+                        bbox(2) = box_line_width;
+                    }
                   break;
                 }
-                if (str[i] == '\n')
-                  previous = 0;
-                else
-                  previous = glyph_index;
+              if (str[i] == '\n')
+                previous = 0;
+              else
+                previous = glyph_index;
             }
         }
       if (mode == MODE_BBOX)
@@ -469,15 +469,15 @@
 
           for (unsigned int i = 0; i < multiline_align_xoffsets.size (); i++)
             {
-            /* Center align */
-            if (multiline_halign == 1)
-              multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i])/2;
-            /* Right align */
-            else if (multiline_halign == 2)
-              multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i]);
-            /* Left align */
-            else
-              multiline_align_xoffsets[i] = 0;
+              /* Center align */
+              if (multiline_halign == 1)
+                multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i])/2;
+              /* Right align */
+              else if (multiline_halign == 2)
+                multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i]);
+              /* Left align */
+              else
+                multiline_align_xoffsets[i] = 0;
             }
         }
     }
--- a/libinterp/interp-core/txt-eng-ft.h
+++ b/libinterp/interp-core/txt-eng-ft.h
@@ -33,10 +33,11 @@
 #include <dMatrix.h>
 #include <uint8NDArray.h>
 #include "txt-eng.h"
+#include "txt-render.h"
 
 class
 OCTINTERP_API
-ft_render : public text_processor
+ft_render : public base_text_render , public text_processor 
 {
 public:
   enum {
--- a/libinterp/interp-core/txt-eng.h
+++ b/libinterp/interp-core/txt-eng.h
@@ -54,7 +54,7 @@
 {
 public:
   text_element_string (const std::string& s = "")
-      : text_element (), str (s) { }
+    : text_element (), str (s) { }
 
   ~text_element_string (void) { }
 
@@ -72,12 +72,12 @@
 class
 OCTINTERP_API
 text_element_list :
-    public text_element,
-    public octave_base_list<text_element *>
+  public text_element,
+  public octave_base_list<text_element *>
 {
 public:
   text_element_list (void)
-      : text_element (), octave_base_list<text_element*> () { }
+    : text_element (), octave_base_list<text_element*> () { }
 
   ~text_element_list (void)
     {
@@ -98,7 +98,7 @@
 {
 public:
   text_subscript_element (void)
-      : text_element_list () { }
+    : text_element_list () { }
 
   ~text_subscript_element (void) { }
 
@@ -111,7 +111,7 @@
 {
 public:
   text_superscript_element (void)
-      : text_element_list () { }
+    : text_element_list () { }
 
   ~text_superscript_element (void) { }
 
@@ -149,7 +149,7 @@
 };
 
 #define TEXT_ELEMENT_ACCEPT(cls) \
-inline void \
+  inline void \
 cls::accept (text_processor& p) \
 { p.visit (*this); }
 
@@ -158,9 +158,9 @@
 TEXT_ELEMENT_ACCEPT(text_subscript_element)
 TEXT_ELEMENT_ACCEPT(text_superscript_element)
 
-class
-OCTINTERP_API
-text_parser
+     class
+     OCTINTERP_API
+     text_parser
 {
 public:
   text_parser (void) { }
new file mode 100644
--- /dev/null
+++ b/libinterp/interp-core/txt-latex.cc
@@ -0,0 +1,190 @@
+/*
+
+Copyright (C) 2013 Andrej Lojdl
+
+This file is part of Octave.
+
+Octave 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 3 of the License, or (at your
+option) any later version.
+
+Octave 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 Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include"oct.h"
+#include"octave.h"
+#include"parse.h"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cstdlib>
+#include "txt-latex.h"
+
+
+latex_render::latex_render (void)
+: bbox (1, 4, 0.0),red (0),green (0),blue (0) 
+{
+}
+
+latex_render::~latex_render (void)
+{
+}
+
+void 
+latex_render::adapter (const std::string& txt)
+{
+  std::ofstream file;
+
+  file.open ("default.tex");
+  /* Adding LaTeX configuration lines to this file */
+  file << "\\documentclass[fleqn]{article} \n\\usepackage{amsmath} \n\\usepackage{color} \n\\pagestyle{empty}	\n\\begin{document} \n\t\\normalsize \n\t\t\\begin{displaymath}\n\t\t\t";
+  file << txt;
+  file << "\n\t\t\\end{displaymath} \n\\end{document}";
+  file.close();	
+}
+
+uint8NDArray 
+latex_render::render (void)
+{
+  int cmd,width,height,max_color;
+  std::string comment;
+  uint8NDArray data;
+  std::ifstream file;
+  char magic_number[2],skip;
+
+  // Checking if command processor is available //
+  if(system( NULL ))
+    {
+      /* Probably we want to delete files after they are no longer needed - checking if user have all programs will be done soewhere else */
+
+      // .tex -> .dvi
+      cmd = system ("latex default.tex");
+
+      // .dvi -> .eps
+      cmd = system ("dvips default.dvi -E -o default.eps");
+
+      // .eps -> .png 
+      cmd = system ("gs -dEPSCrop -dSAFER -dBATCH -dNOPAUSE -r600 -sDEVICE=ppm -sOutputFile=default.ppm \"default.eps\"");
+
+      // removing temporary files 
+      cmd = remove ("default.tex");
+      cmd = remove ("default.dvi");
+      cmd = remove ("default.log");
+      cmd = remove ("default.aux");
+
+      // read data from PPM file to Array for OpenGL rendering
+      file.open("default.ppm");
+      file>>magic_number>>skip;
+      std::getline(file, comment);
+      file>>width>>height;
+      data = uint8NDArray (dim_vector (4, height, width), static_cast<uint8_t> (0));
+
+      // reading the data, row by row 
+      for(int j=0; j<width; j++)
+        {
+          for(int i=0; i<height; i++)
+            {
+              file>>data(0,i,j); //red
+              file>>data(1,i,j); //green
+              file>>data(2,i,j); //blue
+              data(3,i,j) = 0;   //alpha -> transparent
+            }
+        }
+      file.close();     
+
+      // remove PPM file
+      cmd = remove("default.ppm");
+    }
+  else
+    exit (EXIT_FAILURE);
+  return data; 
+}
+
+Matrix 
+latex_render::get_bbox (void)
+{
+  std::ifstream file;
+  std::string comment;
+  double tmp, scaling = 1.36;
+  Matrix bounding_box (1, 4, 0.0);
+  int counter = 0,x,y, cmd;
+
+  file.open("default.eps");
+  char character = 0,string[20];
+  std::getline(file,comment);
+  std::getline(file,comment);
+  std::getline(file,comment);
+  std::getline(file,comment);
+
+  // For the first moment, bounding box is set so the fontsize will be 12pt
+  file>>string;
+  file>>x;
+
+  file>>y;
+  file>>tmp;
+  x=tmp-x;
+
+  file>>tmp;
+  y=tmp-y;
+  bounding_box(0) = 0;
+  bounding_box(1) = 0;
+  bounding_box(2) = x*scaling;
+  bounding_box(3) = y*scaling;
+  file.close();
+
+  // remove EPS file is no longer needed
+  cmd = remove ("default.eps");
+
+  return bounding_box;
+}
+
+void
+latex_render::set_font (const std::string& name, const std::string& weight,
+                        const std::string& angle, double size)
+{}
+
+void
+latex_render::set_color (Matrix c) {}
+
+void
+latex_render::text_to_pixels (const std::string& txt,
+                              uint8NDArray& pixels, Matrix& bbox,
+                              int halign, int valign, double rotation)
+{
+  adapter (txt);
+  pixels = render();
+  bbox = get_bbox();	
+}
+
+Matrix
+latex_render::get_extent (text_element *elt, double rotation)
+{
+  Matrix extent (1, 2, 0.0);
+
+  return extent;
+}
+
+
+Matrix 
+latex_render::get_extent (const std::string& txt, double rotation)
+{
+  text_element *elt = text_parser_none().parse(txt);
+  Matrix extent = get_extent (elt, rotation);
+  delete elt;
+
+  return extent;
+}
new file mode 100644
--- /dev/null
+++ b/libinterp/interp-core/txt-latex.h
@@ -0,0 +1,68 @@
+/*
+
+Copyright (C) 2013 Andrej Lojdl
+
+This file is part of Octave.
+
+Octave 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 3 of the License, or (at your
+option) any later version.
+
+Octave 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 Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if ! defined (txt_latex_h)
+#define txt_latex_h 1
+
+#include <dMatrix.h>
+#include <uint8NDArray.h>
+#include "txt-render.h"
+
+class 
+OCTINTERP_API
+latex_render : public base_text_render
+{
+public:
+  latex_render (void);
+
+  ~latex_render (void);  
+
+  void set_font (const std::string& name, const std::string& weight,
+                 const std::string& angle, double size);
+
+  void set_color (Matrix c);
+
+  void text_to_pixels (const std::string& txt,
+                       uint8NDArray& pixels_, Matrix& bbox,
+                       int halign, int valign, double rotation);
+
+  Matrix get_extent (text_element *elt, double rotation = 0.0);
+  Matrix get_extent (const std::string& txt, double rotation = 0.0);
+
+  /* remaining methods of latex_text_renderer class */
+
+  // method making TEX file from text (input string) 
+  void adapter (const std::string& txt);
+
+  // method rendering text TEX -> DVI -> EPS -> PNG 
+  uint8NDArray render (void);
+
+  // method extracting bounding box from EPS file
+  Matrix get_bbox (void);
+
+private:
+  Matrix bbox;
+  uint8NDArray pixels;
+  uint8_t red, green, blue;
+
+};
+#endif
new file mode 100644
--- /dev/null
+++ b/libinterp/interp-core/txt-render.cc
@@ -0,0 +1,75 @@
+/*
+
+Copyright (C) 2013 Andrej Lojdl
+
+This file is part of Octave.
+
+Octave 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 3 of the License, or (at your
+option) any later version.
+
+Octave 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 Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <dMatrix.h>
+#include <uint8NDArray.h>
+#include <string>
+#include "txt-render.h"
+#include "txt-latex.h"
+#include "txt-eng-ft.h"
+#include "oct-refcount.h"
+
+dummy_render::dummy_render (void) {}
+dummy_render::~dummy_render (void) {}
+
+void
+dummy_render::set_font (const std::string& name, const std::string& weight,
+                        const std::string& angle, double size)
+{}
+
+void
+dummy_render::set_color (Matrix c) {}
+
+void
+dummy_render::text_to_pixels (const std::string& txt,
+                              uint8NDArray& pixels, Matrix& bbox,
+                              int halign, int valign, double rotation)
+{}
+
+Matrix
+dummy_render::get_extent (text_element *elt, double rotation) {}
+
+
+Matrix 
+dummy_render::get_extent (const std::string& txt, double rotation) {}
+
+
+
+base_text_render 
+*text_render::make_text_render (const caseless_str& s)
+{
+  if (s.compare ("latex"))
+    rep = new latex_render ();
+  else
+    {
+#if HAVE_FREETYPE
+      rep = new ft_render ();
+#else
+      rep = new dummy_render ();
+#endif
+    }
+  return rep;
+}
new file mode 100644
--- /dev/null
+++ b/libinterp/interp-core/txt-render.h
@@ -0,0 +1,153 @@
+/*
+
+Copyright (C) 2013 Andrej Lojdl
+
+This file is part of Octave.
+
+Octave 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 3 of the License, or (at your
+option) any later version.
+
+Octave 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 Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if ! defined(txt_render_h)
+#define txt_render_h 1
+
+#include <dMatrix.h>
+#include <uint8NDArray.h>
+#include <string>
+#include "txt-eng.h"
+#include "caseless-str.h"
+
+
+class OCTINTERP_API text_render;
+
+class 
+OCTINTERP_API
+base_text_render
+{
+public:
+  friend class text_render;
+
+  base_text_render (void) : count(1) { }
+
+  virtual ~base_text_render (void) { }
+
+  virtual void set_font (const std::string& name, const std::string& weight,
+                         const std::string& angle, double size) = 0;
+
+  virtual void set_color (Matrix c) = 0;
+
+  virtual void text_to_pixels (const std::string& txt,
+                               uint8NDArray& pixels_, Matrix& bbox,
+                               int halign, int valign, double rotation) = 0;
+
+  virtual Matrix get_extent (text_element *elt, double rotation = 0.0) = 0;
+  virtual Matrix get_extent (const std::string& txt, double rotation = 0.0) = 0;
+
+private: 
+  octave_refcount<int> count;        
+};
+
+/* if user don't have FREETYPE library we use this dummy class */
+
+class
+OCTINTERP_API
+dummy_render : public base_text_render
+{
+  dummy_render (void);
+
+  ~dummy_render (void);
+
+  void set_font (const std::string& name, const std::string& weight,
+                 const std::string& angle, double size);
+
+  void set_color (Matrix c);
+
+  void text_to_pixels (const std::string& txt,
+                       uint8NDArray& pixels_, Matrix& bbox,
+                       int halign, int valign, double rotation);
+
+  Matrix get_extent (text_element *elt, double rotation = 0.0);
+  Matrix get_extent (const std::string& txt, double rotation = 0.0);
+};
+
+
+class
+OCTINTERP_API
+text_render
+{
+public:
+  text_render (const caseless_str& s = caseless_str ())
+    : rep (make_text_render(s)) { }
+
+  text_render (const text_render& e) 
+    : rep (e.rep)
+    {
+      rep->count++;
+    } 
+
+  ~text_render ( void )
+    {
+      if( rep && --rep->count == 0 )
+        {
+          delete rep;
+        }
+    }
+
+  text_render& operator = (const text_render& e)
+    {
+      if (rep != e.rep)
+        {
+          if (rep && --rep->count == 0)
+            delete rep;
+
+          rep = e.rep;
+          if (rep)
+            rep->count++;
+        }
+      return *this;
+    }
+
+  void set_font (const std::string& name, const std::string& weight,
+                 const std::string& angle, double size) 
+    { 
+      rep->set_font (name, weight, angle, size); 
+    }
+
+
+  void set_color (Matrix c) { rep->set_color (c); }
+
+  void text_to_pixels (const std::string& txt,
+                       uint8NDArray& pixels_, Matrix& bbox,
+                       int halign, int valign, double rotation) 
+    {
+      rep->text_to_pixels (txt, pixels_, bbox, halign, valign, rotation);
+    }
+
+  Matrix get_extent (text_element *elt, double rotation = 0.0)
+    {
+      return rep->get_extent (elt, rotation);
+    }
+
+  Matrix get_extent (const std::string& txt, double rotation = 0.0)
+    {
+      return rep->get_extent (txt, rotation);
+    }
+
+
+private:
+  base_text_render *rep;
+  base_text_render *make_text_render (const caseless_str& s);
+};
+#endif
--- a/libinterp/interpfcn/graphics.cc
+++ b/libinterp/interpfcn/graphics.cc
@@ -57,6 +57,7 @@
 #include "parse.h"
 #include "toplev.h"
 #include "txt-eng-ft.h"
+#include "txt-render.h"
 #include "unwind-prot.h"
 
 // forward declarations
@@ -7139,6 +7140,7 @@
 void
 text::properties::update_font (void)
 {
+
 #ifdef HAVE_FREETYPE
 #ifdef HAVE_FONTCONFIG
   renderer.set_font (get ("fontname").string_value (),
@@ -7153,7 +7155,8 @@
 void
 text::properties::update_text_extent (void)
 {
-#ifdef HAVE_FREETYPE
+
+   text_render r (get_interpreter ());
 
   int halign = 0, valign = 0;
 
@@ -7178,8 +7181,9 @@
   octave_value string_prop = get_string ();
 
   string_vector sv = string_prop.all_strings ();
-
-  renderer.text_to_pixels (sv.join ("\n"), pixels, bbox,
+  
+  
+  r.text_to_pixels (sv.join ("\n"), pixels, bbox,
                            halign, valign, get_rotation ());
   /* The bbox is relative to the text's position.
      We'll leave it that way, because get_position () does not return
@@ -7187,7 +7191,7 @@
      Conversion to proper coordinates is performed in get_extent. */
   set_extent (bbox);
 
-#endif
+
 
   if (autopos_tag_is ("xlabel") || autopos_tag_is ("ylabel") ||
       autopos_tag_is ("zlabel") || autopos_tag_is ("title"))
@@ -7619,7 +7623,7 @@
 #ifdef HAVE_FREETYPE
 
   text_element *elt;
-  ft_render text_renderer;
+  text_render text_renderer;
   Matrix box;
 
   // FIXME: parsed content should be cached for efficiency
--- a/libinterp/interpfcn/graphics.in.h
+++ b/libinterp/interpfcn/graphics.in.h
@@ -44,6 +44,7 @@
 #include "oct-mutex.h"
 #include "oct-refcount.h"
 #include "ov.h"
+#include "txt-render.h"
 #include "txt-eng-ft.h"
 
 // FIXME -- maybe this should be a configure option?
@@ -3727,7 +3728,7 @@
 
 #if HAVE_FREETYPE
     // freetype renderer, used for calculation of text (tick labels) size
-    ft_render text_renderer;
+    text_render text_renderer;
 #endif
 
     void set_text_child (handle_property& h, const std::string& who,
@@ -4308,7 +4309,7 @@
     const uint8NDArray& get_pixels (void) const { return pixels; }
 #if HAVE_FREETYPE
     // freetype renderer, used for calculation of text size
-    ft_render renderer;
+    text_render renderer;
 #endif
 
   protected: