diff -ur Font-FreeType-0.07-orig/FreeType.xs Font-FreeType-0.07/FreeType.xs
--- Font-FreeType-0.07-orig/FreeType.xs	2015-09-27 20:56:20 +0900
+++ Font-FreeType-0.07/FreeType.xs	2017-02-24 19:40:05 +0900
@@ -23,6 +23,7 @@
 #include FT_OUTLINE_H
 #include FT_BBOX_H
 #include FT_TYPE1_TABLES_H
+#include FT_OPENTYPE_VALIDATE_H
 
 #undef assert
 #include <assert.h>
@@ -96,6 +97,7 @@
 struct QefFT2_Face_Extra_
 {
     SV *library_sv;
+    FT_Bytes gsub_data;
     FT_UInt loaded_glyph_idx;
     FT_Int32 glyph_load_flags;
     FT_Glyph glyph_ft;
@@ -178,6 +180,98 @@
     QEFFT2_CONSTANT(FT_ENCODING_MS_JOHAB)
 };
 
+/*------------------- Vertical glyph stuff -------------------*/
+
+/* (more info: http://d.hatena.ne.jp/project_the_tower2/20100509/1273370298) */
+
+static FT_UInt get_vertical_glyph(FT_Face face, FT_UInt index)
+{
+    QefFT2_Face_Extra *extra = face->generic.data;
+
+    if (!extra->gsub_data) {
+        return 0;
+    }
+
+    const uint8_t *gsub = extra->gsub_data;
+
+    const uint16_t featurelist_ofs = gsub[6]<<8 | gsub[7];
+    const uint8_t *featurelist = gsub + featurelist_ofs;
+    const uint16_t num_features = featurelist[0]<<8 | featurelist[1];
+    uint16_t vert_offset = 0;
+    unsigned int i;
+    for (i = 0; i < num_features; i++) {
+        if (memcmp(&featurelist[2+6*i], "vert", 4) == 0) {
+            vert_offset = featurelist[2+6*i+4] << 8 | featurelist[2+6*i+5];
+        }
+    }
+    if (!vert_offset) {
+        return 0;
+    }
+    if (memcmp(&featurelist[vert_offset], "\0\0\0\1\0\0", 6) != 0) {
+        return 0;
+    }
+
+    const uint16_t lookuplist_ofs = gsub[8]<<8 | gsub[9];
+    const uint8_t *lookuplist = gsub + lookuplist_ofs;
+    /* FreeType validation should ensure that the referenced lookup entry
+     * does in fact exist, so we don't need to check for array overrun. */
+    const uint16_t lookup_ofs = lookuplist[2]<<8 | lookuplist[3];
+    const uint8_t *lookup = lookuplist + lookup_ofs;
+    const uint16_t lookuptype = lookup[0]<<8 | lookup[1];
+    const uint16_t subtablecount = lookup[4]<<8 | lookup[5];
+    if (lookuptype != 1 /* single substitution */ || subtablecount != 1) {
+        return 0;
+    }
+
+    const uint16_t subtable_ofs = lookup[6]<<8 | lookup[7];
+    const uint8_t *subtable = lookup + subtable_ofs;
+    const uint16_t substformat = subtable[0]<<8 | subtable[1];
+    const uint16_t coverage_ofs = subtable[2]<<8 | subtable[3];
+    const uint8_t *coverage = subtable + coverage_ofs;
+    const uint16_t coverageformat = coverage[0]<<8 | coverage[1];
+
+    int32_t coverage_index = -1;
+    if (coverageformat == 1) {
+        const uint16_t glyphcount = coverage[2]<<8 | coverage[3];
+        uint16_t i;
+        for (i = 0; i < glyphcount; i++) {
+            const uint16_t covered_glyph = coverage[4+i*2]<<8 | coverage[4+i*2+1];
+            if (covered_glyph == index) {
+                coverage_index = i;
+                break;
+            }
+        }
+    } else if (coverageformat == 2) {
+        const uint16_t rangecount = coverage[2]<<8 | coverage[3];
+        uint16_t i;
+        for (i = 0; i < rangecount; i++) {
+            const uint16_t startglyphid = coverage[4+i*6]<<8 | coverage[4+i*6+1];
+            const uint16_t endglyphid = coverage[4+i*6+2]<<8 | coverage[4+i*6+3];
+            const uint16_t startcoverageindex = coverage[4+i*6+4]<<8 | coverage[4+i*6+5];
+            if (index >= startglyphid && index <= endglyphid) {
+                coverage_index = startcoverageindex + (index - startglyphid);
+                break;
+            }
+        }
+    } else {
+        return 0;
+    }
+    if (coverage_index < 0) {
+        return 0;
+    }
+
+    if (substformat == 1) {
+        const int16_t deltaglyphid = (int16_t)(subtable[4]<<8 | subtable[5]);
+        return index + deltaglyphid;
+    } else if (substformat == 2) {
+        return subtable[6+coverage_index*2]<<8 | subtable[6+coverage_index*2+1];
+    } else {
+        return 0;
+    }
+}
+
+/*------------------------------------------------------------*/
+
 static void
 errchk (FT_Error err, const char *desc)
 {
@@ -408,6 +502,10 @@
         SV *library_sv;
         QefFT2_Face_Extra *extra;
         const FT_Bitmap_Size *size;
+        FT_Bytes dummy_base;  /* FreeType is reported to die if these are   */
+        FT_Bytes dummy_gdef;  /*    not provided to FT_OpenType_Validate(). */
+        FT_Bytes dummy_gpos;
+        FT_Bytes dummy_jstf;
     CODE:
         errchk(FT_New_Face(library, filename, faceidx, &RETVAL),
                "opening font face");
@@ -418,6 +516,11 @@
         extra->loaded_glyph_idx = 0;
         extra->glyph_load_flags = glyph_load_flags;
         extra->glyph_ft = 0;
+        if (FT_OpenType_Validate(RETVAL, FT_VALIDATE_GSUB, &dummy_base,
+                                 &dummy_gdef, &dummy_gpos, &extra->gsub_data,
+                                 &dummy_jstf) != 0) {
+            extra->gsub_data = NULL;
+        }
         RETVAL->generic.data = (void *) extra;
     OUTPUT:
         RETVAL
@@ -789,9 +892,17 @@
 SV *
 qefft2_face_glyph_from_char_code (Font_FreeType_Face face, FT_ULong char_code, int fallback = 0)
     PREINIT:
+        QefFT2_Face_Extra *extra;
         FT_UInt glyph_idx;
     CODE:
         glyph_idx = FT_Get_Char_Index(face, char_code);
+        extra = face->generic.data;
+        if (extra->glyph_load_flags & FT_LOAD_VERTICAL_LAYOUT) {
+            const FT_UInt vglyph_idx = get_vertical_glyph(face, glyph_idx);
+            if (vglyph_idx) {
+                glyph_idx = vglyph_idx;
+            }
+        }
         if (glyph_idx || fallback)
             RETVAL = make_glyph(SvRV(ST(0)), char_code, glyph_idx);
         else
@@ -803,6 +914,7 @@
 SV *
 qefft2_face_glyph_from_char (Font_FreeType_Face face, SV *sv, int fallback = 0)
     PREINIT:
+        QefFT2_Face_Extra *extra;
         FT_UInt glyph_idx;
         const U8 *str;
         STRLEN len;
@@ -823,6 +935,13 @@
             char_code = *str;
         }
         glyph_idx = FT_Get_Char_Index(face, char_code);
