--- pango-1.26.0/modules/basic/basic-fc.c.orig	2009-10-08 23:32:21.061864911 +0900
+++ pango-1.26.0/modules/basic/basic-fc.c	2009-10-25 22:20:37.365011773 +0900
@@ -149,6 +149,8 @@ basic_engine_shape (PangoEngineShape *en
 
   buffer = pango_ot_buffer_new (fc_font);
   pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
+  if (analysis->flags & PANGO_ANALYSIS_FLAG_VERTICAL_ROTATE)
+    pango_ot_buffer_set_rtl (buffer, 0);
 
   n_chars = g_utf8_strlen (text, length);
   pango_glyph_string_set_size (glyphs, n_chars);
@@ -173,6 +175,17 @@ basic_engine_shape (PangoEngineShape *en
 	  if (analysis->level % 2)
 	    g_unichar_get_mirror_char (c, &c);
 
+	  if (analysis->flags & PANGO_ANALYSIS_FLAG_VERTICAL)
+	    {
+	      switch (c)
+	        {
+	        case 0x30fc: c = 0x4e28; break;
+	        case 0x28: c = 0x29; break;
+	        case 0x29: c = 0x28; break;
+	        default:;
+	        }
+	    }
+
 	  glyph = pango_fc_font_get_glyph (fc_font, c);
 	}
 
--- pango-1.26.0/pango/pango-context.c.orig	2009-10-14 00:07:14.268747068 +0900
+++ pango-1.26.0/pango/pango-context.c	2009-10-25 23:21:57.305852578 +0900
@@ -56,6 +56,8 @@ struct _PangoContextClass
 };
 
 static void pango_context_finalize    (GObject           *object);
+static PangoLanguage * compute_derived_language (PangoLanguage *lang,
+                                                 PangoScript    script);
 
 G_DEFINE_TYPE (PangoContext, pango_context, G_TYPE_OBJECT)
 
@@ -650,6 +652,11 @@ typedef enum {
 } ChangedFlags;
 
 
+typedef enum {
+  WIDTH_NOWIDE         = 0,
+  WIDTH_WIDE           = 1 << 1,
+  WIDTH_VERTICAL_ALNUM = 1 << 2
+} WideFlags;
 
 typedef struct _PangoWidthIter PangoWidthIter;
 
@@ -659,7 +666,7 @@ struct _PangoWidthIter
 	const gchar *text_end;
 	const gchar *start;
 	const gchar *end;
-	gboolean wide;
+	WideFlags wide;
 };
 
 typedef struct _ItemizeState ItemizeState;
@@ -800,33 +807,101 @@ update_end (ItemizeState *state)
 }
 
 static void
-width_iter_next(PangoWidthIter* iter)
+width_iter_next(PangoWidthIter* iter, gboolean vertical_alnum)
 {
+  gint digit = 0;
+  const gchar *first_digit_c = NULL;
+  const gchar *p;
+  gboolean iswide;
+  gboolean prev_isvertical_alnum = FALSE;
+
   iter->start = iter->end;
 
+  if (iter->wide & WIDTH_VERTICAL_ALNUM)
+    {
+      iter->wide ^= WIDTH_VERTICAL_ALNUM;
+      prev_isvertical_alnum = TRUE;
+    }
+
   if (iter->end < iter->text_end)
     {
       gunichar ch = g_utf8_get_char (iter->end);
-      iter->wide = g_unichar_iswide (ch);
+      iter->wide = g_unichar_iswide (ch) ? WIDTH_WIDE : WIDTH_NOWIDE;
     }
 
   while (iter->end < iter->text_end)
     {
       gunichar ch = g_utf8_get_char (iter->end);
-      if (g_unichar_iswide (ch) != iter->wide)
+      iswide = g_unichar_iswide (ch);
+
+      if (iswide == FALSE && g_unichar_isalnum (ch))
+        {
+          if (digit == 0)
+            first_digit_c = iter->end;
+          digit++;
+        }
+      else
+        {
+          /* If the digit is one or two on CJK, the gravity is vertical.
+           */
+          if (digit == 1 || digit == 2)
+            {
+              if (first_digit_c > iter->start)
+                iter->end = first_digit_c;
+              break;
+            }
+          digit = 0;
+        }
+
+      if (iswide != (iter->wide == WIDTH_WIDE))
         break;
       iter->end = g_utf8_next_char (iter->end);
     }
+
+  if (iter->end == iter->text_end)
+    {
+      if (digit == 1 || digit == 2)
+        {
+          if (first_digit_c > iter->start)
+            iter->end = first_digit_c;
+        }
+    }
+
+  digit = 0;
+  for (p = iter->start;
+       vertical_alnum && p < iter->end;
+       p = g_utf8_next_char (p))
+    {
+      gunichar ch = g_utf8_get_char (p);
+
+      if (g_unichar_isalnum (ch) && !g_unichar_iswide(ch))
+        digit++;
+      else
+        break;
+    }
+
+  if (iter->wide == WIDTH_NOWIDE && (digit == 1 || digit == 2))
+    {
+      iter->wide |= WIDTH_VERTICAL_ALNUM;
+    }
 }
 
 static void
