Index: configure.ac
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/configure.ac,v
retrieving revision 1.637
diff -u -r1.637 configure.ac
--- configure.ac	9 May 2006 17:40:41 -0000	1.637
+++ configure.ac	10 May 2006 14:54:43 -0000
@@ -441,7 +441,7 @@
 dnl *** pango ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_PANGO, true)
 GST_CHECK_FEATURE(PANGO, [pango], pango, [
-  PKG_CHECK_MODULES(PANGO, pango pangoft2,
+  PKG_CHECK_MODULES(PANGO, pango pangoft2 pangocairo,
       HAVE_PANGO="yes", HAVE_PANGO="no")
   AC_SUBST(PANGO_CFLAGS)
   AC_SUBST(PANGO_LIBS)
Index: ext/pango/gsttextoverlay.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/ext/pango/gsttextoverlay.c,v
retrieving revision 1.42
diff -u -r1.42 gsttextoverlay.c
--- ext/pango/gsttextoverlay.c	9 May 2006 19:24:45 -0000	1.42
+++ ext/pango/gsttextoverlay.c	10 May 2006 14:54:44 -0000
@@ -2,6 +2,7 @@
  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
  * Copyright (C) <2003> David Schleef <ds@schleef.org>
  * Copyright (C) <2006> Julien Moutte <julien@moutte.net>
+ * Copyright (C) <2006> Young-Ho Cha <ganadist@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -82,6 +83,7 @@
 #include "gsttimeoverlay.h"
 #include "gstclockoverlay.h"
 #include "gsttextrender.h"
+#include <string.h>
 
 /* FIXME:
  *  - use proper strides and offset for I420
@@ -290,6 +292,7 @@
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
+  PangoFontMap *fontmap;
 
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
@@ -302,7 +305,8 @@
       GST_DEBUG_FUNCPTR (gst_text_overlay_change_state);
 
   klass->get_text = gst_text_overlay_get_text;
-  klass->pango_context = pango_ft2_get_context (72, 72);
+  fontmap = pango_cairo_font_map_get_default ();
+  klass->pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
 
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TEXT,
       g_param_spec_string ("text", "text",
@@ -362,7 +366,11 @@
   GstTextOverlay *overlay = GST_TEXT_OVERLAY (object);
 
   g_free (overlay->default_text);
-  g_free (overlay->bitmap.buffer);
+
+  if (overlay->text_image) {
+    g_free (overlay->text_image);
+    overlay->text_image = NULL;
+  }
 
   if (overlay->layout) {
     g_object_unref (overlay->layout);
@@ -437,7 +445,6 @@
   overlay->layout =
       pango_layout_new (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_context);
   pango_layout_set_alignment (overlay->layout, PANGO_ALIGN_CENTER);
-  memset (&overlay->bitmap, 0, sizeof (overlay->bitmap));
 
   overlay->halign = DEFAULT_PROP_HALIGNMENT;
   overlay->valign = DEFAULT_PROP_VALIGNMENT;
@@ -452,6 +459,7 @@
   overlay->shading_value = DEFAULT_SHADING_VALUE;
 
   overlay->default_text = g_strdup (DEFAULT_PROP_TEXT);
+  overlay->text_image = NULL;
   overlay->need_render = TRUE;
 
   overlay->fps_n = 0;
@@ -797,136 +805,185 @@
   }
 }
 
-/* FIXME:
- *  - use proper strides and offset for I420
- *  - don't draw over the edge of the picture (try a longer
- *    text with a huge font size)
- */
+static inline void
+gst_text_overlay_blit_1 (GstTextOverlay * overlay, guchar * dest, gint xpos,
+    guchar * text_image, guint dest_stride)
+{
+  gint i, j = 0;
+  gint x, y;
+  gint y0 = 0;
+  gint width = overlay->image_width;
+  gint height = overlay->image_height;
+  guchar r, g, b, a;
+  guchar *pimage;
+
+  if (xpos < 0) {
+    xpos = 0;
+  }
+  if (xpos + width > overlay->width) {
+    width = overlay->width - xpos;
+  }
+
+  for (i = 0; i < height; i++) {
+    pimage = text_image + 4 * (i * overlay->image_width);
+    for (j = 0; j < width; j++) {
+      b = *pimage++;
+      g = *pimage++;
+      r = *pimage++;
+      a = *pimage++;
+      y = (int) (((19595 * r) >> 16) + ((38470 * g) >> 16) +
+          ((7471 * b) >> 16));
+      y = CLAMP (y, 0, 255);
+      x = dest[(i + y0) * dest_stride + j + xpos];
+      dest[(i + y0) * dest_stride + j + xpos] = (y * a + x * (255 - a)) / 255;
+    }
+  }
+}
 
 static inline void
-gst_text_overlay_blit_yuv420 (GstTextOverlay * overlay, FT_Bitmap * bitmap,
-    guint8 * yuv_pixels, gint x0, gint y0)
+gst_text_overlay_blit_sub2x2cb (GstTextOverlay * overlay, guchar * dest,
+    gint xpos, guchar * text_image, guint dest_stride)
 {
-  int y;                        /* text bitmap coordinates */
-  int x1, y1;                   /* video buffer coordinates */
-  int bit_rowinc, uv_rowinc;
-  guint8 *p, *bitp, *u_p;
-  int video_width, video_height;
-  int bitmap_x0 = 0;            //x0 < 1 ? -(x0 - 1) : 1;       /* 1 pixel border */
-  int bitmap_y0 = y0 < 1 ? -(y0 - 1) : 1;       /* 1 pixel border */
-  int bitmap_width = bitmap->width - bitmap_x0;
-  int bitmap_height = bitmap->rows - bitmap_y0;
-  int u_plane_size;
-  int skip_y, skip_x;
-  guint8 v;
-
-  video_width = I420_Y_ROWSTRIDE (overlay->width);
-  video_height = overlay->height;
-
-/*
-  if (x0 < 0 && abs (x0) < bitmap_width) {
-    bitmap_x0 = abs (x0);
-    x0 = 0;
-  }
-*/
-
-  if (x0 + bitmap_x0 + bitmap_width > overlay->width - 1)       /* 1 pixel border */
-    bitmap_width -= x0 + bitmap_x0 + bitmap_width - overlay->width + 1;
-  if (y0 + bitmap_y0 + bitmap_height > video_height - 1)        /* 1 pixel border */
-    bitmap_height -= y0 + bitmap_y0 + bitmap_height - video_height + 1;
-
-  uv_rowinc = video_width / 2 - bitmap_width / 2;
-  bit_rowinc = bitmap->pitch - bitmap_width;
-  u_plane_size = (video_width / 2) * (video_height / 2);
-
-  y1 = y0 + bitmap_y0;
-  x1 = x0 + bitmap_x0;
-  bitp = bitmap->buffer + bitmap->pitch * bitmap_y0 + bitmap_x0;
-  for (y = bitmap_y0; y < bitmap_y0 + bitmap_height; y++) {
-    int n;
-
-    p = yuv_pixels + (y + y0) * I420_Y_ROWSTRIDE (overlay->width) + x1;
-    for (n = bitmap_width; n > 0; --n) {
-      v = *bitp;
-      if (v) {
-        p[-1] = CLAMP (p[-1] - v, 0, 255);
-        p[1] = CLAMP (p[1] - v, 0, 255);
-        p[-video_width] = CLAMP (p[-video_width] - v, 0, 255);
-        p[video_width] = CLAMP (p[video_width] - v, 0, 255);
-      }
-      p++;
-      bitp++;
+  gint i, j;
+  gint x, y;
+  gint y0 = 0;
+  gint width = overlay->image_width;
+  gint height = overlay->image_height;
+  guchar r, g, b, a;
+  guchar *pimage;
+
+  if (xpos < 0) {
+    xpos = 0;
+  }
+  if (xpos + width > overlay->width) {
+    width = overlay->width - xpos;
+  }
+
+  for (i = 0; i < height; i += 2) {
+    pimage = text_image + 4 * (i * overlay->image_width);
+    for (j = 0; j < width; j += 2) {
+      b = *pimage++;
+      g = *pimage++;
+      r = *pimage++;
+      a = *pimage++;
+      y = (int) (-((11059 * r) >> 16) - ((21709 * g) >> 16) +
+          ((32768 * b) >> 16) + 128);
+      y = CLAMP (y, 0, 255);
+
+      x = dest[(i / 2 + y0) * dest_stride + (j + xpos) / 2];
+      dest[(i / 2 + y0) * dest_stride + (j + xpos) / 2] =
+          (y * a + x * (255 - a)) / 255;
+      pimage += 4;
     }
-    bitp += bit_rowinc;
   }
+}
 
-  y = bitmap_y0;
-  y1 = y0 + bitmap_y0;
-  x1 = x0 + bitmap_x0;
-  bitp = bitmap->buffer + bitmap->pitch * bitmap_y0 + bitmap_x0;
-  p = yuv_pixels + video_width * y1 + x1;
-  u_p =
-      yuv_pixels + video_width * video_height + (video_width >> 1) * (y1 >> 1) +
-      (x1 >> 1);
-  skip_y = 0;
-  skip_x = 0;
-
-  for (; y < bitmap_y0 + bitmap_height; y++) {
-    int n;
-
-    x1 = x0 + bitmap_x0;
-    skip_x = 0;
-    for (n = bitmap_width; n > 0; --n) {
-      v = *bitp;
-      if (v) {
-        *p = v;
-        if (!skip_y) {
-          u_p[0] = u_p[u_plane_size] = 0x80;
-        }
-      }
-      if (!skip_y) {
-        skip_x = !skip_x;
-        if (!skip_x)
-          u_p++;
-      }
-      p++;
-      bitp++;
+static inline void
+gst_text_overlay_blit_sub2x2cr (GstTextOverlay * overlay, guchar * dest,
+    gint xpos, guchar * text_image, guint dest_stride)
+{
+  gint i, j;
+  gint x, y;
+  gint y0 = 0;
+  gint width = overlay->image_width;
+  gint height = overlay->image_height;
+  guchar r, g, b, a;
+  guchar *pimage;
+
+  if (xpos < 0) {
+    xpos = 0;
+  }
+  if (xpos + width > overlay->width) {
+    width = overlay->width - xpos;
+  }
+
+  for (i = 0; i < height; i += 2) {
+    pimage = text_image + 4 * (i * overlay->image_width);
+    for (j = 0; j < width; j += 2) {
+      b = *pimage++;
+      g = *pimage++;
+      r = *pimage++;
+      a = *pimage++;
+      y = (int) (((32768 * r) >> 16) - ((27439 * g) >> 16) -
+          ((5329 * b) >> 16) + 128);
+      y = CLAMP (y, 0, 255);
+      x = dest[(i / 2 + y0) * dest_stride + (j + xpos) / 2];
+      dest[(i / 2 + y0) * dest_stride + (j + xpos) / 2] =
+          (y * a + x * (255 - a)) / 255;
+      pimage += 4;
     }
-    /*if (!skip_x && !skip_y) u_p--; */
-    p += I420_Y_ROWSTRIDE (overlay->width) - bitmap_width;
-    bitp += bit_rowinc;
-    skip_y = !skip_y;
-    u_p += skip_y ? uv_rowinc : 0;
   }
 }
 
 static void
-gst_text_overlay_resize_bitmap (GstTextOverlay * overlay, gint width,
-    gint height)
+gst_text_overlay_render_pangocairo (GstTextOverlay * overlay, gint width,
+    gint height, const gchar * string, gint textlen)
 {
-  FT_Bitmap *bitmap = &overlay->bitmap;
-  int pitch = (width | 3) + 1;
-  int size = pitch * height;
-
-  /* no need to keep reallocating; just keep the maximum size so far */
-  if (size <= overlay->bitmap_buffer_size) {
-    bitmap->rows = height;
-    bitmap->width = width;
-    bitmap->pitch = pitch;
-    memset (bitmap->buffer, 0, overlay->bitmap_buffer_size);
-    return;
-  }
-  if (!bitmap->buffer) {
-    /* initialize */
-    bitmap->pixel_mode = ft_pixel_mode_grays;
-    bitmap->num_grays = 256;
-  }
-  overlay->bitmap_buffer_size = size;
-  bitmap->buffer = g_realloc (bitmap->buffer, size);
-  memset (bitmap->buffer, 0, size);
-  bitmap->rows = height;
-  bitmap->width = width;
-  bitmap->pitch = pitch;
+  cairo_t *cr;
+  cairo_surface_t *surface;
+  cairo_t *cr_shadow;
+  cairo_surface_t *surface_shadow;
+
+  /* add some space */
+  if (width)
+    width += 10;
+
+  /* FIXME */
+  if (width < overlay->width)
+    pango_layout_set_width (overlay->layout, -1);
+  else {
+    PangoRectangle ink_rect, logical_rect;
+    gst_text_overlay_update_wrap_mode (overlay);
+    pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
+    width = ink_rect.width;
+    height = ink_rect.height + ink_rect.y;
+  }
+
+  surface_shadow = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
+  cr_shadow = cairo_create (surface_shadow);
+
+  /* clear shadow surface */
+  cairo_set_source_rgba (cr_shadow, 0.0, 0.0, 0.0, 0.0);
+  cairo_set_operator (cr_shadow, CAIRO_OPERATOR_CLEAR);
+  cairo_paint (cr_shadow);
+  cairo_set_operator (cr_shadow, CAIRO_OPERATOR_OVER);
+  cairo_save (cr_shadow);
+
+  /* set shadow color */
+  cairo_set_source_rgb (cr_shadow, 0.0, 0.0, 0.0);
+
+  /* draw text shadow */
+  pango_cairo_update_layout (cr_shadow, overlay->layout);
+  pango_layout_set_markup (overlay->layout, string, textlen);
+  pango_cairo_show_layout (cr_shadow, overlay->layout);
+  cairo_restore (cr_shadow);
+  cairo_destroy (cr_shadow);
+
+  overlay->text_image = g_realloc (overlay->text_image, 4 * width * height);
+  memset (overlay->text_image, 0, 4 * width * height);
+
+  surface = cairo_image_surface_create_for_data (overlay->text_image,
+      CAIRO_FORMAT_ARGB32, width, height, width * 4);
+  cr = cairo_create (surface);
+
+  /* set default color */
+  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+  pango_cairo_update_layout (cr, overlay->layout);
+
+  /* draw text */
+  pango_layout_set_markup (overlay->layout, string, textlen);
+  pango_cairo_show_layout (cr, overlay->layout);
+
+  /* composite shadow with offset */
+  cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
+  cairo_set_source_surface (cr, surface_shadow, 1.0, 1.0);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+  cairo_surface_destroy (surface_shadow);
+  cairo_surface_destroy (surface);
+  overlay->image_width = width;
+  overlay->image_height = height;
 }
 
 static void
@@ -960,9 +1017,8 @@
   pango_layout_set_markup (overlay->layout, string, textlen);
 
   pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
-  gst_text_overlay_resize_bitmap (overlay, ink_rect.width,
-      ink_rect.height + ink_rect.y);
-  pango_ft2_render_layout (&overlay->bitmap, overlay->layout, -ink_rect.x, 0);
+  gst_text_overlay_render_pangocairo (overlay, ink_rect.width,
+      ink_rect.height + ink_rect.y, string, textlen);
   overlay->baseline_y = ink_rect.y;
 
   g_free (string);
@@ -974,18 +1030,21 @@
 gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame)
 {
   gint xpos, ypos;
+  gint width, height;
+  guchar *y, *u, *v;
 
-  video_frame = gst_buffer_make_writable (video_frame);
+  width = overlay->image_width;
+  height = overlay->image_height;
 
   switch (overlay->halign) {
     case GST_TEXT_OVERLAY_HALIGN_LEFT:
       xpos = overlay->xpad;
       break;
     case GST_TEXT_OVERLAY_HALIGN_CENTER:
-      xpos = (overlay->width - overlay->bitmap.width) / 2;
+      xpos = (overlay->width - width) / 2;
       break;
     case GST_TEXT_OVERLAY_HALIGN_RIGHT:
-      xpos = overlay->width - overlay->bitmap.width - overlay->xpad;
+      xpos = overlay->width - width - overlay->xpad;
       break;
     default:
       xpos = 0;
@@ -995,10 +1054,10 @@
 
   switch (overlay->valign) {
     case GST_TEXT_OVERLAY_VALIGN_BOTTOM:
-      ypos = overlay->height - overlay->bitmap.rows - overlay->ypad;
+      ypos = overlay->height - height - overlay->ypad;
       break;
     case GST_TEXT_OVERLAY_VALIGN_BASELINE:
-      ypos = overlay->height - (overlay->bitmap.rows + overlay->ypad);
+      ypos = overlay->height - (height + overlay->ypad);
       break;
     case GST_TEXT_OVERLAY_VALIGN_TOP:
       ypos = overlay->ypad;
@@ -1009,18 +1068,28 @@
   }
   ypos += overlay->deltay;
 
+  y = GST_BUFFER_DATA (video_frame);
+  u = y + I420_U_OFFSET (overlay->width, overlay->height);
+  v = y + I420_V_OFFSET (overlay->width, overlay->height);
+
   /* shaded background box */
   if (overlay->want_shading) {
     gst_text_overlay_shade_y (overlay,
-        GST_BUFFER_DATA (video_frame),
-        I420_Y_ROWSTRIDE (overlay->width),
-        xpos, xpos + overlay->bitmap.width, ypos, ypos + overlay->bitmap.rows);
+        y, I420_Y_ROWSTRIDE (overlay->width),
+        xpos, xpos + width, ypos, ypos + height);
   }
 
-
-  if (overlay->bitmap.buffer) {
-    gst_text_overlay_blit_yuv420 (overlay, &overlay->bitmap,
-        GST_BUFFER_DATA (video_frame), xpos, ypos);
+  /* blit text on video image */
+  if (overlay->text_image) {
+    gst_text_overlay_blit_1 (overlay,
+        y + (ypos / 1) * I420_Y_ROWSTRIDE (overlay->width), xpos,
+        overlay->text_image, I420_Y_ROWSTRIDE (overlay->width));
+    gst_text_overlay_blit_sub2x2cb (overlay,
+        u + (ypos / 2) * I420_U_ROWSTRIDE (overlay->width), xpos,
+        overlay->text_image, I420_U_ROWSTRIDE (overlay->width));
+    gst_text_overlay_blit_sub2x2cr (overlay,
+        v + (ypos / 2) * I420_V_ROWSTRIDE (overlay->width), xpos,
+        overlay->text_image, I420_V_ROWSTRIDE (overlay->width));
   }
 
   return gst_pad_push (overlay->srcpad, video_frame);
Index: ext/pango/gsttextoverlay.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/ext/pango/gsttextoverlay.h,v
retrieving revision 1.12
diff -u -r1.12 gsttextoverlay.h
--- ext/pango/gsttextoverlay.h	7 Mar 2006 15:08:15 -0000	1.12
+++ ext/pango/gsttextoverlay.h	10 May 2006 14:54:44 -0000
@@ -2,7 +2,7 @@
 #define __GST_TEXT_OVERLAY_H__
 
 #include <gst/gst.h>
-#include <pango/pangoft2.h>
+#include <pango/pangocairo.h>
 
 G_BEGIN_DECLS
 
@@ -102,8 +102,9 @@
     gboolean                 want_shading;
 
     PangoLayout             *layout;
-    FT_Bitmap                bitmap;
-    gint                     bitmap_buffer_size;
+    guchar                  *text_image;
+    gint                     image_width;
+    gint                     image_height;
     gint                     baseline_y;
 
     gboolean                 need_render;
