diff --git a/CMakeLists.txt b/CMakeLists.txt
index d0eaac0063de3129a73fdafc436f1fb449471fbc..1256a526da15fb3ee6001fd9693f4d770519628c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,7 @@ option(ENABLE_BUILD_ANDROID "Build Gmsh library for Android NDK" OFF)
 option(ENABLE_BUILD_IOS "Build Gmsh library for iOS (ARM)" OFF)
 option(ENABLE_BUILD_IOS_EMULATOR "Build Gmsh library for iOS emulator (x86)" OFF)
 option(ENABLE_CGNS "Enable CGNS mesh export" OFF)
+option(ENABLE_CAIRO "Enable cairo to render fonts" OFF)
 option(ENABLE_CHACO "Enable Chaco mesh partitioner" ${DEFAULT})
 option(ENABLE_DINTEGRATION "Enable discrete integration and levelsets" ${DEFAULT})
 option(ENABLE_FLTK "Build FLTK GUI" ${DEFAULT})
@@ -567,6 +568,16 @@ if(ENABLE_BFGS)
   set_config_option(HAVE_BFGS "Bfgs")
 endif(ENABLE_BFGS)
 
+if(ENABLE_CAIRO)
+  find_library(CAIRO_LIB cairo)
+  find_path(CAIRO_INC "cairo/cairo.h" PATH_SUFFIXES include)
+  if(CAIRO_INC AND CAIRO_LIB)
+     set_config_option(HAVE_CAIRO "cairo")
+     list(APPEND EXTERNAL_LIBRARIES ${CAIRO_LIB})
+     list(APPEND EXTERNAL_INCLUDES ${CAIRO_INC})
+  endif(CAIRO_LIB AND CAIRO_INC)
+endif(ENABLE_CAIRO)
+
 if(ENABLE_DINTEGRATION)
   add_subdirectory(contrib/DiscreteIntegration)
   include_directories(contrib/DiscreteIntegration)
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index cdba70304e4d57acad6c3075b98c84348d32ff16..597232e57da2a58a22120d54e81571b2e3f898fe 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -14,6 +14,7 @@
 #cmakedefine HAVE_BFGS
 #cmakedefine HAVE_BLAS
 #cmakedefine HAVE_BLOSSOM
+#cmakedefine HAVE_CAIRO
 #cmakedefine HAVE_CHACO
 #cmakedefine HAVE_DLOPEN
 #cmakedefine HAVE_DINTEGRATION
