diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c
index 1e0d0a3..6a5f00f 100644
--- a/src/smooth/ftsmooth.c
+++ b/src/smooth/ftsmooth.c
@@ -333,7 +333,87 @@
 
 #endif  /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
 
-  /* convert a slot's glyph image into a bitmap */
+/* Oversampling scale: 1, 2, 4... */
+#define SCALE  2
+
+  /* This function averages inflated spans in direct rendering mode */
+  static void
+  ft_smooth_slow_spans( int             y,
+                        int             count,
+                        const FT_Span*  spans,
+                        TOrigin*        target )
+  {
+    unsigned char*  dst = target->origin - ( y / SCALE ) * target->pitch;
+    unsigned short  x;
+
+
+    for ( ; count--; spans++ )
+      for ( x = 0; x < spans->len; x++ )
+        if ( dst[ ( spans->x + x ) / SCALE ] == 256 - 256 / ( SCALE * SCALE ) &&
+             spans->coverage + SCALE * SCALE / 2 >= 256                     )
+          dst[ ( spans->x + x ) / SCALE ] = 255;
+        else
+          dst[ ( spans->x + x ) / SCALE ] +=
+                  ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE );
+  }
+
+
+  static FT_Error
+  ft_smooth_raster_slow( FT_Renderer  render,
+                         FT_Outline*  outline,
+                         FT_Bitmap*   bitmap )
+  {
+    FT_Error    error      = FT_Err_Ok;
+    FT_Vector*  points     = outline->points;
+    FT_Vector*  points_end = FT_OFFSET( points, outline->n_points );
+    FT_Vector*  vec;
+
+    FT_Raster_Params   params;
+    TOrigin            target;
+
+
+    /* Render 3 separate coverage bitmaps, shifting the outline.  */
+    /* Set up direct rendering to record them on each third byte. */
+    params.target     = bitmap;
+    params.source     = outline;
+    params.flags      = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
+    params.gray_spans = (FT_SpanFunc)ft_smooth_slow_spans;
+    params.user       = &target;
+
+    params.clip_box.xMin = 0;
+    params.clip_box.yMin = 0;
+    params.clip_box.xMax = bitmap->width * SCALE;
+    params.clip_box.yMax = bitmap->rows  * SCALE;
+
+    if ( bitmap->pitch < 0 )
+      target.origin = bitmap->buffer;
+    else
+      target.origin = bitmap->buffer
+                      + ( bitmap->rows - 1 ) * (unsigned int)bitmap->pitch;
+
+    target.pitch = bitmap->pitch;
+
+    /* implode outline */
+    for ( vec = points; vec < points_end; vec++ )
+    {
+      vec->x *= SCALE;
+      vec->y *= SCALE;
+    }
+
+    /* render outline into the bitmap */
+    error = render->raster_render( render->raster, &params );
+
+    /* deflate outline */
+    for ( vec = points; vec < points_end; vec++ )
+    {
+      vec->x /= SCALE;
+      vec->y /= SCALE;
+    }
+
+    return error;
+  }
+
+
   static FT_Error
   ft_smooth_render( FT_Renderer       render,
                     FT_GlyphSlot      slot,
@@ -406,6 +486,7 @@
 
     if ( mode == FT_RENDER_MODE_NORMAL ||
          mode == FT_RENDER_MODE_LIGHT  )
+#if SCALE == 1
     {
       FT_Raster_Params  params;
 
@@ -416,6 +497,9 @@
 
       error = render->raster_render( render->raster, &params );
     }
+#else
+      error = ft_smooth_raster_slow( render, outline, bitmap );
+#endif
     else
     {
       if ( mode == FT_RENDER_MODE_LCD )
@@ -469,6 +553,7 @@
     return error;
   }
 
+#undef SCALE
 
   FT_DEFINE_RENDERER(
     ft_smooth_renderer_class,