+        extra = face->generic.data;
+        if (extra->glyph_load_flags & FT_LOAD_VERTICAL_LAYOUT) {
+            const FT_UInt vglyph_idx = get_vertical_glyph(face, glyph_idx);
+            if (vglyph_idx) {
+                glyph_idx = vglyph_idx;
+            }
+        }
         fallback = SvOK(ST(2)) ? SvIV(ST(2)) : 0;
         if (glyph_idx || fallback)
             RETVAL = make_glyph(SvRV(ST(0)), char_code, glyph_idx);
@@ -983,9 +1102,17 @@
 qefft2_glyph_left_bearing (Font_FreeType_Glyph glyph)
     PREINIT:
         FT_Face face;
+        QefFT2_Face_Extra *extra;
+        FT_GlyphSlot glyphslot;
     CODE:
         face = (FT_Face) SvIV(glyph->face_sv);
-        RETVAL = ensure_glyph_loaded(face, glyph)->metrics.horiBearingX;
+        extra = face->generic.data;
+        glyphslot = ensure_glyph_loaded(face, glyph);
+        if (extra->glyph_load_flags & FT_LOAD_VERTICAL_LAYOUT) {
+            RETVAL = glyphslot->metrics.vertBearingX;
+        } else {
+            RETVAL = glyphslot->metrics.horiBearingX;
+        }
     OUTPUT:
         RETVAL
 
@@ -1004,6 +1131,25 @@
 
 
 FT_F26Dot6
+qefft2_glyph_top_bearing (Font_FreeType_Glyph glyph)
+    PREINIT:
+        FT_Face face;
+        QefFT2_Face_Extra *extra;
+        FT_GlyphSlot glyphslot;
+    CODE:
+        face = (FT_Face) SvIV(glyph->face_sv);
+        extra = face->generic.data;
+        glyphslot = ensure_glyph_loaded(face, glyph);
+        if (extra->glyph_load_flags & FT_LOAD_VERTICAL_LAYOUT) {
+            RETVAL = glyphslot->metrics.vertBearingY;
+        } else {
+            RETVAL = glyphslot->metrics.horiBearingY;
+        }
+    OUTPUT:
+        RETVAL
+
+
+FT_F26Dot6
 qefft2_glyph_horizontal_advance (Font_FreeType_Glyph glyph)
     PREINIT:
         FT_Face face;
diff -ur Font-FreeType-0.07-orig/lib/Font/FreeType/Glyph.pm Font-FreeType-0.07/lib/Font/FreeType/Glyph.pm
--- Font-FreeType-0.07-orig/lib/Font/FreeType/Glyph.pm	2015-09-27 20:56:20 +0900
+++ Font-FreeType-0.07/lib/Font/FreeType/Glyph.pm	2017-02-24 19:24:48 +0900
@@ -410,6 +410,12 @@
 If you pass a file-handle to this method then it will write the path
 string to that file, otherwise it will return it as a string.
 
+=item top_bearing()
+
+The top bearing, which is the distance from the origin to the top of the
+glyph image.  Usually negative for horizontal layouts and positive for
+vertical ones.
+
 =item vertical_advance()
 
 The distance from the origin of the current glyph to the place where
diff -ur Font-FreeType-0.07-orig/lib/Font/FreeType.pm Font-FreeType-0.07/lib/Font/FreeType.pm
--- Font-FreeType-0.07-orig/lib/Font/FreeType.pm	2015-09-27 20:56:20 +0900
+++ Font-FreeType-0.07/lib/Font/FreeType.pm	2017-02-24 19:17:52 +0900
@@ -200,9 +200,7 @@
 
 =item FT_LOAD_VERTICAL_LAYOUT
 
-Return metrics and glyphs suitable for vertical layout.  This module
-doesn't yet provide any intentional support for vertical layout, so
-this probably won't be much use.
+Return metrics and glyphs suitable for vertical layout.
 
 =back
 