-width_iter_init (PangoWidthIter* iter, const char* text, int length)
+width_iter_init (PangoWidthIter* iter, const char* text, int length, ItemizeState *state)
 {
+  PangoLanguage *lang;
+  gboolean vertical_alnum;
+
   iter->text_start = text;
   iter->text_end = text + length;
   iter->start = iter->end = text;
 
-  width_iter_next (iter);
+  lang = compute_derived_language (state->lang, state->script);
+  vertical_alnum = 
+    state->context->base_gravity == PANGO_GRAVITY_VERTICAL &&
+    pango_language_matches (lang, "ja;ko;zh");
+
+  width_iter_next (iter, vertical_alnum);
 }
 
 static void
@@ -903,7 +978,7 @@ itemize_state_init (ItemizeState      *s
 			       &state->script_end, &state->script);
 
   /* Initialize the width iterator */
-  width_iter_init (&state->width_iter, text + start_index, length);
+  width_iter_init (&state->width_iter, text + start_index, length, state);
 
   update_end (state);
 
@@ -914,6 +989,10 @@ itemize_state_init (ItemizeState      *s
 
   state->gravity = PANGO_GRAVITY_AUTO;
   state->centered_baseline = PANGO_GRAVITY_IS_VERTICAL (state->context->resolved_gravity);
+  if (state->context && state->context->base_gravity == PANGO_GRAVITY_VERTICAL)
+    {
+      state->centered_baseline = TRUE;
+    }
   state->gravity_hint = state->context->gravity_hint;
   state->resolved_gravity = PANGO_GRAVITY_AUTO;
   state->derived_lang = NULL;
@@ -930,6 +1009,9 @@ itemize_state_init (ItemizeState      *s
 static gboolean
 itemize_state_next (ItemizeState *state)
 {
+  PangoLanguage *lang;
+  gboolean vertical_alnum;
+
   if (state->run_end == state->end)
     return FALSE;
 
@@ -957,7 +1039,12 @@ itemize_state_next (ItemizeState *state)
     }
   if (state->run_end == state->width_iter.end)
     {
-      width_iter_next (&state->width_iter);
+      lang = compute_derived_language (state->lang, state->script);
+      vertical_alnum =
+        state->context->base_gravity == PANGO_GRAVITY_VERTICAL &&
+        pango_language_matches (lang, "ja;ko;zh");
+
+      width_iter_next (&state->width_iter, vertical_alnum);
       state->changed |= WIDTH_CHANGED;
     }
 
@@ -1075,6 +1162,14 @@ itemize_state_add_character (ItemizeStat
     }
 
   state->item->analysis.flags = state->centered_baseline ? PANGO_ANALYSIS_FLAG_CENTERED_BASELINE : 0;
+  if (state->context->base_gravity == PANGO_GRAVITY_VERTICAL)
+    {
+      state->item->analysis.flags |= PANGO_ANALYSIS_FLAG_VERTICAL;
+      if (state->width_iter.wide & WIDTH_VERTICAL_ALNUM)
+        state->item->analysis.flags |= PANGO_ANALYSIS_FLAG_VERTICAL_ALNUM;
+      if (PANGO_GRAVITY_IS_VERTICAL (state->resolved_gravity))
+        state->item->analysis.flags |= PANGO_ANALYSIS_FLAG_VERTICAL_ROTATE;
+    }
 
   state->item->analysis.script = state->script;
   state->item->analysis.language = state->derived_lang;
@@ -1306,10 +1401,18 @@ itemize_state_update_for_new_run (Itemiz
 	  if (G_LIKELY (gravity == PANGO_GRAVITY_AUTO))
 	    gravity = state->context->resolved_gravity;
 
-	  state->resolved_gravity = pango_gravity_get_for_script_and_width (state->script,
-									    state->width_iter.wide,
-									    gravity,
-									    gravity_hint);
+	  if (state->context->base_gravity == PANGO_GRAVITY_VERTICAL)
+	    {
+	      if (state->width_iter.wide != WIDTH_NOWIDE)
+	        state->resolved_gravity = PANGO_GRAVITY_SOUTH;
+	      else
+	        state->resolved_gravity = PANGO_GRAVITY_WEST;
+	    }
+	  else
+	    state->resolved_gravity = pango_gravity_get_for_script_and_width (state->script,
+									      state->width_iter.wide != WIDTH_NOWIDE,
+									      gravity,
+									      gravity_hint);
 	}
 
       if (old_gravity != state->resolved_gravity)
--- pango-1.26.0/pango/pango-gravity.h.orig	2009-10-15 23:07:26.809834572 +0900
+++ pango-1.26.0/pango/pango-gravity.h	2009-10-15 23:10:04.639983263 +0900
@@ -52,7 +52,8 @@ typedef enum {
   PANGO_GRAVITY_EAST,
   PANGO_GRAVITY_NORTH,
   PANGO_GRAVITY_WEST,
-  PANGO_GRAVITY_AUTO
+  PANGO_GRAVITY_AUTO,
+  PANGO_GRAVITY_VERTICAL
 } PangoGravity;
 
 /**
--- pango-1.26.0/pango/pango-item.h.orig	2009-10-14 00:07:42.618694095 +0900
+++ pango-1.26.0/pango/pango-item.h	2009-10-22 22:53:20.035804383 +0900
@@ -31,6 +31,9 @@ typedef struct _PangoItem PangoItem;
 
 /* TODO: if more flags are needed, turn this into a real PangoAnalysisFlags enum */
 #define PANGO_ANALYSIS_FLAG_CENTERED_BASELINE (1 << 0)
+#define PANGO_ANALYSIS_FLAG_VERTICAL (1 << 1)
+#define PANGO_ANALYSIS_FLAG_VERTICAL_ALNUM (1 << 2)
+#define PANGO_ANALYSIS_FLAG_VERTICAL_ROTATE (1 << 3)
 
 struct _PangoAnalysis
 {
--- pango-1.26.0/pango/pango-layout.c.orig	2009-10-18 01:18:40.711340912 +0900
+++ pango-1.26.0/pango/pango-layout.c	2009-10-25 22:52:47.490444613 +0900
@@ -4550,6 +4550,7 @@ pango_layout_line_get_extents (PangoLayo
   PangoLayoutLinePrivate *private = (PangoLayoutLinePrivate *)line;
   GSList *tmp_list;
   int x_pos = 0;
+  int rotate_length;
   gboolean caching = FALSE;
 
   g_return_if_fail (LINE_IS_VALID (line));
@@ -4654,6 +4655,23 @@ pango_layout_line_get_extents (PangoLayo
   if (logical_rect && !line->runs)
     pango_layout_line_get_empty_extents (line, logical_rect);
 
+  if (line && line->layout && line->layout->context &&
+      pango_context_get_base_gravity (line->layout->context) == PANGO_GRAVITY_VERTICAL)
+    {
+      if (ink_rect)
+        {
+          rotate_length = ink_rect->width;
+          ink_rect->width = ink_rect->height;
+          ink_rect->height = rotate_length;
+        }
+      if (logical_rect)
+        {
+          rotate_length = logical_rect->width;
+          logical_rect->width = logical_rect->height;
+          logical_rect->height = rotate_length;
+        }
+    }
+
   if (caching)
     {
       if (&private->ink_rect != ink_rect)
--- pango-1.26.0/pango/pango-renderer.c.orig	2009-10-15 00:02:02.826741634 +0900
+++ pango-1.26.0/pango/pango-renderer.c	2009-10-26 00:17:02.706719515 +0900
@@ -462,6 +462,7 @@ pango_renderer_draw_layout_line (PangoRe
 				 int               y)
 {
   int x_off = 0;
+  int y_off = 0;
   int glyph_string_width;
   LineState state;
   GSList *l;
@@ -495,6 +496,7 @@ pango_renderer_draw_layout_line (PangoRe
     {
       PangoFontMetrics *metrics;
       gint rise;
+      gint rise_x;
       PangoLayoutRun *run = l->data;
       PangoAttrShape *shape_attr;
       PangoRectangle ink_rect, *ink = NULL;
@@ -506,6 +508,7 @@ pango_renderer_draw_layout_line (PangoRe
       pango_renderer_prepare_run (renderer, run);
 
       get_item_properties (run->item, &rise, &shape_attr);
+      rise_x = 0;
 
       if (shape_attr)
 	{
@@ -530,7 +533,19 @@ pango_renderer_draw_layout_line (PangoRe
 	    pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
 					ink, logical);
 	  if (logical)
-	    glyph_string_width = logical_rect.width;
+	    {
+	      if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_VERTICAL)
+	        {
+	          if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_VERTICAL_ALNUM)
+	            glyph_string_width = logical_rect.height - 2 * PANGO_SCALE;
+	          else if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_VERTICAL_ROTATE)
+	            glyph_string_width = (logical_rect.height / 2 + 2 * PANGO_SCALE) * run->glyphs->num_glyphs;
+	          else
+	            glyph_string_width = (logical_rect.height - 2 * PANGO_SCALE) * run->glyphs->num_glyphs;
+	        }
+	      else
+	        glyph_string_width = logical_rect.width;
+	    }
 	  else
 	    glyph_string_width = pango_glyph_string_get_width (run->glyphs);
 	}
@@ -540,12 +555,28 @@ pango_renderer_draw_layout_line (PangoRe
       if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE)
 	{
 	  gboolean is_hinted = ((logical_rect.y | logical_rect.height) & (PANGO_SCALE - 1)) == 0;
-	  int adjustment = logical_rect.y + logical_rect.height / 2;
+	  int adjustment;
+
+	  if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_VERTICAL)
+	    {
+	      if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_VERTICAL_ROTATE)
+	        adjustment = logical_rect.height;
+	      else
+	        adjustment = 0;
+	    }
+	  else
+	    {
+	      adjustment = logical_rect.y + logical_rect.height / 2;
+	    }
 
 	  if (is_hinted)
 	    adjustment = PANGO_UNITS_ROUND (adjustment);
 
 	  rise += adjustment;
+
+	  if ((run->item->analysis.flags & PANGO_ANALYSIS_FLAG_VERTICAL) &&
+	      (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_VERTICAL_ROTATE))
+	    rise_x += adjustment;
 	}
 
 
@@ -567,14 +598,14 @@ pango_renderer_draw_layout_line (PangoRe
 
       if (shape_attr)
 	{
-	  draw_shaped_glyphs (renderer, run->glyphs, shape_attr, x + x_off, y - rise);
+	  draw_shaped_glyphs (renderer, run->glyphs, shape_attr, x + x_off, y + y_off - rise);
 	}
       else
 	{
 	  pango_renderer_draw_glyph_item (renderer,
 					  text,
 					  run,
-					  x + x_off, y - rise);
+					  x + x_off + rise_x, y + y_off - rise);
 	}
 
       if (renderer->underline != PANGO_UNDERLINE_NONE ||
@@ -585,12 +616,12 @@ pango_renderer_draw_layout_line (PangoRe
 
 	  if (renderer->underline != PANGO_UNDERLINE_NONE)
 	    add_underline (renderer, &state,metrics,
-			   x + x_off, y - rise,
+			   x + x_off + rise_x, y + y_off - rise,
 			   ink, logical);
 
 	  if (renderer->strikethrough)
 	    add_strikethrough (renderer, &state, metrics,
-			       x + x_off, y - rise,
+			       x + x_off + rise_x, y + y_off - rise,
 			       ink, logical);
 
 	  pango_font_metrics_unref (metrics);
@@ -603,7 +634,10 @@ pango_renderer_draw_layout_line (PangoRe
       if (!renderer->strikethrough && state.strikethrough)
 	draw_strikethrough (renderer, &state);
 
-      x_off += glyph_string_width;
+      if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_VERTICAL)
+        y_off += glyph_string_width;
+      else
+        x_off += glyph_string_width;
     }
 
   /* Finish off any remaining underlines
--- pango-1.26.0/pango/pangocairo-render.c.orig	2009-10-14 00:07:57.122419387 +0900
+++ pango-1.26.0/pango/pangocairo-render.c	2009-10-25 23:17:15.459154295 +0900
@@ -294,8 +294,11 @@ pango_cairo_renderer_show_text_glyphs (P
 
   int i, count;
   int x_position = 0;
+  int y_position = 0;
+  PangoGlyphUnit x_offset, y_offset;
   cairo_glyph_t *cairo_glyphs;
   cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH (cairo_glyph_t)];
+  cairo_text_extents_t extents;
   double base_x = crenderer->x_offset + (double)x / PANGO_SCALE;
   double base_y = crenderer->y_offset + (double)y / PANGO_SCALE;
 
@@ -309,16 +312,31 @@ pango_cairo_renderer_show_text_glyphs (P
 	{
 	  PangoGlyphInfo *gi = &glyphs->glyphs[i];
 
+	  if (gi->geometry.x_offset == 0 && gi->geometry.y_offset)
+	    {
+	      x_offset = gi->geometry.x_offset;
+	      y_offset = (gi->geometry.y_offset > 0) ? gi->geometry.y_offset : 0;
+	    }
+	  else
+	    {
+	      x_offset = gi->geometry.x_offset;
+	      y_offset = gi->geometry.y_offset;
+	    }
+
 	  if (gi->glyph != PANGO_GLYPH_EMPTY)
 	    {
-	      double cx = base_x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+	      double cx = base_x + (double)(x_position + x_offset) / PANGO_SCALE;
 	      double cy = gi->geometry.y_offset == 0 ?
 			  base_y :
-			  base_y + (double)(gi->geometry.y_offset) / PANGO_SCALE;
+			  base_y + (double)(y_position + y_offset) / PANGO_SCALE;
 
 	      _pango_cairo_renderer_draw_unknown_glyph (crenderer, font, gi, cx, cy);
 	    }
-	  x_position += gi->geometry.width;
+
+	  if (gi->geometry.x_offset == 0 && gi->geometry.y_offset)
+	    y_position += gi->geometry.width + 2 * PANGO_SCALE;
+	  else
+	    x_position += gi->geometry.width;
 	}
 
       goto done;
@@ -334,12 +352,23 @@ pango_cairo_renderer_show_text_glyphs (P
     {
       PangoGlyphInfo *gi = &glyphs->glyphs[i];
 
+      if (gi->geometry.x_offset == 0 && gi->geometry.y_offset)
+        {
+          x_offset = gi->geometry.x_offset;
+          y_offset = (gi->geometry.y_offset > 0) ? gi->geometry.y_offset : 0;
+        }
+      else
+        {
+          x_offset = gi->geometry.x_offset;
+          y_offset = gi->geometry.y_offset;
+        }
+
       if (gi->glyph != PANGO_GLYPH_EMPTY)
 	{
-	  double cx = base_x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
+	  double cx = base_x + (double)(x_position + x_offset) / PANGO_SCALE;
 	  double cy = gi->geometry.y_offset == 0 ?
 		      base_y :
-		      base_y + (double)(gi->geometry.y_offset) / PANGO_SCALE;
+		      base_y + (double)(y_position + y_offset) / PANGO_SCALE;
 
 	  if (gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
 	    _pango_cairo_renderer_draw_unknown_glyph (crenderer, font, gi, cx, cy);
@@ -351,7 +380,11 @@ pango_cairo_renderer_show_text_glyphs (P
 	      count++;
 	    }
 	}
-      x_position += gi->geometry.width;
+
+      if (gi->geometry.x_offset == 0 && gi->geometry.y_offset)
+        y_position += gi->geometry.width + 2 * PANGO_SCALE;
+      else
+        x_position += gi->geometry.width;
     }
 
   if (G_UNLIKELY (crenderer->do_path))
--- pango-1.26.0/pango/shape.c.orig	2009-10-14 00:11:46.959602963 +0900
+++ pango-1.26.0/pango/shape.c	2009-10-25 23:18:12.854509996 +0900
@@ -138,7 +138,23 @@ pango_shape (const gchar      *text,
       if (glyphs->glyphs[i].geometry.width < 0)
 	{
 	  glyphs->glyphs[i].geometry.width = -glyphs->glyphs[i].geometry.width;
-	  glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width;
+	  if (analysis->flags & PANGO_ANALYSIS_FLAG_VERTICAL &&
+	      (analysis->flags & PANGO_ANALYSIS_FLAG_VERTICAL_ALNUM) == NULL)
+	    {
+	      if (analysis->flags & PANGO_ANALYSIS_FLAG_VERTICAL_ROTATE)
+	        glyphs->glyphs[i].geometry.width /= 2;
+	      glyphs->glyphs[i].geometry.y_offset += glyphs->glyphs[i].geometry.width;
+	    }
+	  else
+	    glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width;
+	}
+      else if (analysis->flags & PANGO_ANALYSIS_FLAG_VERTICAL &&
+               (analysis->flags & PANGO_ANALYSIS_FLAG_VERTICAL_ALNUM) == NULL)
+	{
+	  if (analysis->flags & PANGO_ANALYSIS_FLAG_VERTICAL_ROTATE)
+	    glyphs->glyphs[i].geometry.width /= 2;
+	  if (glyphs->glyphs[i].geometry.y_offset == 0)
+	    glyphs->glyphs[i].geometry.y_offset = -1;
 	}
     }
 }
