# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1551790276 -3600
#      Tue Mar 05 13:51:16 2019 +0100
# Node ID 4b74ae233ac0102c721c1de7ba77d0e368454158
# Parent  2f847e3e8d6b72f179270d3ba8d13f83ae777d0e
Implement axes and text "fontsmoothing" property (bug #55833)

* base-text-renderer.h (base_text_renderer::set_anti_aliasing): New pure virtual
  method
  
* ft-text-renderer.[h,cc] (text_renderer::m_antialias): New bool data member.
  (ft_text_renderer::set_anti_aliasing): Implement
  base_text_renderer::set_anti_aliasing.
  (is_opaque): New function to determine if a pixel is opaque.
  (ft_text_renderer::process_charater): Render glyph monochrome or antialiased
  depending on m_antialias.
 
* text-renderer.[h,cc] (text_renderer::set_anti_aliasing): New method.

* graphics.in.h (axes::properties::fontsmoothing): Add "u" and corresponding
  updater.
  (text::properties::fontsmoothing,text::properties::update_fontsmoothing): New
  property and and corresponding updater.

* grpahics.cc (text::properties::update_font): Update the text-renderer anti
  aliasing.

* grpahics.cc (opengl_renderer::set_font): Update the text-renderer anti
  aliasing.

* genpropdoc: document properties

diff -r 2f847e3e8d6b -r 4b74ae233ac0 doc/interpreter/genpropdoc.m
--- a/doc/interpreter/genpropdoc.m	Fri Feb 22 07:34:47 2019 +0000
+++ b/doc/interpreter/genpropdoc.m	Tue Mar 05 13:51:16 2019 +0100
@@ -696,12 +696,12 @@
         s.doc = doc_fontsize;
         s.valid = "scalar";
 
+      case "fontsmoothing"
+        s.doc = "Control whether __objname__'s text labels are anti-aliased.";
+
       case "fontunits"
         s.doc = doc_fontunits;
 
-      case "fontsmoothing"
-        s.doc = doc_unused;
-
       case "fontweight"
         s.doc = doc_fontweight;
 
@@ -1082,6 +1082,9 @@
         s.doc = doc_fontname;
         s.valid = valid_string;
 
+      case "fontsmoothing"
+        s.doc = "Control whether __objname__ labels are anti-aliased.";
+
       case "fontsize"
         s.doc = doc_fontsize;
         s.valid = "scalar";
diff -r 2f847e3e8d6b -r 4b74ae233ac0 libinterp/corefcn/base-text-renderer.h
--- a/libinterp/corefcn/base-text-renderer.h	Fri Feb 22 07:34:47 2019 +0000
+++ b/libinterp/corefcn/base-text-renderer.h	Tue Mar 05 13:51:16 2019 +0100
@@ -52,6 +52,9 @@
 
     virtual ~base_text_renderer (void) = default;
 
+    virtual void
+    set_anti_aliasing (bool on) = 0;
+
     virtual Matrix
     get_extent (text_element *elt, double rotation) = 0;
 
diff -r 2f847e3e8d6b -r 4b74ae233ac0 libinterp/corefcn/ft-text-renderer.cc
--- a/libinterp/corefcn/ft-text-renderer.cc	Fri Feb 22 07:34:47 2019 +0000
+++ b/libinterp/corefcn/ft-text-renderer.cc	Tue Mar 05 13:51:16 2019 +0100
@@ -369,7 +369,7 @@
         xoffset (0), line_yoffset (0), yoffset (0), mode (MODE_BBOX),
         color (dim_vector (1, 3), 0), m_do_strlist (false), m_strlist (),
         line_xoffset (0), m_ymin (0), m_ymax (0), m_deltax (0),
-        m_max_fontsize (0)
+        m_max_fontsize (0), m_antialias (true)
     { }
 
     // No copying!
@@ -413,6 +413,8 @@
     Matrix get_extent (const std::string& txt, double rotation,
                        const caseless_str& interpreter);
 
+    void set_anti_aliasing (bool on) { m_antialias = on; };
+
     void set_font (const std::string& name, const std::string& weight,
                    const std::string& angle, double size);
 
@@ -537,6 +539,9 @@
 
     // Used for computing the distance between lines.
     double m_max_fontsize;
+    
+    // Anti-aliasing.
+    bool m_antialias;
 
   };
 
@@ -703,7 +708,17 @@
         break;
       }
   }