diff --git a/Fltk/CMakeLists.txt b/Fltk/CMakeLists.txt
index 482a976a69bcc3efe160cc10137de6582e544e1b..545fb76198ccb49d3444122849c1359d2a8d82c9 100644
--- a/Fltk/CMakeLists.txt
+++ b/Fltk/CMakeLists.txt
@@ -9,6 +9,7 @@ set(SRC
       openglWindow.cpp
     optionWindow.cpp
       colorbarWindow.cpp
+    drawContextFltkCairo.cpp
     gamepadWindow.cpp
     fieldWindow.cpp
     pluginWindow.cpp
diff --git a/Fltk/FlGui.cpp b/Fltk/FlGui.cpp
index 82aae7c944ac2a88cbb46b89fd8a229afc7d0d1c..23866fcf653af9e7911fadb6faac0ce6728c5272 100644
--- a/Fltk/FlGui.cpp
+++ b/Fltk/FlGui.cpp
@@ -18,6 +18,7 @@ typedef unsigned long intptr_t;
 #include <FL/fl_draw.H>
 #include "FlGui.h"
 #include "drawContextFltk.h"
+#include "drawContextFltkCairo.h"
 #include "graphicWindow.h"
 #include "optionWindow.h"
 #include "fieldWindow.h"
@@ -239,7 +240,11 @@ FlGui::FlGui(int argc, char **argv)
   Fl::add_handler(globalShortcut);
 
   // set global fltk-dependent drawing functions
+#if defined(HAVE_CAIRO)
+  drawContext::setGlobal(new drawContextFltkCairo);
+#else
   drawContext::setGlobal(new drawContextFltk);
+#endif
 
   // set default font size
   FL_NORMAL_SIZE = drawContext::global()->getFontSize();
diff --git a/Fltk/drawContextFltkCairo.cpp b/Fltk/drawContextFltkCairo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2fa3bb9506337754f6dcad5b82650e2d00f5582b
--- /dev/null
+++ b/Fltk/drawContextFltkCairo.cpp
@@ -0,0 +1,173 @@
+#include "drawContextFltkCairo.h"
+#if defined(HAVE_CAIRO)
+#include <cairo/cairo.h>
+#include "GL/gl.h"
+
+//mostly borrowed from fltk function gl_texture_fifo::display_texture 
+static void _data2gl (int width, int height, unsigned char *data, int Lx, int Ly, unsigned int _textureId) {
+  //setup matrices
+  GLint matrixMode;
+  glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
+  glMatrixMode (GL_PROJECTION);
+  glPushMatrix();
+  glLoadIdentity ();
+  glMatrixMode (GL_MODELVIEW);
+  glPushMatrix();
+  glLoadIdentity ();
+  float winw = Fl_Window::current()->w();
+  float winh = Fl_Window::current()->h();
+  glScalef (2.0f / winw, 2.0f /  winh, 1.0f);
+  glTranslatef (-winw / 2.0f, -winh / 2.0f, 0.0f);
+  //write the texture on screen
+  GLfloat pos[4];
+  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
+  
+	glEnable (GL_TEXTURE_RECTANGLE_ARB);
+  glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); 
+  glDisable(GL_LIGHTING);
+  glDisable (GL_DEPTH_TEST);
+	glEnable (GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+	glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _textureId);
+	glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
+	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_SRC0_ALPHA);
+  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  
+  glTranslatef(pos[0] /*+ rect->x_bearing*/, pos[1] /*+ rect->y_bearing*/, pos[2]);
+
+	glBegin (GL_QUADS);
+	glTexCoord2f (0, 0);
+	glVertex2f (0.0f, Ly);
+	glTexCoord2f (Lx, 0);
+	glVertex2f (Lx, Ly);
+	glTexCoord2f (Lx, Ly);
+	glVertex2f (Lx, 0.0f);
+	glTexCoord2f (0, Ly);
+	glVertex2f (0.0f, 0.0f);
+	glEnd ();
+
+  glPopAttrib();
+
+  // reset original matrices
+  glPopMatrix(); // GL_MODELVIEW
+  glMatrixMode (GL_PROJECTION);
+  glPopMatrix();
+  glMatrixMode (matrixMode);
+}
+
+double drawContextFltkCairo::getStringWidth(const char *str) {
+  cairo_text_extents_t e;
+  cairo_text_extents(_cr, str, &e);
+  return e.width;
+}
+
+void drawContextFltkCairo::draw()
+{
+  drawContextFltk::draw();
+}
+
+//ensure the surface is large enough
+void drawContextFltkCairo::_resizeSurface(int w, int h)
+{
+  if (w > cairo_image_surface_get_width(_surface) || h > cairo_image_surface_get_height(_surface)) {
+    cairo_font_face_t *face = cairo_get_font_face(_cr);
+    cairo_matrix_t matrix;
+    cairo_get_font_matrix(_cr, &matrix);
+    cairo_destroy(_cr);
+    cairo_surface_destroy(_surface);
+    _surface = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
+    _cr = cairo_create(_surface);
+    cairo_set_font_face(_cr, face);
+    cairo_set_font_matrix(_cr, &matrix);
+  }
+}
+
+void drawContextFltkCairo::drawString(const char *str)
+{
+  cairo_text_extents_t extent;
+  cairo_text_extents(_cr, str, &extent);
+  _resizeSurface(extent.width + 2, extent.height + 2);
+  cairo_surface_t *surface = _surface;
+  cairo_t *cr = _cr;
+
+  cairo_set_source_rgba (cr, 0., 0., 0., 0);
+  cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+  cairo_paint(cr);
+  cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+  extent.width +=1;
+  extent.height +=1;
+  cairo_move_to(cr, 1-extent.x_bearing, 1-extent.y_bearing);
+	cairo_set_source_rgba(cr, 1, 1, 1, 1);
+  cairo_show_text(cr, str);
+  _data2gl(cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface), cairo_image_surface_get_data(surface), extent.width + 1, extent.height + 1, _textureId);
+
+  // fltk version (fl_read_image is too slow)
+  /*Fl_Offscreen offscreen = fl_create_offscreen(100, 100);
+  fl_begin_offscreen(offscreen);
+  fl_color(0, 0, 0);
+  fl_rectf(0, 0, 100, 100);
+  fl_color(255, 255, 255);
+  fl_draw(str, 10, 90);
+  fl_read_image(data, 0, 0, 100, 100);
+
+  CGContextRef src = (CGContextRef)fl_gc;   // get bitmap context
+
+  uchar *base = (uchar *)CGBitmapContextGetData(src);  // get data
+  for (int i = 0; i < 100 * 100; ++i) {
+    data[i] = data[i * 3];
+  }
+  fl_end_offscreen();
+  fl_delete_offscreen(offscreen);
+  */
+}
+
+drawContextFltkCairo::~drawContextFltkCairo()
+{
+  cairo_destroy(_cr);
+  cairo_surface_destroy(_surface);
+	glDeleteTextures(1, &_textureId);
+}
+
+drawContextFltkCairo::drawContextFltkCairo()
+{
+  _surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 100, 100);
+  _cr = cairo_create(_surface);
+  glGenTextures (1, &_textureId);
+  _currentFontId = -1;
+}
+
+void drawContextFltkCairo::setFont(int fontid, int fontsize) {
+  if (_currentFontId != fontid) {
+    switch (fontid) {
+      case FL_HELVETICA :
+      case FL_HELVETICA_BOLD :
+      case FL_HELVETICA_BOLD_ITALIC :
+      case FL_HELVETICA_ITALIC :
+        cairo_select_font_face(_cr, "sans",
+          fontid & FL_ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL,
+          fontid & FL_BOLD ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL);
+        break;
+      case FL_COURIER :
+      case FL_COURIER_BOLD :
+      case FL_COURIER_BOLD_ITALIC :
+      case FL_COURIER_ITALIC :
+        cairo_select_font_face(_cr, "courier",
+          fontid & FL_ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL,
+          fontid & FL_BOLD ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL);
+        break;
+      case FL_TIMES :
+      case FL_TIMES_BOLD :
+      case FL_TIMES_BOLD_ITALIC :
+      case FL_TIMES_ITALIC :
+        cairo_select_font_face(_cr, "serif",
+          fontid & FL_ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL,
+          fontid & FL_BOLD ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL);
+        break;
+      default :
+        cairo_select_font_face(_cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+    }
+    _currentFontId = fontid;
+  }
+  cairo_set_font_size(_cr, fontsize);
+}
+#endif
diff --git a/Fltk/drawContextFltkCairo.h b/Fltk/drawContextFltkCairo.h
new file mode 100644
index 0000000000000000000000000000000000000000..daccf7ec3a1bc2a4d3888f3cd7fc2f6d937858ba
--- /dev/null
+++ b/Fltk/drawContextFltkCairo.h
@@ -0,0 +1,26 @@
+#ifndef _DRAW_CONTEXT_FLTK_CAIRO_H_
+#define _DRAW_CONTEXT_FLTK_CAIRO_H_
+#include "GmshConfig.h"
+#if defined(HAVE_CAIRO)
+#include "drawContextFltk.h"
+typedef struct _cairo_surface cairo_surface_t;
+typedef struct _cairo cairo_t;
+class drawContextFltkCairo : public drawContextFltk {
+  cairo_surface_t *_surface;
+  cairo_t *_cr;
+  unsigned int _textureId;
+  int _currentFontId;
+  int _currentFontSize;
+  void _resizeSurface(int w, int h);
+ public:
+  void draw();
+  drawContextFltkCairo();
+  ~drawContextFltkCairo();
+  double getStringWidth(const char *str);
+  //int getStringHeight();
+  //int getStringDescent();
+  void drawString(const char *str);
+  void setFont(int fontid, int fontsize);
+};
+#endif
+#endif