Index: FL/Fl_Gl_Window_Driver.H
===================================================================
--- FL/Fl_Gl_Window_Driver.H	(revision 12166)
+++ FL/Fl_Gl_Window_Driver.H	(working copy)
@@ -4,7 +4,7 @@
 // Definition of classes  Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device
 // for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 2016 by Bill Spitzak and others.
+// Copyright 2016-2017 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -49,6 +49,7 @@
   virtual ~Fl_Gl_Window_Driver() {}
   static Fl_Gl_Window_Driver *newGlWindowDriver(Fl_Gl_Window *w);
   static Fl_Gl_Window_Driver *global();
+  static void remove_displaylist_fonts();
   virtual float pixels_per_unit() {return 1;}
   virtual void before_show(int& need_redraw) {}
   virtual void after_show(int need_redraw) {}
@@ -79,10 +80,15 @@
   virtual void gl_visual(Fl_Gl_Choice*); // support for Fl::gl_visual() function
   virtual void gl_start() {} // support for gl_start() function
   virtual void* GetProcAddress(const char *procName); // support for glutGetProcAddress()
-  virtual void draw_string(const char* str, int n); // support for gl_draw()
-  virtual void get_list(Fl_Font_Descriptor* fd, int r) {} // support for gl_draw() without textures
-  virtual void gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) {} // support for gl_font() without textures
-  virtual int overlay_color(Fl_Color i) {return 0;} // support for gl_color() with HAVE_GL_OVERLAY
+  // support for texture-based string drawing with the GL_EXT_texture_rectangle extension
+  virtual uchar *draw_string_to_rgba(const char *str, int n,  int w, int h,  int scale, void **pdata);
+  virtual void dispose_after_draw(void *data);
+  // support for backup string drawing method when extension is absent
+  virtual void draw_string(const char* str, int n);
+  virtual void get_list(Fl_Font_Descriptor* fd, int r) {}
+  virtual void gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) {}
+  // support for gl_color() with HAVE_GL_OVERLAY
+  virtual int overlay_color(Fl_Color i) {return 0;}
 };
 
 #ifdef FL_CFG_GFX_QUARTZ
@@ -111,7 +117,6 @@
   virtual void make_overlay_current();
   virtual void redraw_overlay();
   virtual void gl_start();
-  virtual void draw_string(const char* str, int n);
   static NSOpenGLContext* create_GLcontext_for_window(NSOpenGLPixelFormat *pixelformat, NSOpenGLContext *shared_ctx, Fl_Window *window);
   static NSOpenGLPixelFormat *mode_to_NSOpenGLPixelFormat(int mode, const int*); // uses Objective-c
   static void GLcontext_update(NSOpenGLContext*); // uses Objective-c
@@ -118,6 +123,9 @@
   static void GLcontext_release(NSOpenGLContext*); // uses Objective-c
   static void GLcontext_makecurrent(NSOpenGLContext*); // uses Objective-c
   static void GL_cleardrawable(void); // uses Objective-c
+  virtual uchar *draw_string_to_rgba(const char *str, int n,  int w, int h, int scale, void **pdata);
+  virtual void dispose_after_draw(void *data);
+  virtual void draw_string(const char* str, int n);
 };
 #endif // FL_CFG_GFX_QUARTZ
 
Index: FL/gl.h
===================================================================
--- FL/gl.h	(revision 12166)
+++ FL/gl.h	(working copy)
@@ -89,16 +89,8 @@
 FL_EXPORT void gl_draw(const char*, int n, float x, float y);
 FL_EXPORT void gl_draw(const char*, int x, int y, int w, int h, Fl_Align);
 FL_EXPORT void gl_measure(const char*, int& x, int& y);
-#ifdef __APPLE__ // PORTME: OpenGL platform texture
 extern FL_EXPORT void gl_texture_pile_height(int max);
 extern FL_EXPORT int gl_texture_pile_height();
-#elif defined(WIN32)
-  // not needed
-#elif defined(FL_PORTING)
-#  pragma message "FL_PORTING: define functions to control OpenGL texture pile height if supported"
-#else // X11
-  // not needed
-#endif
 
 FL_EXPORT void gl_draw_image(const uchar *, int x,int y,int w,int h, int d=3, int ld=0);
 
Index: FL/gl_draw.H
===================================================================
--- FL/gl_draw.H	(revision 12166)
+++ FL/gl_draw.H	(working copy)
@@ -18,7 +18,7 @@
 
 #include "gl.h"
 
