bug 3512 - implement font-stretch property for Linux (fontconfig) backend. r=karlt
authorJonathan Kew <jfkthame@gmail.com>
Mon, 05 Sep 2011 08:33:43 +0100
changeset 76544 b264ee97923a
parent 76543 3fdf87297e66
child 76545 36d230088375
push id1703
push userjkew@mozilla.com
push dateMon, 05 Sep 2011 07:40:02 +0000
treeherdermozilla-inbound@910e5f55a57e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs3512
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 3512 - implement font-stretch property for Linux (fontconfig) backend. r=karlt
gfx/thebes/gfxFontconfigUtils.cpp
gfx/thebes/gfxFontconfigUtils.h
gfx/thebes/gfxPangoFonts.cpp
--- a/gfx/thebes/gfxFontconfigUtils.cpp
+++ b/gfx/thebes/gfxFontconfigUtils.cpp
@@ -172,16 +172,76 @@ gfxFontconfigUtils::FcWeightForBaseWeigh
         case 9:
             return FC_WEIGHT_BLACK;
     }
 
     // extremes
     return aBaseWeight < 2 ? FC_WEIGHT_THIN : FC_WEIGHT_EXTRABLACK;
 }
 
+/* static */ PRInt16
+gfxFontconfigUtils::GetThebesStretch(FcPattern *aPattern)
+{
+    int width;
+    if (FcPatternGetInteger(aPattern, FC_WIDTH, 0, &width) != FcResultMatch) {
+        return NS_FONT_STRETCH_NORMAL;
+    }
+
+    if (width <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) {
+        return NS_FONT_STRETCH_ULTRA_CONDENSED;
+    }
+    if (width <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) {
+        return NS_FONT_STRETCH_EXTRA_CONDENSED;
+    }
+    if (width <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) {
+        return NS_FONT_STRETCH_CONDENSED;
+    }
+    if (width <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) {
+        return NS_FONT_STRETCH_SEMI_CONDENSED;
+    }
+    if (width <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) {
+        return NS_FONT_STRETCH_NORMAL;
+    }
+    if (width <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) {
+        return NS_FONT_STRETCH_SEMI_EXPANDED;
+    }
+    if (width <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) {
+        return NS_FONT_STRETCH_EXPANDED;
+    }
+    if (width <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) {
+        return NS_FONT_STRETCH_EXTRA_EXPANDED;
+    }
+    return NS_FONT_STRETCH_ULTRA_EXPANDED;
+}
+
+/* static */ int
+gfxFontconfigUtils::FcWidthForThebesStretch(PRInt16 aStretch)
+{
+    switch (aStretch) {
+        default: // this will catch "normal" (0) as well as out-of-range values
+            return FC_WIDTH_NORMAL;
+        case NS_FONT_STRETCH_ULTRA_CONDENSED:
+            return FC_WIDTH_ULTRACONDENSED;
+        case NS_FONT_STRETCH_EXTRA_CONDENSED:
+            return FC_WIDTH_EXTRACONDENSED;
+        case NS_FONT_STRETCH_CONDENSED:
+            return FC_WIDTH_CONDENSED;
+        case NS_FONT_STRETCH_SEMI_CONDENSED:
+            return FC_WIDTH_SEMICONDENSED;
+        case NS_FONT_STRETCH_SEMI_EXPANDED:
+            return FC_WIDTH_SEMIEXPANDED;
+        case NS_FONT_STRETCH_EXPANDED:
+            return FC_WIDTH_EXPANDED;
+        case NS_FONT_STRETCH_EXTRA_EXPANDED:
+            return FC_WIDTH_EXTRAEXPANDED;
+        case NS_FONT_STRETCH_ULTRA_EXPANDED:
+            return FC_WIDTH_ULTRAEXPANDED;
+    }
+}
+
 // This makes a guess at an FC_WEIGHT corresponding to a base weight and
 // offset (without any knowledge of which weights are available).
 
 /* static */ int
 GuessFcWeight(const gfxFontStyle& aFontStyle)
 {
     /*
      * weights come in two parts crammed into one
@@ -239,16 +299,17 @@ gfxFontconfigUtils::NewPattern(const nsT
 
     nsAutoRef<FcPattern> pattern(FcPatternCreate());
     if (!pattern)
         return nsReturnRef<FcPattern>();
 
     FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle.size);
     FcPatternAddInteger(pattern, FC_SLANT, GetFcSlant(aFontStyle));
     FcPatternAddInteger(pattern, FC_WEIGHT, GuessFcWeight(aFontStyle));
+    FcPatternAddInteger(pattern, FC_WIDTH, FcWidthForThebesStretch(aFontStyle.stretch));
 
     if (aLang) {
         AddString(pattern, FC_LANG, aLang);
     }
 
     PRBool useWeakBinding = PR_FALSE;
     for (PRUint32 i = 0; i < aFamilies.Length(); ++i) {
         NS_ConvertUTF16toUTF8 family(aFamilies[i]);
--- a/gfx/thebes/gfxFontconfigUtils.h
+++ b/gfx/thebes/gfxFontconfigUtils.h
@@ -144,22 +144,25 @@ public:
     static const char *ToCString(const FcChar8 *aChar8Ptr)
     {
         return reinterpret_cast<const char*>(aChar8Ptr);
     }
 
     static PRUint8 FcSlantToThebesStyle(int aFcSlant);
     static PRUint8 GetThebesStyle(FcPattern *aPattern); // slant
     static PRUint16 GetThebesWeight(FcPattern *aPattern);
+    static PRInt16 GetThebesStretch(FcPattern *aPattern);
 
     static int GetFcSlant(const gfxFontStyle& aFontStyle);
     // Returns a precise FC_WEIGHT from |aBaseWeight|,
     // which is a CSS absolute weight / 100.
     static int FcWeightForBaseWeight(PRInt8 aBaseWeight);
 
+    static int FcWidthForThebesStretch(PRInt16 aStretch);
+
     static PRBool GetFullnameFromFamilyAndStyle(FcPattern *aFont,
                                                 nsACString *aFullname);
 
     // This doesn't consider which faces exist, and so initializes the pattern
     // using a guessed weight, and doesn't consider sizeAdjust.
     static nsReturnRef<FcPattern>
     NewPattern(const nsTArray<nsString>& aFamilies,
                const gfxFontStyle& aFontStyle, const char *aLang);
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -444,16 +444,24 @@ gfxUserFcFontEntry::AdjustPatternToCSS(F
     // and italic.
     if (res != FcResultMatch ||
         IsItalic() != (fontSlant != FC_SLANT_ROMAN)) {
         FcPatternDel(aPattern, FC_SLANT);
         FcPatternAddInteger(aPattern, FC_SLANT,
                             IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN);
     }
 
+    int fontWidth = -1;
+    FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth);
+    int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch);
+    if (cssWidth != fontWidth) {
+        FcPatternDel(aPattern, FC_WIDTH);
+        FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth);
+    }
+
     // Ensure that there is a fullname property (if there is a family
     // property) so that fontconfig rules can identify the real name of the
     // font, because the family property will be replaced.
     FcChar8 *unused;
     if (FcPatternGetString(aPattern,
                            FC_FULLNAME, 0, &unused) == FcResultNoMatch) {
         nsCAutoString fullname;
         if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern,
@@ -1245,30 +1253,32 @@ private:
     // so the set may be updated when downloads complete
     PRPackedBool mWaitingForUserFont;
 };
 
 // Find the FcPattern for an @font-face font suitable for CSS family |aFamily|
 // and style |aStyle| properties.
 static const nsTArray< nsCountedRef<FcPattern> >*
 FindFontPatterns(gfxUserFontSet *mUserFontSet,
-                const nsACString &aFamily, PRUint8 aStyle, PRUint16 aWeight,
-                PRBool& aFoundFamily, PRBool& aWaitForUserFont)
+                 const nsACString &aFamily, PRUint8 aStyle,
+                 PRUint16 aWeight, PRInt16 aStretch,
+                 PRBool& aFoundFamily, PRBool& aWaitForUserFont)
 {
     // Convert to UTF16
     NS_ConvertUTF8toUTF16 utf16Family(aFamily);
 
     // needsBold is not used here.  Instead synthetic bold is enabled through
     // FcFontRenderPrepare when the weight in the requested pattern is
     // compared against the weight in the font pattern.
     PRBool needsBold;
 
     gfxFontStyle style;
     style.style = aStyle;
     style.weight = aWeight;
+    style.stretch = aStretch;
 
     gfxUserFcFontEntry *fontEntry = static_cast<gfxUserFcFontEntry*>
         (mUserFontSet->FindFontEntry(utf16Family, style, aFoundFamily,
                                      needsBold, aWaitForUserFont));
 
     // Accept synthetic oblique for italic and oblique.
     if (!fontEntry && aStyle != FONT_STYLE_NORMAL) {
         style.style = FONT_STYLE_NORMAL;
@@ -1426,20 +1436,23 @@ gfxFcFontSet::SortPreferredFonts(PRBool 
 
                 // Trim off the prefix
                 nsDependentCSubstring cssFamily(cFamily, userPrefix.Length());
 
                 PRUint8 thebesStyle =
                     gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant);
                 PRUint16 thebesWeight =
                     gfxFontconfigUtils::GetThebesWeight(mSortPattern);
+                PRInt16 thebesStretch =
+                    gfxFontconfigUtils::GetThebesStretch(mSortPattern);
 
                 PRBool foundFamily, waitForUserFont;
                 familyFonts = FindFontPatterns(mUserFontSet, cssFamily,
-                                               thebesStyle, thebesWeight,
+                                               thebesStyle,
+                                               thebesWeight, thebesStretch,
                                                foundFamily, waitForUserFont);
                 if (waitForUserFont) {
                     aWaitForUserFont = PR_TRUE;
                 }
                 NS_ASSERTION(foundFamily,
                              "expected to find a user font, but it's missing!");
             }
         }