-
+  bool is_opaque (const FT_GlyphSlot &glyph, const int x, const int y)
+  {
+    // Borrowed from https://stackoverflow.com/questions/14800827/
+    //    indexing-pixels-in-a-monochrome-freetype-glyph-buffer
+    int pitch = std::abs (glyph->bitmap.pitch);
+    unsigned char *row = &glyph->bitmap.buffer[pitch * y];
+    char cvalue = row[x >> 3];
+    
+    return ((cvalue & (128 >> (x & 7))) != 0);
+  }
+  
   FT_UInt
   ft_text_renderer::process_character (FT_ULong code, FT_UInt previous)
   {
@@ -745,7 +760,9 @@
             switch (mode)
               {
               case MODE_RENDER:
-                if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
+                if (FT_Render_Glyph (face->glyph, (m_antialias
+                                                   ? FT_RENDER_MODE_NORMAL
+                                                   : FT_RENDER_MODE_MONO)))
                   {
                     glyph_index = 0;
                     warn_glyph_render (code);
@@ -777,7 +794,11 @@
                     for (int r = 0; static_cast<unsigned int> (r) < bitmap.rows; r++)
                       for (int c = 0; static_cast<unsigned int> (c) < bitmap.width; c++)
                         {
-                          unsigned char pix = bitmap.buffer[r*bitmap.width+c];
+                          unsigned char pix
+                            = (m_antialias
+                               ? bitmap.buffer[r*bitmap.width+c]
+                               : (is_opaque (face->glyph, c, r) ? 255 : 0));
+                          
                           if (x0+c < 0 || x0+c >= pixels.dim2 ()
                               || y0-r < 0 || y0-r >= pixels.dim3 ())
                             {
diff -r 2f847e3e8d6b -r 4b74ae233ac0 libinterp/corefcn/gl-render.cc
--- a/libinterp/corefcn/gl-render.cc	Fri Feb 22 07:34:47 2019 +0000
+++ b/libinterp/corefcn/gl-render.cc	Tue Mar 05 13:51:16 2019 +0100
@@ -4008,6 +4008,8 @@
   void
   opengl_renderer::set_font (const base_properties& props)
   {
+    bool do_anitalias = props.get ("fontsmoothing").string_value () == "on";
+    txt_renderer.set_anti_aliasing (do_anitalias);
     txt_renderer.set_font (props.get ("fontname").string_value (),
                            props.get ("fontweight").string_value (),
                            props.get ("fontangle").string_value (),
diff -r 2f847e3e8d6b -r 4b74ae233ac0 libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Fri Feb 22 07:34:47 2019 +0000
+++ b/libinterp/corefcn/graphics.cc	Tue Mar 05 13:51:16 2019 +0100
@@ -9182,6 +9182,8 @@
                          get ("fontangle").string_value (),
                          get ("__fontsize_points__").double_value () * dpr);
 
+  txt_renderer.set_anti_aliasing (is_fontsmoothing ());
+
   Matrix c = get_color_rgb ();
   if (! c.isempty ())
     txt_renderer.set_color (c);
@@ -9474,7 +9476,7 @@
 
   // check coplanarity for 3D-faces with more than 3 corners
   int fcmax = idx.rows ();
-  if (fcmax > 3 && vert.columns () > 2 && 
+  if (fcmax > 3 && vert.columns () > 2 &&
       ! (facecolor_is ("none") && edgecolor_is ("none")))
     {
       for (octave_idx_type jj = 0; jj < idx.columns (); jj++)
diff -r 2f847e3e8d6b -r 4b74ae233ac0 libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h	Fri Feb 22 07:34:47 2019 +0000
+++ b/libinterp/corefcn/graphics.in.h	Tue Mar 05 13:51:16 2019 +0100
@@ -3630,8 +3630,8 @@
       radio_property fontangle u , "{normal}|italic"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize u , 10
+      bool_property fontsmoothing u , "on"
       radio_property fontunits SU , "{points}|inches|centimeters|normalized|pixels"
-      bool_property fontsmoothing , "on"
       radio_property fontweight u , "{normal}|bold"
       double_property gridalpha m , 0.15
       radio_property gridalphamode , "{auto}|manual"
@@ -3968,6 +3968,10 @@
       update_font ("fontsize");
       sync_positions ();
     }
+    void update_fontsmoothing (void)
+    {
+      update_font ("fontsmoothing");
+    }
     void update_fontangle (void)
     {
       update_font ("fontangle");
@@ -4347,6 +4351,7 @@
       radio_property fontangle u , "{normal}|italic|oblique"
       string_property fontname u , OCTAVE_DEFAULT_FONTNAME
       double_property fontsize u , 10
+      bool_property fontsmoothing u , "on"
       radio_property fontunits SU , "inches|centimeters|normalized|{points}|pixels"
       radio_property fontweight u , "{normal}|bold"
       radio_property horizontalalignment mu , "{left}|center|right"
@@ -4435,6 +4440,7 @@
     void update_rotation (void) { update_text_extent (); }
     void update_fontname (void) { update_font (); update_text_extent (); }
     void update_fontsize (void) { update_font (); update_text_extent (); }
+    void update_fontsmoothing (void) { update_font (); update_text_extent (); }
 
     void update_color (void)
     {
diff -r 2f847e3e8d6b -r 4b74ae233ac0 libinterp/corefcn/text-renderer.cc
--- a/libinterp/corefcn/text-renderer.cc	Fri Feb 22 07:34:47 2019 +0000
+++ b/libinterp/corefcn/text-renderer.cc	Tue Mar 05 13:51:16 2019 +0100
@@ -87,6 +87,13 @@
   }
 
   void
+  text_renderer::set_anti_aliasing (bool on)
+  {
+    if (ok ())
+      rep->set_anti_aliasing (on);
+  }
+
+  void
   text_renderer::set_font (const std::string& name, const std::string& weight,
                            const std::string& angle, double size)
   {
diff -r 2f847e3e8d6b -r 4b74ae233ac0 libinterp/corefcn/text-renderer.h
--- a/libinterp/corefcn/text-renderer.h	Fri Feb 22 07:34:47 2019 +0000
+++ b/libinterp/corefcn/text-renderer.h	Tue Mar 05 13:51:16 2019 +0100
@@ -62,6 +62,8 @@
     Matrix get_extent (const std::string& txt, double rotation = 0.0,
                        const caseless_str& interpreter = "tex");
 
+    void set_anti_aliasing (bool on);
+    
     void set_font (const std::string& name, const std::string& weight,
                    const std::string& angle, double size);
 