-extern FL_EXPORT void gl_remove_displaylist_fonts();
+//extern FL_EXPORT void gl_remove_displaylist_fonts();
 
 
 //
Index: src/Fl_Gl_Choice.cxx
===================================================================
--- src/Fl_Gl_Choice.cxx	(revision 12166)
+++ src/Fl_Gl_Choice.cxx	(working copy)
@@ -24,7 +24,6 @@
 #  include "Fl_Gl_Choice.H"
 #  include <FL/Fl_Gl_Window.H>
 #  include <FL/Fl_Gl_Window_Driver.H>
-#  include <FL/gl_draw.H>
 #  include "flstring.h"
 #  include <FL/fl_utf8.h>
 
@@ -53,7 +52,7 @@
       break;
     }
   }
-  if (!nContext) gl_remove_displaylist_fonts();
+  if (!nContext) Fl_Gl_Window_Driver::remove_displaylist_fonts();
 }
 
 static Fl_Gl_Choice *first;
@@ -75,7 +74,6 @@
 
 
 #ifdef FL_CFG_GFX_QUARTZ
-extern void gl_texture_reset();
 
 Fl_Gl_Choice *Fl_Cocoa_Gl_Window_Driver::find(int m, const int *alistp)
 {
@@ -92,9 +90,6 @@
 GLContext Fl_Cocoa_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) {
   GLContext context, shared_ctx = 0;
   if (context_list && nContext) shared_ctx = context_list[0];
-  // resets the pile of string textures used to draw strings
-  // necessary before the first context is created
-  if (!shared_ctx) gl_texture_reset();
   context = create_GLcontext_for_window((NSOpenGLPixelFormat*)g->pixelformat, shared_ctx, window);
   if (!context) return 0;
   add_context(context);
Index: src/gl_draw.cxx
===================================================================
--- src/gl_draw.cxx	(revision 12166)
+++ src/gl_draw.cxx	(working copy)
@@ -3,7 +3,7 @@
 //
 // OpenGL drawing support routines for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 1998-2016 by Bill Spitzak and others.
+// Copyright 1998-2017 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -19,9 +19,55 @@
 // Functions from <FL/gl.h>
 // See also Fl_Gl_Window and gl_start.cxx
 
+/*                          IMPLEMENTATION NOTES
+ Text drawing to an OpenGL scene is implemented using textures in a cross-platform way.
+ This implementation requires the GL_EXT_texture_rectangle OpenGL extension, and
+ draws text to an offscreen buffer using regular FLTK text support.
+ If GL_EXT_texture_rectangle is not detected at run-time, text is drawn using a 
+ backup, platform-specific procedure.
+ 
+ Text drawn to OpenGL using textures allows any font and any UTF script, including 
+ right-to-left ones, provided it's supported by regular FLTK text functions.
+ Textures representing drawn text are memorized in a fifo list to avoid recomputing textures
+ at each redraw. The size of this list can be increased by the user when a large number of
+ text strings are simultaneously displayed (see gl_texture_pile_height functions).
+ Text drawn using the backup mechanism may be restricted to specific sets of characters.
+ 
+ Function draw_string_using_texture() pilots the cross-platform,
+ texture-based text drawing procedure. Part of this procedure consists in drawing text
+ to a premultiplied, RGBA byte array. Besides the cross-platform implementation in
+ function Fl_Gl_Window_Driver::draw_string_to_rgba(), a Mac OS-specific implementation
+ in Fl_Cocoa_Gl_Window_Driver::draw_string_to_rgba() takes advantage of the fact that
+ offscreen buffers have an alpha layer on this platform.
+ 
+ Class gl_texture_fifo manages the fifo list of precomputed textures. Each time a string
+ is drawn, this list is searched for the same text, font and size. If found, the precomputed
+ texture is used. If not a new texture is computed.
+ 
+ The first call to gl_font() checks for the availability of GL_EXT_texture_rectangle.
+ When it's not available, all text is drawn using Fl_Gl_Window_Driver::draw_string(),
+ or its platform-specific implementation Fl_Cocoa_Gl_Window_Driver::draw_string().
+ 
+ The GL_EXT_texture_rectangle extension is widely available on graphics cards.
+ It's unavailable on very old Apple hardware, and with VirtualBox for WIN32 guest
+ and MacOS host.
+ 
+ The backup text drawing method Fl_Gl_Window_Driver::draw_string() contains
+ platform-dependent parts implemented in Fl_XXX_Gl_Window_Driver::get_list() and
+ Fl_XXX_Gl_Window_Driver::gl_bitmap_font() for the X11 and WIN32 platforms.
+ These use glXUseXFont() and wglUseFontBitmapsW() which are platform-specific.
+ These methods allow to use all fonts, sizes and characters natively supported
+ by individual fonts.
+ 
+ The backup text drawing method for the MacOS platform Fl_Cocoa_Gl_Window_Driver::draw_string()
+ uses glutStrokeString(). A single font is used, but the fontsize can be changed. 
+ This method draws ASCII characters only.
+ */
+
+
 #include "config_lib.h"
 #if defined(FL_PORTING)
-#  pragma message "FL_PORTING: implement OpenGL text rendering here"
+#  pragma message "FL_PORTING: The cross-platform implementation of OpenGL text rendering may be enough"
 #endif
 
 #include "flstring.h"
@@ -29,13 +75,18 @@
 
 #include <FL/Fl.H>
 #include <FL/gl.h>
-#include <FL/gl_draw.H>
+#include <FL/glu.h>  // for gluUnProject()
 #include <FL/fl_draw.H>
 #include <FL/Fl_Gl_Window_Driver.H>
 
 #if defined(FL_CFG_GFX_QUARTZ)
 #include "drivers/Quartz/Fl_Font.H"
+#include <FL/glut.H> // for glutStrokeString() and glutStrokeWidth()
 #  define GENLISTSIZE 0
+#if  MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
+#  include <OpenGL/glext.h>
+#  define GL_TEXTURE_RECTANGLE_ARB GL_TEXTURE_RECTANGLE_EXT
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED
 
 #elif defined(FL_CFG_GFX_GDI)
 #include "drivers/GDI/Fl_Font.H"
@@ -43,6 +94,8 @@
 
 #elif defined(FL_CFG_GFX_XLIB)
 #include "drivers/Xlib/Fl_Font.H"
+#include <FL/x.H>
+#include <GL/glx.h>
 #if USE_XFT
 #  define GENLISTSIZE 256
 #else
@@ -49,10 +102,13 @@
 #  define GENLISTSIZE 0x10000
 #endif // USE_XFT
 
+#endif // FL_CFG_GFX_QUARTZ
+
+#ifndef GL_TEXTURE_RECTANGLE_ARB // can be undefined under WIN32+mingw
+#define GL_TEXTURE_RECTANGLE_ARB        0x84F5
+#define GL_UNSIGNED_INT_8_8_8_8_REV     0x8367
 #endif
-#include <FL/fl_utf8.h>
 
-
 /** Returns the current font's height */
 int   gl_height() {return fl_height();}
 /** Returns the current font's descent */
@@ -65,6 +121,9 @@
 double gl_width(uchar c) {return fl_width(c);}
 
 static Fl_Font_Descriptor *gl_fontsize;
+static int has_texture_rectangle = -1; // 1 means GL_EXT_texture_rectangle is available, -1 means unchecked yet
+static void gl_texture_reset();
+static void draw_string_using_texture(const char* str, int n);
 
 
 /**
@@ -71,17 +130,39 @@
   Sets the current OpenGL font to the same font as calling fl_font()
   */
 void  gl_font(int fontid, int size) {
+  if (has_texture_rectangle == -1) {
+    const char* vs= (const char*)glGetString(GL_VERSION);
+    int version;
+    sscanf(vs, "%d", &version);
+    if (version >= 3) has_texture_rectangle = 1;
+    else has_texture_rectangle =
+      strstr((const char*)glGetString(GL_EXTENSIONS), "GL_EXT_texture_rectangle") != NULL ? 1 : 0;
+  }
   fl_font(fontid, size);
   Fl_Font_Descriptor *fl_fontsize = fl_graphics_driver->font_descriptor();
-  Fl_Gl_Window_Driver::global()->gl_bitmap_font(fl_fontsize);
+  if (!has_texture_rectangle) {
+    Fl_Gl_Window_Driver::global()->gl_bitmap_font(fl_fontsize);
+  }
   gl_fontsize = fl_fontsize;
 }
 
-#if defined(FL_CFG_GFX_QUARTZ) || defined(FL_CFG_GFX_GDI) || defined(FL_CFG_GFX_XLIB)
 
-void gl_remove_displaylist_fonts()
+/**
+ Draws an array of n characters of the string in the current font
+ at the current position.
+ \see  gl_texture_pile_height(int)
+ */
+void gl_draw(const char* str, int n) {
+  if (has_texture_rectangle == -1) { // avoid undefined font
+    gl_font(FL_HELVETICA, FL_NORMAL_SIZE);
+  }
+  if (has_texture_rectangle) draw_string_using_texture(str, n);
+  else Fl_Gl_Window_Driver::global()->draw_string(str, n);
+}
+
+
+void Fl_Gl_Window_Driver::remove_displaylist_fonts()
 {
-# if HAVE_GL
   // clear variables used mostly in fl_font
   fl_graphics_driver->font(0, 0);
 
@@ -112,20 +193,11 @@
       }
     }
   }
