Update Skia's handling of vertical text when freetype metrics are available.

This is a cherry-pick of a larger change going into upstream Skia at...
https://codereview.appspot.com/6554064/

bug: 7124435
Change-Id: Id8b030afaf493741e133b592a4e08a3fd90ec2f3
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index d77ebb9..6c03bf9 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -174,6 +174,7 @@
     FT_Matrix   fMatrix22;
     uint32_t    fLoadGlyphFlags;
     bool        fDoLinearMetrics;
+    bool        fUseVertMetrics;
 
     FT_Error setupSize();
     void emboldenOutline(FT_Outline* outline);
@@ -777,6 +778,7 @@
     fScaleY = SkScalarToFixed(sy);
 
     // compute the flags we send to Load_Glyph
+    fUseVertMetrics = false;
     {
         FT_Int32 loadFlags = FT_LOAD_DEFAULT;
         bool linearMetrics = false;
@@ -833,6 +835,12 @@
         // See http://code.google.com/p/skia/issues/detail?id=222.
         loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
 
+        // Use vertical layout if requested and supported.
+        if ((fRec.fFlags & SkScalerContext::kVertical_Flag) && FT_HAS_VERTICAL(fFace)) {
+            loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
+            fUseVertMetrics = true;
+        }
+
         fLoadGlyphFlags = loadFlags;
         fDoLinearMetrics = linearMetrics;
     }
@@ -1002,6 +1010,20 @@
         bbox->xMax  = (bbox->xMax + 63) & ~63;
         bbox->yMax  = (bbox->yMax + 63) & ~63;
     }
+
+    // Must come after snapToPixelBoundary so that the width and height are
+    // consistent. Otherwise asserts will fire later on when generating the
+    // glyph image.
+    if (fUseVertMetrics) {
+        FT_Vector vector;
+        vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX;
+        vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY;
+        FT_Vector_Transform(&vector, &fMatrix22);
+        bbox->xMin += vector.x;
+        bbox->xMax += vector.x;
+        bbox->yMin += vector.y;
+        bbox->yMax += vector.y;
+    }
 }
 
 void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) {
@@ -1072,6 +1094,16 @@
             FT_GlyphSlot_Own_Bitmap(fFace->glyph);
             FT_Bitmap_Embolden(gFTLibrary, &fFace->glyph->bitmap, kBitmapEmboldenStrength, 0);
         }
+
+        if (fUseVertMetrics) {
+            FT_Vector vector;
+            vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX;
+            vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY;
+            FT_Vector_Transform(&vector, &fMatrix22);
+            fFace->glyph->bitmap_left += SkFDot6Floor(vector.x);
+            fFace->glyph->bitmap_top  += SkFDot6Floor(vector.y);
+        }
+
         glyph->fWidth   = SkToU16(fFace->glyph->bitmap.width);
         glyph->fHeight  = SkToU16(fFace->glyph->bitmap.rows);
         glyph->fTop     = -SkToS16(fFace->glyph->bitmap_top);
@@ -1095,8 +1127,17 @@
         glyph->fAdvanceY = -SkFixedMul(fMatrix22.yx, fFace->glyph->linearHoriAdvance);
     }
 
-    if ((fRec.fFlags & SkScalerContext::kVertical_Flag)
-            && fFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+    if (fUseVertMetrics) {
+        if (fDoLinearMetrics) {
+            glyph->fAdvanceX = -SkFixedMul(fMatrix22.xy, fFace->glyph->linearVertAdvance);
+            glyph->fAdvanceY = SkFixedMul(fMatrix22.yy, fFace->glyph->linearVertAdvance);
+        } else {
+            glyph->fAdvanceX = -SkFDot6ToFixed(fFace->glyph->advance.x);
+            glyph->fAdvanceY = SkFDot6ToFixed(fFace->glyph->advance.y);
+        }
+
+    } else if ((fRec.fFlags & SkScalerContext::kVertical_Flag)
+                && fFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
 
         //TODO: do we need to specially handle SubpixelPositioning and Kerning?
 
@@ -1537,6 +1578,14 @@
         emboldenOutline(&fFace->glyph->outline);
     }
 
+    if (fUseVertMetrics) {
+        FT_Vector vector;
+        vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX;
+        vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY;
+        FT_Vector_Transform(&vector, &fMatrix22);
+        FT_Outline_Translate(&fFace->glyph->outline, vector.x, vector.y);
+    }
+
     FT_Outline_Funcs    funcs;
 
     funcs.move_to   = move_proc;