Bug 1293210 - add cap height support to nsFontMetrics. draft
authorJeremy Chen <jeremychen@mozilla.com>
Thu, 18 Aug 2016 17:43:54 +0800
changeset 402508 dd55125e365924d0796fc8e342a8b2e1a762494e
parent 402150 97a52326b06a07930216ebefa5af333271578904
child 402509 6bbcafc1ae49f453cffd6182023791bc37f2b825
push id26677
push userjichen@mozilla.com
push dateThu, 18 Aug 2016 09:44:38 +0000
bugs1293210
milestone51.0a1
Bug 1293210 - add cap height support to nsFontMetrics. MozReview-Commit-ID: 8EXWUtbuN3s
gfx/src/nsFontMetrics.cpp
gfx/src/nsFontMetrics.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -168,16 +168,22 @@ nsFontMetrics::GetMetrics(gfxFont::Orien
 
 nscoord
 nsFontMetrics::XHeight()
 {
     return ROUND_TO_TWIPS(GetMetrics().xHeight);
 }
 
 nscoord
+nsFontMetrics::CapHeight()
+{
+    return ROUND_TO_TWIPS(GetMetrics().capHeight);
+}
+
+nscoord
 nsFontMetrics::SuperscriptOffset()
 {
     return ROUND_TO_TWIPS(GetMetrics().emHeight *
                           NS_FONT_SUPERSCRIPT_OFFSET_RATIO);
 }
 
 nscoord
 nsFontMetrics::SubscriptOffset()
--- a/gfx/src/nsFontMetrics.h
+++ b/gfx/src/nsFontMetrics.h
@@ -70,16 +70,21 @@ public:
     void Destroy();
 
     /**
      * Return the font's x-height.
      */
     nscoord XHeight();
 
     /**
+     * Return the font's cap-height.
+     */
+    nscoord CapHeight();
+
+    /**
      * Return the font's superscript offset (the distance from the
      * baseline to where a superscript's baseline should be placed).
      * The value returned will be positive.
      */
     nscoord SuperscriptOffset();
 
     /**
      * Return the font's subscript offset (the distance from the
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -3454,22 +3454,28 @@ gfxFont::InitMetricsFromSfntTables(Metri
     SET_UNSIGNED(underlineSize, post->underlineThickness);
 
     // 'OS/2' table is optional, if not found we'll estimate xHeight
     // and aveCharWidth by measuring glyphs
     gfxFontEntry::AutoTable os2Table(mFontEntry, kOS_2TableTag);
     if (os2Table) {
         const OS2Table *os2 =
             reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
-        // although sxHeight is a signed field, we consider negative values to
-        // be erroneous and just ignore them
-        if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
-            uint16_t(os2->version) >= 2 && int16_t(os2->sxHeight) > 0) {
-            // version 2 and later includes the x-height field
-            SET_SIGNED(xHeight, os2->sxHeight);
+        // although sxHeight and sCapHeight are signed fields, we consider
+        // negative values to be erroneous and just ignore them
+        if (uint16_t(os2->version) >= 2) {
+            // version 2 and later includes the x-height and cap-height fields
+            if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
+                int16_t(os2->sxHeight) > 0) {
+                SET_SIGNED(xHeight, os2->sxHeight);
+            }
+            if (len >= offsetof(OS2Table, sCapHeight) + sizeof(int16_t) &&
+                int16_t(os2->sCapHeight) > 0) {
+                SET_SIGNED(capHeight, os2->sCapHeight);
+            }
         }
         // this should always be present in any valid OS/2 of any version
         if (len >= offsetof(OS2Table, sTypoLineGap) + sizeof(int16_t)) {
             SET_SIGNED(aveCharWidth, os2->xAvgCharWidth);
             SET_SIGNED(strikeoutSize, os2->yStrikeoutSize);
             SET_SIGNED(strikeoutOffset, os2->yStrikeoutPosition);
 
             // for fonts with USE_TYPO_METRICS set in the fsSelection field,
@@ -3507,16 +3513,22 @@ void gfxFont::CalculateDerivedMetrics(Me
 
     if (aMetrics.xHeight <= 0) {
         // only happens if we couldn't find either font metrics
         // or a char to measure;
         // pick an arbitrary value that's better than zero
         aMetrics.xHeight = aMetrics.maxAscent * DEFAULT_XHEIGHT_FACTOR;
     }
 
+    // If we have a font that doesn't provide a capHeight value, use maxAscent
+    // as a reasonable fallback.
+    if (aMetrics.capHeight <= 0) {
+        aMetrics.capHeight = aMetrics.maxAscent;
+    }
+
     aMetrics.maxHeight = aMetrics.maxAscent + aMetrics.maxDescent;
 
     if (aMetrics.maxHeight - aMetrics.emHeight > 0.0) {
         aMetrics.internalLeading = aMetrics.maxHeight - aMetrics.emHeight;
     } else {
         aMetrics.internalLeading = 0.0;
     }
 
@@ -3769,16 +3781,17 @@ gfxFont::CreateVerticalMetrics()
     metrics->strikeoutSize = std::max(1.0, metrics->strikeoutSize);
     metrics->strikeoutOffset = - 0.5 * metrics->strikeoutSize;
 
     // Somewhat arbitrary values for now, subject to future refinement...
     metrics->spaceWidth = metrics->aveCharWidth;
     metrics->zeroOrAveCharWidth = metrics->aveCharWidth;
     metrics->maxHeight = metrics->maxAscent + metrics->maxDescent;
     metrics->xHeight = metrics->emHeight / 2;
+    metrics->capHeight = metrics->maxAscent;
 
     return metrics;
 }
 
 gfxFloat
 gfxFont::SynthesizeSpaceWidth(uint32_t aCh)
 {
     // return an appropriate width for various Unicode space characters
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1507,16 +1507,17 @@ public:
     virtual already_AddRefed<mozilla::gfx::GlyphRenderingOptions>
       GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams = nullptr)
     { return nullptr; }
 
     gfxFloat SynthesizeSpaceWidth(uint32_t aCh);
 
     // Font metrics
     struct Metrics {
+        gfxFloat capHeight;
         gfxFloat xHeight;
         gfxFloat strikeoutSize;
         gfxFloat strikeoutOffset;
         gfxFloat underlineSize;
         gfxFloat underlineOffset;
 
         gfxFloat internalLeading;
         gfxFloat externalLeading;