-#endif // HAVE_GL
+  // when all GL contexts have been deleted, string textures are no longer valid
+  gl_texture_reset();
 }
-#endif
 
 
-/**
-  Draws an array of n characters of the string in the current font
-  at the current position.
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
-  */
-void gl_draw(const char* str, int n) {
-  Fl_Gl_Window_Driver::global()->draw_string(str, n);
-}
-
 void Fl_Gl_Window_Driver::draw_string(const char* str, int n) {
   static unsigned short *buf = NULL;
   static int l = 0;
@@ -141,7 +213,6 @@
   for (i = 0; i < n; i++) {
     unsigned int r;
     r = (str[i] & 0xFC00) >> 10;
-    //if (!gl_fontsize->glok[r]) get_list(r);
     this->get_list(gl_fontsize, r);
   }
   glCallLists(n, GL_UNSIGNED_SHORT, buf);
@@ -149,7 +220,7 @@
 
 /**
   Draws n characters of the string in the current font at the given position 
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ \see gl_texture_pile_height(int)
   */
 void gl_draw(const char* str, int n, int x, int y) {
   glRasterPos2i(x, y);
@@ -158,7 +229,7 @@
 
 /**
   Draws n characters of the string in the current font at the given position 
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ \see gl_texture_pile_height(int)
   */
 void gl_draw(const char* str, int n, float x, float y) {
   glRasterPos2f(x, y);
@@ -167,7 +238,7 @@
 
 /**
   Draws a nul-terminated string in the current font at the current position
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ \see gl_texture_pile_height(int)
   */
 void gl_draw(const char* str) {
   gl_draw(str, strlen(str));
@@ -175,7 +246,7 @@
 
 /**
   Draws a nul-terminated string in the current font at the given position 
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ \see gl_texture_pile_height(int)
   */
 void gl_draw(const char* str, int x, int y) {
   gl_draw(str, strlen(str), x, y);
@@ -183,7 +254,7 @@
 
 /**
   Draws a nul-terminated string in the current font at the given position 
- \see On the Mac OS X platform, see gl_texture_pile_height(int)
+ \see gl_texture_pile_height(int)
   */
 void gl_draw(const char* str, float x, float y) {
   gl_draw(str, strlen(str), x, y);
@@ -245,10 +316,7 @@
 
 
 #if defined(FL_CFG_GFX_XLIB)
-#include <FL/x.H>
-#include <GL/glx.h>
 
-
 void Fl_X11_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) {
   if (!fl_fontsize->listbase) {
 #if !USE_XFT
@@ -303,14 +371,6 @@
 void Fl_WinAPI_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) {
   if (!fl_fontsize->listbase) {
     fl_fontsize->listbase = glGenLists(GENLISTSIZE);
-     /* old, unused WIN32 code
-     int base = fl_fontsize->metr.tmFirstChar;
-     int count = fl_fontsize->metr.tmLastChar-base+1;
-     HFONT oldFid = (HFONT)SelectObject((HDC)fl_graphics_driver->gc(), fl_fontsize->fid);
-     fl_fontsize->listbase = glGenLists(256);
-     wglUseFontBitmaps((HDC)fl_graphics_driver->gc(), base, count, fl_fontsize->listbase+base);
-     SelectObject((HDC)fl_graphics_driver->gc(), oldFid);
-     */
   }
   glListBase(fl_fontsize->listbase);
 }
@@ -356,42 +416,19 @@
 }
 
 
-#if defined(FL_CFG_GFX_QUARTZ) || defined(FL_DOXYGEN)
-
 #if ! defined(FL_DOXYGEN)
 
-#include <FL/x.H>
-#if !defined(kCGBitmapByteOrder32Host) // doc says available 10.4 but some 10.4 don't have it
-#  define kCGBitmapByteOrder32Host 0
-#endif
+class gl_texture_fifo;
+static gl_texture_fifo *gl_fifo = NULL; // points to the texture pile class instance
 
-#if  MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
-#  include <OpenGL/glext.h>
-#  define GL_TEXTURE_RECTANGLE_ARB GL_TEXTURE_RECTANGLE_EXT
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED
-
-/* Text drawing to an OpenGL scene under Mac OS X is implemented using textures, as recommended by Apple.
- This allows to use any font at any size, and any Unicode character.
- Some old Apple hardware doesn't implement the required GL_EXT_texture_rectangle extension.
- For these, glutStrokeString() is used to draw text. In that case, it's possible to vary text size,
- but not text font, and only ASCII characters can be drawn.
- */
-
-static int gl_scale = 1; // set to 2 for high resolution Fl_Gl_Window
-static int has_texture_rectangle = 0; // true means GL_EXT_texture_rectangle is available
-
-#include <FL/glu.h>  // for gluUnProject() and gluCheckExtension()
-#include <FL/glut.H> // for glutStrokeString() and glutStrokeLength()
-
 // manages a fifo pile of pre-computed string textures
 class gl_texture_fifo {
-  friend class Fl_Cocoa_Gl_Window_Driver;
+  friend void draw_string_using_texture(const char* str, int n);
 private:
   typedef struct { // information for a pre-computed texture
     GLuint texName; // its name
-    char *utf8; //its text
+    char *utf8; // its text
     Fl_Font_Descriptor *fdesc; // its font
-    float ratio; // used without rectangle texture
     int scale; // 1 or 2 for low/high resolution
   } data;
   data *fifo; // array of pile elements
@@ -399,9 +436,9 @@
   int current; // the oldest texture to have entered the pile
   int last; // pile top
   int textures_generated; // true after glGenTextures has been called
-  void display_texture(int rank);
-  int compute_texture(const char* str, int n);
-  int already_known(const char *str, int n);
+  void display_texture(int rank, int scale);
+  int compute_texture(const char* str, int n, int scale);
+  int already_known(const char *str, int n, int scale);
 public:
   gl_texture_fifo(int max = 100); // 100 = default height of texture pile
   inline int size(void) {return size_; };
@@ -408,6 +445,7 @@
   ~gl_texture_fifo(void);
 };
 
+
 gl_texture_fifo::gl_texture_fifo(int max)
 {
   size_ = max;
@@ -425,8 +463,9 @@
   free(fifo);
 }
 
+
 // displays a pre-computed texture on the GL scene
-void gl_texture_fifo::display_texture(int rank)
+void gl_texture_fifo::display_texture(int rank, int gl_scale)
 {
   //setup matrices
   GLint matrixMode;
@@ -440,7 +479,7 @@
   float winw = gl_scale * Fl_Window::current()->w();
   float winh = gl_scale * Fl_Window::current()->h();
   // GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable
-  glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); 
+  glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
   glDisable (GL_DEPTH_TEST); // ensure text is not removed by depth buffer test.
   glEnable (GL_BLEND); // for text fading
   glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // ditto
@@ -448,38 +487,29 @@
   GLfloat pos[4];
   glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
   float R = 2;
-  if (!has_texture_rectangle) {
-    R *= fifo[rank].ratio;
-  }
   glScalef (R/winw, R/winh, 1.0f);
   glTranslatef (-winw/R, -winh/R, 0.0f);
-  GLint width;
-  if (has_texture_rectangle) {
-    glEnable (GL_TEXTURE_RECTANGLE_ARB);
-    glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fifo[rank].texName);
-    GLint height;
-    glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_WIDTH, &width);
-    glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_HEIGHT, &height);
-    CGRect bounds = CGRectMake (pos[0], pos[1] - gl_scale*fl_descent(), width, height);
-    //write the texture on screen
-    glBegin (GL_QUADS);
-    glTexCoord2f (0.0f, 0.0f); // draw lower left in world coordinates
-    glVertex2f (bounds.origin.x, bounds.origin.y);
-    
-    glTexCoord2f (0.0f, height); // draw upper left in world coordinates
-    glVertex2f (bounds.origin.x, bounds.origin.y + bounds.size.height);
-    
-    glTexCoord2f (width, height); // draw upper right in world coordinates
-    glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height);
-    
-    glTexCoord2f (width, 0.0f); // draw lower right in world coordinates
-    glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y);
-    glEnd ();
-  } else {
-    glTranslatef(pos[0]*2/R, pos[1]*2/R, 0.0);
-    glutStrokeString(GLUT_STROKE_ROMAN, (uchar*)fifo[rank].utf8);
-    width = fl_width(fifo[rank].utf8);
-  }
+  glEnable (GL_TEXTURE_RECTANGLE_ARB);
+  glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fifo[rank].texName);
+  GLint width, height;
+  glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_WIDTH, &width);
+  glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ARB, 0, GL_TEXTURE_HEIGHT, &height);
+  
+  GLdouble Y = pos[1] - gl_scale * fl_descent();
+  //write the texture on screen
+  glBegin (GL_QUADS);
+  glTexCoord2f (0.0f, 0.0f); // draw lower left in world coordinates
+  glVertex2f (pos[0], Y);
+  
+  glTexCoord2f (0.0f, height); // draw upper left in world coordinates
+  glVertex2f (pos[0], Y+height);
+  
+  glTexCoord2f (width, height); // draw upper right in world coordinates
+  glVertex2f (pos[0] + width, Y+height);
+  
+  glTexCoord2f (width, 0.0f); // draw lower right in world coordinates
+  glVertex2f (pos[0] + width, Y);
+  glEnd ();
   glPopAttrib();
   
   // reset original matrices
@@ -501,11 +531,135 @@
   glRasterPos2d(objX, objY);
 }
 
-// pre-computes a string texture
-int gl_texture_fifo::compute_texture(const char* str, int n)
+
+#if defined(FL_CFG_GFX_QUARTZ)
+
+void Fl_Cocoa_Gl_Window_Driver::draw_string(const char* str, int n) {
+  GLint matrixMode;
+  glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
+  glMatrixMode (GL_PROJECTION);
+  glPushMatrix();
+  glLoadIdentity ();
+  glMatrixMode (GL_MODELVIEW);
+  glPushMatrix();
+  glLoadIdentity ();
+  Fl_Gl_Window *gwin = Fl_Window::current()->as_gl_window();
+  int retina = (gwin ? gwin->pixels_per_unit() : 1);
+  float winw =  retina * Fl_Window::current()->w();
+  float winh =  retina * Fl_Window::current()->h();
+  // GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable
+  glPushAttrib(GL_ENABLE_BIT  | GL_COLOR_BUFFER_BIT);
+  glDisable (GL_DEPTH_TEST); // ensure text is not removed by depth buffer test.
+  glEnable (GL_BLEND); // for text fading
+  glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // ditto
+  glDisable(GL_LIGHTING);
+  GLfloat pos[4];
+  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
+  int l = 0;
+  for (int i = 0; i < n; i++) {
+    if (*(uchar*)(str+i) < 128) l += glutStrokeWidth(GLUT_STROKE_ROMAN, *(str+i));
+  }
+  float fl_w = fl_width(str, n);
+  float R = 2 * retina*fl_w/l;
+  glScalef (R/winw, R/winh, 1.0f);
+  glTranslatef (-winw/R, -winh/R, 0.0f);
+  glTranslatef(pos[0]*2/R, pos[1]*2/R, 0.0);
+  glutStrokeString(GLUT_STROKE_ROMAN, (uchar*)str);
+  glPopAttrib();
+  
+  // reset original matrices
+  glPopMatrix(); // GL_MODELVIEW
+  glMatrixMode (GL_PROJECTION);
+  glPopMatrix();
+  glMatrixMode (matrixMode);
+  
+  //set the raster position to end of string
+  pos[0] += fl_w;
+  GLdouble modelmat[16];
+  glGetDoublev (GL_MODELVIEW_MATRIX, modelmat);
+  GLdouble projmat[16];
+  glGetDoublev (GL_PROJECTION_MATRIX, projmat);
+  GLdouble objX, objY, objZ;
+  GLint viewport[4];
+  glGetIntegerv (GL_VIEWPORT, viewport);
+  gluUnProject(pos[0], pos[1], pos[2], modelmat, projmat, viewport, &objX, &objY, &objZ);
+  glRasterPos2d(objX, objY);
+}
+
+uchar *Fl_Cocoa_Gl_Window_Driver::draw_string_to_rgba(const char *str, int n,  int w, int h, int gl_scale, void **pdata)
+{ // MacOS-specific version
+  Fl_Font f = fl_font(); Fl_Fontsize s = fl_size();
+  Fl_Offscreen off = fl_create_offscreen(w, h);
+  fl_begin_offscreen(off);
+  CGContextSetRGBFillColor(off, 0,0,0,0);
+  fl_rectf(0,0,w,h);
+  GLfloat colors[4];
+  glGetFloatv(GL_CURRENT_COLOR, colors);
+  uchar r = colors[0]*255, g = colors[1]*255, b = colors[2]*255;
+  fl_color(r, g, b);
+  fl_font(f, s);
+  CGContextTranslateCTM(off, 0, h);
+  CGContextScaleCTM(off, gl_scale, -gl_scale);
+  fl_draw(str, n, 0, fl_height()-fl_descent());
+  fl_end_offscreen();
+  *pdata = off;
+  return (uchar*)CGBitmapContextGetData(off);
+}
+
+void Fl_Cocoa_Gl_Window_Driver::dispose_after_draw(void *data) {
+  fl_delete_offscreen((Fl_Offscreen)data);
+}
+
+#endif // FL_CFG_GFX_QUARTZ
+
+
+uchar *Fl_Gl_Window_Driver::draw_string_to_rgba(const char *str, int n,  int w, int h, int unused, void **pdata)
+{ // cross-platform version
+  Fl_Font f = fl_font(); Fl_Fontsize s = fl_size();
+  Fl_Offscreen off = fl_create_offscreen(w, h);
+  fl_begin_offscreen(off);
+  fl_font(f, s);
+  GLfloat colors[4];
+  glGetFloatv(GL_CURRENT_COLOR, colors);
+  uchar r = colors[0]*255, g = colors[1]*255, b = colors[2]*255;
+  uchar red = (r >= 2 ? r-2 : r+2), green = (g >= 2 ? g-2 : g+2), blue = (b >= 2 ? b-2 : b+2);
+  fl_color(red, green, blue); // this is the background color
+  fl_rectf(0, 0, w, h);
+  fl_color(r, g, b); // this is the text color
+  fl_draw(str, n, 0, fl_height() - fl_descent());
+  const uchar *rgb = fl_read_image(NULL, 0, 0, w, h);
+  // transforms depth-3 rgb into premul RGBA byte array with background color transparent and rest opaque
+  fl_end_offscreen();
+  fl_delete_offscreen(off);
+  uchar* rgba = new uchar[4 * w * h];
+  uchar *q = rgba;
+  while (h-- > 0) { // for each row
+    const uchar *img = rgb + h*w*3;
+    for (int j = 0; j < w; j++) { // for each column
+      r = *img++; // the pixel color components
+      g = *img++;
+      b = *img++;
+      if (r == red && g == green && b == blue) { // if pixel has background color
+         memset(q, 0, 4); q += 4;
+      } else {
+        *q++ = r; *q++ = g; *q++ = b;
+        *q++ = 0xFF;
+      }
+    }
+  }
+  delete[] rgb;
+  *pdata = rgba;
+  return rgba;
+}
+
+void Fl_Gl_Window_Driver::dispose_after_draw(void *data) {
+  delete[] (uchar*)data;
+}
+
+
+// pre-computes a string texture. OK MacOS & Linux & WIN32
+int gl_texture_fifo::compute_texture(const char* str, int n, int gl_scale)
 {
-  Fl_Graphics_Driver *prev_driver = fl_graphics_driver;
-  fl_graphics_driver = Fl_Display_Device::display_device()->driver();
   current = (current + 1) % size_;
   if (current > last) last = current;
   if ( fifo[current].utf8 ) free(fifo[current].utf8);
@@ -518,41 +672,23 @@
   h = fl_height() * gl_scale;
   fifo[current].scale = gl_scale;
   fifo[current].fdesc = gl_fontsize;
-  if (has_texture_rectangle) {
-    //write str to a bitmap just big enough
-    CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
-    void *base = NULL;
-    if (fl_mac_os_version < 100600) base = calloc(4*w, h);
-    void* save_gc = fl_graphics_driver->gc();
-    CGContextRef gc = CGBitmapContextCreate(base, w, h, 8, w*4, lut,
-                                  (CGBitmapInfo)(kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
-    fl_graphics_driver->gc(gc);
-    CGColorSpaceRelease(lut);
-    GLfloat colors[4];
-    glGetFloatv(GL_CURRENT_COLOR, colors);
-    fl_color((uchar)(colors[0]*255), (uchar)(colors[1]*255), (uchar)(colors[2]*255));
-    CGContextTranslateCTM(gc, 0, h - gl_scale*fl_descent());
-    CGContextScaleCTM(gc, gl_scale, gl_scale);
-    fl_draw(str, n, 0, 0);
-    //put this bitmap in a texture
-    glPushAttrib(GL_TEXTURE_BIT);
-    glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fifo[current].texName);
-    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glPixelStorei(GL_UNPACK_ROW_LENGTH, w);
-    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, w, h, 0,  GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, CGBitmapContextGetData(gc));
-    glPopAttrib();
-    CGContextRelease(gc);
-    fl_graphics_driver->gc(save_gc);
-    if (base) free(base);
-  } else {
-    fifo[current].ratio = float(w)/glutStrokeLength(GLUT_STROKE_ROMAN, (uchar*)fifo[current].utf8);
-  }
-  fl_graphics_driver = prev_driver;
+  //write str to a bitmap just big enough
+  void *to_dispose;
+  uchar *rgba = Fl_Gl_Window_Driver::global()->draw_string_to_rgba(str, n, w, h, gl_scale, &to_dispose);
+  //put this bitmap in a texture
+  glPushAttrib(GL_TEXTURE_BIT);
+  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fifo[current].texName);
+  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glPixelStorei(GL_UNPACK_ROW_LENGTH, w);
+  glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, w, h, 0,  GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, rgba);
+  glPopAttrib();
+  Fl_Gl_Window_Driver::global()->dispose_after_draw(to_dispose);
+//fprintf(stderr, "%s scale=%d\n",fifo[current].utf8, fifo[current].scale);
   return current;
 }
 
 // returns rank of pre-computed texture for a string if it exists
-int gl_texture_fifo::already_known(const char *str, int n)
+int gl_texture_fifo::already_known(const char *str, int n, int gl_scale)
 {
   int rank;
   for ( rank = 0; rank <= last; rank++) {
@@ -562,29 +698,30 @@
   return -1;
 }
 
-static gl_texture_fifo *gl_fifo = NULL; // points to the texture pile class instance
 
 // draws a utf8 string using pre-computed texture if available
-void Fl_Cocoa_Gl_Window_Driver::draw_string(const char* str, int n)
+static void draw_string_using_texture(const char* str, int n)
 {
   Fl_Gl_Window *gwin = Fl_Window::current()->as_gl_window();
-  gl_scale = (gwin ? gwin->pixels_per_unit() : 1);
-  
-  //fprintf(stderr,"gl_scale=%d\n",gl_scale);
+  int gl_scale = (gwin ? gwin->pixels_per_unit() : 1); // set to 2 for high resolution Fl_Gl_Window
+
   if (! gl_fifo) gl_fifo = new gl_texture_fifo();
   if (!gl_fifo->textures_generated) {
-    has_texture_rectangle = gluCheckExtension((GLubyte*)"GL_EXT_texture_rectangle", glGetString(GL_EXTENSIONS));
-    if (has_texture_rectangle) for (int i = 0; i < gl_fifo->size_; i++) glGenTextures(1, &(gl_fifo->fifo[i].texName));
+    GLuint *names = new GLuint[gl_fifo->size_];
+    glGenTextures(gl_fifo->size_, names);
+    for (int i = 0; i < gl_fifo->size_; i++) gl_fifo->fifo[i].texName = names[i];
+    delete[] names;
     gl_fifo->textures_generated = 1;
   }
-  int rank = gl_fifo->already_known(str, n);
+  int rank = gl_fifo->already_known(str, n, gl_scale);
   if (rank == -1) {
-    rank = gl_fifo->compute_texture(str, n);
+    rank = gl_fifo->compute_texture(str, n, gl_scale);
   }
-  gl_fifo->display_texture(rank);
+  gl_fifo->display_texture(rank, gl_scale);
 }
 
-void gl_texture_reset()
+
+static void gl_texture_reset()
 {
   if (gl_fifo) gl_texture_pile_height(gl_texture_pile_height());
 }
@@ -591,8 +728,6 @@
 
 #endif  //! defined(FL_DOXYGEN)
 
-/** \addtogroup group_macosx
- @{ */
 
 /**
  \brief Returns the current height of the pile of pre-computed string textures
@@ -618,10 +753,7 @@
   gl_fifo = new gl_texture_fifo(max);
 }
 
-/** @} */
 
-#endif // FL_CFG_GFX_QUARTZ
-
 #endif // HAVE_GL
 
 //
