Implement CSS computation of font-stretch property and store it in the gfx font structures. (Bug 3512) r=vlad sr=bzbarsky
authorL. David Baron <dbaron@dbaron.org>
Thu, 29 Jan 2009 12:39:18 -0800
changeset 24408 e2182ed1e129
parent 24407 cbcf14ce64cc
child 24409 dc1587c310b8
push id5031
push userdbaron@mozilla.com
push dateThu, 29 Jan 2009 20:45:18 +0000
treeherdermozilla-central@ea3adcdfa653 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad, bzbarsky
bugs3512
milestone1.9.2a1pre
Implement CSS computation of font-stretch property and store it in the gfx font structures. (Bug 3512) r=vlad sr=bzbarsky
content/canvas/src/nsCanvasRenderingContext2D.cpp
gfx/public/nsFont.h
gfx/src/nsFont.cpp
gfx/src/thebes/nsSystemFontsBeOS.cpp
gfx/src/thebes/nsSystemFontsGTK2.cpp
gfx/src/thebes/nsSystemFontsMac.cpp
gfx/src/thebes/nsSystemFontsOS2.cpp
gfx/src/thebes/nsSystemFontsQt.cpp
gfx/src/thebes/nsSystemFontsWin.cpp
gfx/src/thebes/nsThebesDeviceContext.cpp
gfx/src/thebes/nsThebesFontMetrics.cpp
gfx/thebes/public/gfxFont.h
gfx/thebes/public/gfxFontConstants.h
gfx/thebes/src/gfxFont.cpp
gfx/thebes/src/gfxPangoFonts.cpp
gfx/thebes/test/gfxFontSelectionTests.h
gfx/thebes/test/gfxTextRunPerfTest.cpp
gfx/thebes/test/gfxWordCacheTest.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresShell.cpp
layout/base/nsStyleConsts.h
layout/mathml/base/src/nsMathMLChar.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSPropList.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/test/property_database.js
layout/svg/base/src/nsSVGGlyphFrame.cpp
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -1967,16 +1967,17 @@ nsCanvasRenderingContext2D::SetFont(cons
     // un-zoom the font size to avoid being affected by text-only zoom
     const nscoord fontSize = nsStyleFont::UnZoomText(parentContext->PresContext(), fontStyle->mFont.size);
 
     PRBool printerFont = (presShell->GetPresContext()->Type() == nsPresContext::eContext_PrintPreview ||
                           presShell->GetPresContext()->Type() == nsPresContext::eContext_Print);
 
     gfxFontStyle style(fontStyle->mFont.style,
                        fontStyle->mFont.weight,
+                       fontStyle->mFont.stretch,
                        NSAppUnitsToFloatPixels(fontSize, aupcp),
                        langGroup,
                        fontStyle->mFont.sizeAdjust,
                        fontStyle->mFont.systemFont,
                        fontStyle->mFont.familyNameQuirks,
                        printerFont);
 
     CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name, &style, presShell->GetPresContext()->GetUserFontSet());
--- a/gfx/public/nsFont.h
+++ b/gfx/public/nsFont.h
@@ -63,55 +63,59 @@ const PRUint8 kGenericFont_monospace    
 const PRUint8 kGenericFont_cursive      = 0x10;
 const PRUint8 kGenericFont_fantasy      = 0x20;
 
 // Font structure.
 struct NS_GFX nsFont {
   // The family name of the font
   nsString name;
 
-  // The style of font (normal, italic, oblique)
+  // The style of font (normal, italic, oblique; see gfxFontConstants.h)
   PRUint8 style;
 
   // Force this font to not be considered a 'generic' font, even if
   // the name is the same as a CSS generic font family.
   PRUint8 systemFont;
 
   // The variant of the font (normal, small-caps)
   PRUint8 variant;
 
   // True if the character set quirks (for treatment of "Symbol",
   // "Wingdings", etc.) should be applied.
   PRUint8 familyNameQuirks;
 
-  // The weight of the font (0-999)
+  // The weight of the font; see gfxFontConstants.h.
   PRUint16 weight;
 
+  // The stretch of the font (the sum of various NS_FONT_STRETCH_*
+  // constants; see gfxFontConstants.h).
+  PRInt16 stretch;
+
   // The decorations on the font (underline, overline,
   // line-through). The decorations can be binary or'd together.
   PRUint8 decorations;
 
   // The logical size of the font, in nscoord units
   nscoord size;
 
   // The aspect-value (ie., the ratio actualsize:actualxheight) that any
   // actual physical font created from this font structure must have when
   // rendering or measuring a string. A value of 0 means no adjustment
   // needs to be done.
   float sizeAdjust;
 
   // Initialize the font struct with an ASCII name
   nsFont(const char* aName, PRUint8 aStyle, PRUint8 aVariant,
-         PRUint16 aWeight, PRUint8 aDecoration, nscoord aSize,
-         float aSizeAdjust=0.0f);
+         PRUint16 aWeight, PRInt16 aStretch, PRUint8 aDecoration,
+         nscoord aSize, float aSizeAdjust=0.0f);
 
   // Initialize the font struct with a (potentially) unicode name
   nsFont(const nsString& aName, PRUint8 aStyle, PRUint8 aVariant,
-         PRUint16 aWeight, PRUint8 aDecoration, nscoord aSize,
-         float aSizeAdjust=0.0f);
+         PRUint16 aWeight, PRInt16 aStretch, PRUint8 aDecoration,
+         nscoord aSize, float aSizeAdjust=0.0f);
 
   // Make a copy of the given font
   nsFont(const nsFont& aFont);
 
   nsFont();
   ~nsFont();
 
   PRBool operator==(const nsFont& aOther) const {
--- a/gfx/src/nsFont.cpp
+++ b/gfx/src/nsFont.cpp
@@ -36,55 +36,58 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsFont.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 
 nsFont::nsFont(const char* aName, PRUint8 aStyle, PRUint8 aVariant,
-               PRUint16 aWeight, PRUint8 aDecoration, nscoord aSize,
-               float aSizeAdjust)
+               PRUint16 aWeight, PRInt16 aStretch, PRUint8 aDecoration,
+               nscoord aSize, float aSizeAdjust)
 {
   NS_ASSERTION(aName && IsASCII(nsDependentCString(aName)),
                "Must only pass ASCII names here");
   name.AssignASCII(aName);
   style = aStyle;
   systemFont = PR_FALSE;
   variant = aVariant;
   familyNameQuirks = PR_FALSE;
   weight = aWeight;
+  stretch = aStretch;
   decorations = aDecoration;
   size = aSize;
   sizeAdjust = aSizeAdjust;
 }
 
 nsFont::nsFont(const nsString& aName, PRUint8 aStyle, PRUint8 aVariant,
-               PRUint16 aWeight, PRUint8 aDecoration, nscoord aSize,
-               float aSizeAdjust)
+               PRUint16 aWeight, PRInt16 aStretch, PRUint8 aDecoration,
+               nscoord aSize, float aSizeAdjust)
   : name(aName)
 {
   style = aStyle;
   systemFont = PR_FALSE;
   variant = aVariant;
   familyNameQuirks = PR_FALSE;
   weight = aWeight;
+  stretch = aStretch;
   decorations = aDecoration;
   size = aSize;
   sizeAdjust = aSizeAdjust;
 }
 
 nsFont::nsFont(const nsFont& aOther)
   : name(aOther.name)
 {
   style = aOther.style;
   systemFont = aOther.systemFont;
   variant = aOther.variant;
   familyNameQuirks = aOther.familyNameQuirks;
   weight = aOther.weight;
+  stretch = aOther.stretch;
   decorations = aOther.decorations;
   size = aOther.size;
   sizeAdjust = aOther.sizeAdjust;
 }
 
 nsFont::nsFont()
 {
 }
@@ -94,16 +97,17 @@ nsFont::~nsFont()
 }
 
 PRBool nsFont::BaseEquals(const nsFont& aOther) const
 {
   if ((style == aOther.style) &&
       (systemFont == aOther.systemFont) &&
       (familyNameQuirks == aOther.familyNameQuirks) &&
       (weight == aOther.weight) &&
+      (stretch == aOther.stretch) &&
       (size == aOther.size) &&
       (sizeAdjust == aOther.sizeAdjust) &&
       name.Equals(aOther.name, nsCaseInsensitiveStringComparator())) {
     return PR_TRUE;
   }
   return PR_FALSE;
 }
 
@@ -120,16 +124,17 @@ PRBool nsFont::Equals(const nsFont& aOth
 nsFont& nsFont::operator=(const nsFont& aOther)
 {
   name = aOther.name;
   style = aOther.style;
   systemFont = aOther.systemFont;
   variant = aOther.variant;
   familyNameQuirks = aOther.familyNameQuirks;
   weight = aOther.weight;
+  stretch = aOther.stretch;
   decorations = aOther.decorations;
   size = aOther.size;
   sizeAdjust = aOther.sizeAdjust;
   return *this;
 }
 
 static PRBool IsGenericFontFamily(const nsString& aFamily)
 {
--- a/gfx/src/thebes/nsSystemFontsBeOS.cpp
+++ b/gfx/src/thebes/nsSystemFontsBeOS.cpp
@@ -101,30 +101,33 @@ nsresult nsSystemFontsBeOS::GetSystemFon
 nsresult 
 nsSystemFontsBeOS::GetSystemFontInfo(const BFont *theFont, nsString *aFontName,
                                      gfxFontStyle *aFontStyle) const 
 { 
  
   aFontStyle->style       = FONT_STYLE_NORMAL; 
   aFontStyle->weight      = FONT_WEIGHT_NORMAL; 
   aFontStyle->decorations = FONT_DECORATION_NONE; 
+  aFontStyle->stretch     = NS_FONT_STRETCH_NORMAL;
   
   font_family family; 
   theFont->GetFamilyAndStyle(&family, NULL);
 
   uint16 face = theFont->Face();
   CopyUTF8toUTF16(family, *aFontName);
   aFontStyle->size = theFont->Size();
 
   if (face & B_ITALIC_FACE)
     aFontStyle->style = FONT_STYLE_ITALIC;
 
   if (face & B_BOLD_FACE)
     aFontStyle->weight = FONT_WEIGHT_BOLD;
 
+  // FIXME: Set aFontStyle->stretch correctly!
+
   if (face & B_UNDERSCORE_FACE)
     aFontStyle->decorations |= FONT_DECORATION_UNDERLINE;
 
   if (face & B_STRIKEOUT_FACE)
     aFontStyle->decorations |= FONT_DECORATION_STRIKEOUT;
 
   aFontStyle->systemFont = PR_TRUE;
 
--- a/gfx/src/thebes/nsSystemFontsGTK2.cpp
+++ b/gfx/src/thebes/nsSystemFontsGTK2.cpp
@@ -208,16 +208,19 @@ nsSystemFontsGTK2::GetSystemFontInfo(Gtk
     g_free(fontname);
 
     NS_NAMED_LITERAL_STRING(quote, "\"");
     NS_ConvertUTF8toUTF16 family(pango_font_description_get_family(desc));
     *aFontName = quote + family + quote;
 
     aFontStyle->weight = pango_font_description_get_weight(desc);
 
+    // FIXME: Set aFontStyle->stretch correctly!
+    aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
+
     float size = float(pango_font_description_get_size(desc) / PANGO_SCALE);
 
     // |size| is now either pixels or pango-points (not Mozilla-points!)
 
     if (!MOZ_pango_font_description_get_size_is_absolute(desc)) {
         // |size| is in pango-points, so convert to pixels.
         size *= gfxPlatformGtk::DPI() / POINTS_PER_INCH_FLOAT;
     }
--- a/gfx/src/thebes/nsSystemFontsMac.cpp
+++ b/gfx/src/thebes/nsSystemFontsMac.cpp
@@ -111,16 +111,17 @@ nsSystemFontsMac::GetSystemFont(nsSystem
     nsresult rv;
 
     // hack for now
     if (aID == eSystemFont_Window ||
         aID == eSystemFont_Document)
     {
         aFontStyle->style       = FONT_STYLE_NORMAL;
         aFontStyle->weight      = FONT_WEIGHT_NORMAL;
+        aFontStyle->stretch     = NS_FONT_STRETCH_NORMAL;
 
         aFontName->AssignLiteral("sans-serif");
         aFontStyle->size = 14;
         aFontStyle->systemFont = PR_TRUE;
 
         return NS_OK;
     }
 
@@ -177,13 +178,14 @@ nsSystemFontsMac::GetSystemFont(nsSystem
 
     *aFontName = fontName; 
     aFontStyle->size = gfxFloat(fontSize);
 
     if (fontStyle & bold)
         aFontStyle->weight = FONT_WEIGHT_BOLD;
     if (fontStyle & italic)
         aFontStyle->style = FONT_STYLE_ITALIC;
+    // FIXME: Set aFontStyle->stretch correctly!
 
     aFontStyle->systemFont = PR_TRUE;
 
     return NS_OK;
 }
--- a/gfx/src/thebes/nsSystemFontsOS2.cpp
+++ b/gfx/src/thebes/nsSystemFontsOS2.cpp
@@ -216,16 +216,19 @@ nsresult nsSystemFontsOS2::GetSystemFont
     if ((pos = fontFace.Find(spcBold.get(), PR_FALSE, 0, -1)) > -1) {
         aFontStyle->weight = FONT_WEIGHT_BOLD;
         // strip the attribute, now that we have set it in the gfxFontStyle
         fontFace.Cut(pos, spcBold.Length());
     } else {
         aFontStyle->weight = FONT_WEIGHT_NORMAL;
     }
 
+    // FIXME: Set aFontStyle->stretch correctly!
+    aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
+
     // similar hopes for italic and oblique fonts...
     NS_NAMED_LITERAL_CSTRING(spcItalic, " Italic");
     NS_NAMED_LITERAL_CSTRING(spcOblique, " Oblique");
     NS_NAMED_LITERAL_CSTRING(spcObli, " Obli");
     if ((pos = fontFace.Find(spcItalic.get(), PR_FALSE, 0, -1)) > -1) {
         aFontStyle->style = FONT_STYLE_ITALIC;
         fontFace.Cut(pos, spcItalic.Length());
     } else if ((pos = fontFace.Find(spcOblique.get(), PR_FALSE, 0, -1)) > -1) {
--- a/gfx/src/thebes/nsSystemFontsQt.cpp
+++ b/gfx/src/thebes/nsSystemFontsQt.cpp
@@ -72,16 +72,18 @@ nsSystemFontsQt::GetSystemFontInfo(const
     QFont qFont = QApplication::font(aClassName);
 
     aFontStyle->style = FONT_STYLE_NORMAL;
     aFontStyle->systemFont = PR_TRUE;
     NS_NAMED_LITERAL_STRING(quote, "\"");
     nsString family((PRUnichar*)qFont.family().data());
     *aFontName = quote + family + quote;
     aFontStyle->weight = qFont.weight();
+    // FIXME: Set aFontStyle->stretch correctly!
+    aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
     aFontStyle->size = qFont.pointSizeF() * float(gfxQtPlatform::DPI()) / 72.0f;
     return NS_OK;
 }
 
 
 nsresult
 nsSystemFontsQt::GetSystemFont(nsSystemFontID anID, nsString *aFontName,
                                  gfxFontStyle *aFontStyle) const
--- a/gfx/src/thebes/nsSystemFontsWin.cpp
+++ b/gfx/src/thebes/nsSystemFontsWin.cpp
@@ -59,16 +59,19 @@ nsresult nsSystemFontsWin::CopyLogFontTo
     aFontStyle->style = FONT_STYLE_ITALIC;
   }
   // XXX What about oblique?
 
   // Do Weight
   aFontStyle->weight = (ptrLogFont->lfWeight == FW_BOLD ? 
             FONT_WEIGHT_BOLD : FONT_WEIGHT_NORMAL);
 
+  // FIXME: Set aFontStyle->stretch correctly!
+  aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
+
   // XXX mPixelScale is currently hardcoded to 1 in thebes gfx...
   float mPixelScale = 1.0f;
   // Do Point Size
   //
   // The lfHeight is in pixel and it needs to be adjusted for the
   // device it will be "displayed" on
   // Screens and Printers will differe in DPI
   //
--- a/gfx/src/thebes/nsThebesDeviceContext.cpp
+++ b/gfx/src/thebes/nsThebesDeviceContext.cpp
@@ -423,16 +423,17 @@ nsThebesDeviceContext::GetSystemFont(nsS
     NS_ENSURE_SUCCESS(rv, rv);
 
     aFont->name = fontName;
     aFont->style = fontStyle.style;
     aFont->systemFont = fontStyle.systemFont;
     aFont->variant = NS_FONT_VARIANT_NORMAL;
     aFont->familyNameQuirks = fontStyle.familyNameQuirks;
     aFont->weight = fontStyle.weight;
+    aFont->stretch = fontStyle.stretch;
     aFont->decorations = NS_FONT_DECORATION_NONE;
     aFont->size = NSFloatPixelsToAppUnits(fontStyle.size, UnscaledAppUnitsPerDevPixel());
     //aFont->langGroup = fontStyle.langGroup;
     aFont->sizeAdjust = fontStyle.sizeAdjust;
 
     return rv;
 }
 
--- a/gfx/src/thebes/nsThebesFontMetrics.cpp
+++ b/gfx/src/thebes/nsThebesFontMetrics.cpp
@@ -79,17 +79,18 @@ nsThebesFontMetrics::Init(const nsFont& 
     nsCString langGroup;
     if (aLangGroup) {
         const char* lg;
         mLangGroup->GetUTF8String(&lg);
         langGroup.Assign(lg);
     }
 
     PRBool printerFont = mDeviceContext->IsPrinterSurface();
-    mFontStyle = new gfxFontStyle(aFont.style, aFont.weight, size, langGroup,
+    mFontStyle = new gfxFontStyle(aFont.style, aFont.weight, aFont.stretch,
+                                  size, langGroup,
                                   aFont.sizeAdjust, aFont.systemFont,
                                   aFont.familyNameQuirks,
                                   printerFont);
 
     mFontGroup =
         gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle, 
                                                     aUserFontSet);
     if (mFontGroup->FontListLength() < 1) 
--- a/gfx/thebes/public/gfxFont.h
+++ b/gfx/thebes/public/gfxFont.h
@@ -73,18 +73,18 @@ class gfxUserFontData;
 // We should eliminate these synonyms when it won't cause many merge conflicts.
 #define FONT_WEIGHT_NORMAL             NS_FONT_WEIGHT_NORMAL
 #define FONT_WEIGHT_BOLD               NS_FONT_WEIGHT_BOLD
 
 #define FONT_MAX_SIZE                  2000.0
 
 struct THEBES_API gfxFontStyle {
     gfxFontStyle();
-    gfxFontStyle(PRUint8 aStyle, PRUint16 aWeight, gfxFloat aSize,
-                 const nsACString& aLangGroup,
+    gfxFontStyle(PRUint8 aStyle, PRUint16 aWeight, PRInt16 aStretch,
+                 gfxFloat aSize, const nsACString& aLangGroup,
                  float aSizeAdjust, PRPackedBool aSystemFont,
                  PRPackedBool aFamilyNameQuirks,
                  PRPackedBool aPrinterFont);
     gfxFontStyle(const gfxFontStyle& aStyle);
 
     // The style of font (normal, italic, oblique)
     PRUint8 style : 7;
 
@@ -102,16 +102,20 @@ struct THEBES_API gfxFontStyle {
 
     // The weight of the font.  100, 200, ... 900 are the weights, and
     // single integer offsets request the next bolder/lighter font
     // available.  For example, for a font available in weights 200,
     // 400, 700, and 900, a weight of 898 should lead to the weight 400
     // font being used, since it is two weights lighter than 900.
     PRUint16 weight;
 
+    // The stretch of the font (the sum of various NS_FONT_STRETCH_*
+    // constants; see gfxFontConstants.h).
+    PRInt16 stretch;
+
     // The logical size of the font, in pixels
     gfxFloat size;
 
     // the language group
     nsCString langGroup;
 
     // The aspect-value (ie., the ratio actualsize:actualxheight) that any
     // actual physical font created from this font structure must have when
@@ -138,16 +142,17 @@ struct THEBES_API gfxFontStyle {
 
     PRBool Equals(const gfxFontStyle& other) const {
         return (size == other.size) &&
             (style == other.style) &&
             (systemFont == other.systemFont) &&
             (printerFont == other.printerFont) &&
             (familyNameQuirks == other.familyNameQuirks) &&
             (weight == other.weight) &&
+            (stretch == other.stretch) &&
             (langGroup.Equals(other.langGroup)) &&
             (sizeAdjust == other.sizeAdjust);
     }
 };
 
 class gfxFontEntry {
 public:
     THEBES_INLINE_DECL_REFCOUNTING(gfxFontEntry)
--- a/gfx/thebes/public/gfxFontConstants.h
+++ b/gfx/thebes/public/gfxFontConstants.h
@@ -46,11 +46,25 @@
 
 #define NS_FONT_STYLE_NORMAL            0
 #define NS_FONT_STYLE_ITALIC            1
 #define NS_FONT_STYLE_OBLIQUE           2
 
 #define NS_FONT_WEIGHT_NORMAL           400
 #define NS_FONT_WEIGHT_BOLD             700
 #define NS_FONT_WEIGHT_BOLDER           1
-#define NS_FONT_WEIGHT_LIGHTER          -1
+#define NS_FONT_WEIGHT_LIGHTER          (-1)
+
+#define NS_FONT_STRETCH_ULTRA_CONDENSED (-4)
+#define NS_FONT_STRETCH_EXTRA_CONDENSED (-3)
+#define NS_FONT_STRETCH_CONDENSED       (-2)
+#define NS_FONT_STRETCH_SEMI_CONDENSED  (-1)
+#define NS_FONT_STRETCH_NORMAL          0
+#define NS_FONT_STRETCH_SEMI_EXPANDED   1
+#define NS_FONT_STRETCH_EXPANDED        2
+#define NS_FONT_STRETCH_EXTRA_EXPANDED  3
+#define NS_FONT_STRETCH_ULTRA_EXPANDED  4
+// These need to be more than double all of the values above so that we
+// can add any multiple of any of these values to the values above.
+#define NS_FONT_STRETCH_WIDER           10
+#define NS_FONT_STRETCH_NARROWER        (-10)
 
 #endif
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -1223,28 +1223,29 @@ gfxFontGroup::GetGeneration()
     return mUserFontSet->GetGeneration();
 }
 
 
 #define DEFAULT_PIXEL_FONT_SIZE 16.0f
 
 gfxFontStyle::gfxFontStyle() :
     style(FONT_STYLE_NORMAL), systemFont(PR_TRUE), printerFont(PR_FALSE), 
-    familyNameQuirks(PR_FALSE), weight(FONT_WEIGHT_NORMAL), size(DEFAULT_PIXEL_FONT_SIZE),
+    familyNameQuirks(PR_FALSE), weight(FONT_WEIGHT_NORMAL),
+    stretch(NS_FONT_STRETCH_NORMAL), size(DEFAULT_PIXEL_FONT_SIZE),
     langGroup(NS_LITERAL_CSTRING("x-western")), sizeAdjust(0.0f)
 {
 }
 
-gfxFontStyle::gfxFontStyle(PRUint8 aStyle, PRUint16 aWeight, gfxFloat aSize,
-                           const nsACString& aLangGroup,
+gfxFontStyle::gfxFontStyle(PRUint8 aStyle, PRUint16 aWeight, PRInt16 aStretch,
+                           gfxFloat aSize, const nsACString& aLangGroup,
                            float aSizeAdjust, PRPackedBool aSystemFont,
                            PRPackedBool aFamilyNameQuirks,
                            PRPackedBool aPrinterFont):
     style(aStyle), systemFont(aSystemFont), printerFont(aPrinterFont),
-    familyNameQuirks(aFamilyNameQuirks), weight(aWeight),
+    familyNameQuirks(aFamilyNameQuirks), weight(aWeight), stretch(aStretch),
     size(aSize), langGroup(aLangGroup), sizeAdjust(aSizeAdjust)
 {
     if (weight > 900)
         weight = 900;
     if (weight < 100)
         weight = 100;
 
     if (size >= FONT_MAX_SIZE) {
@@ -1259,17 +1260,17 @@ gfxFontStyle::gfxFontStyle(PRUint8 aStyl
         NS_WARNING("empty langgroup");
         langGroup.Assign("x-western");
     }
 }
 
 gfxFontStyle::gfxFontStyle(const gfxFontStyle& aStyle) :
     style(aStyle.style), systemFont(aStyle.systemFont), printerFont(aStyle.printerFont),
     familyNameQuirks(aStyle.familyNameQuirks), weight(aStyle.weight),
-    size(aStyle.size), langGroup(aStyle.langGroup),
+    stretch(aStyle.stretch), size(aStyle.size), langGroup(aStyle.langGroup),
     sizeAdjust(aStyle.sizeAdjust)
 {
 }
 
 void
 gfxFontStyle::ComputeWeightAndOffset(PRInt8 *outBaseWeight, PRInt8 *outOffset) const
 {
     PRInt8 baseWeight = (weight + 50) / 100;
--- a/gfx/thebes/src/gfxPangoFonts.cpp
+++ b/gfx/thebes/src/gfxPangoFonts.cpp
@@ -2240,17 +2240,19 @@ gfxFcFont::GetOrMakeFont(FcPattern *aPat
         // name or style, as size is the only thing expected to be important.
         PRUint8 style = gfxFontconfigUtils::GetThebesStyle(aPattern);
         PRUint16 weight = gfxFontconfigUtils::GetThebesWeight(aPattern);
 
         // The LangSet in the FcPattern does not have an order so there is no
         // one particular language to choose and converting the set to a
         // string through FcNameUnparse() is more trouble than it's worth.
         NS_NAMED_LITERAL_CSTRING(langGroup, "x-unicode");
-        gfxFontStyle fontStyle(style, weight, size, langGroup, 0.0,
+        // FIXME: Pass a real stretch based on aPattern!
+        gfxFontStyle fontStyle(style, weight, NS_FONT_STRETCH_NORMAL,
+                               size, langGroup, 0.0,
                                PR_TRUE, PR_FALSE, PR_FALSE);
 
         nsRefPtr<gfxFontEntry> fe;
         FcChar8 *fc_file;
         if (FcPatternGetString(aPattern,
                                FC_FILE, 0, &fc_file) == FcResultMatch) {
             int index;
             if (FcPatternGetInteger(aPattern,
--- a/gfx/thebes/test/gfxFontSelectionTests.h
+++ b/gfx/thebes/test/gfxFontSelectionTests.h
@@ -101,23 +101,25 @@
 
 void
 SetupTests()
 {
     TestEntry *t;
 
     /* some common styles */
     gfxFontStyle style_western_normal_16 (FONT_STYLE_NORMAL,
+                                          NS_FONT_STRETCH_NORMAL,
                                           400,
                                           16.0,
                                           nsDependentCString("x-western"),
                                           0.0,
                                           PR_FALSE, PR_FALSE, PR_FALSE);
 
     gfxFontStyle style_western_bold_16 (FONT_STYLE_NORMAL,
+                                        NS_FONT_STRETCH_NORMAL,
                                         700,
                                         16.0,
                                         nsDependentCString("x-western"),
                                         0.0,
                                         PR_FALSE, PR_FALSE, PR_FALSE);
 
     /* Test 0 */
     t = AddTest ("sans-serif",
--- a/gfx/thebes/test/gfxTextRunPerfTest.cpp
+++ b/gfx/thebes/test/gfxTextRunPerfTest.cpp
@@ -85,16 +85,17 @@ MakeContext ()
 
 nsRefPtr<gfxFontGroup> fontGroup;
 const char* lastFamilies = nsnull;
 
 void
 RunTest (TestEntry *test, gfxContext *ctx) {
     if (!lastFamilies || strcmp(lastFamilies, test->mFamilies)) {
         gfxFontStyle style_western_normal_16 (FONT_STYLE_NORMAL,
+                                              NS_FONT_STRETCH_NORMAL,
                                               400,
                                               16.0,
                                               nsDependentCString("x-western"),
                                               0.0,
                                               PR_FALSE, PR_FALSE, PR_FALSE);
 
         fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16, nsnull);
     }
--- a/gfx/thebes/test/gfxWordCacheTest.cpp
+++ b/gfx/thebes/test/gfxWordCacheTest.cpp
@@ -151,16 +151,17 @@ main (int argc, char **argv) {
    fflush (stderr);
    fflush (stdout);
 
    gTextRuns = new FrameTextRunCache();
 
    nsRefPtr<gfxContext> ctx = MakeContext();
    {
        gfxFontStyle style (FONT_STYLE_NORMAL,
+                           NS_FONT_STRETCH_NORMAL,
                            139,
                            10.0,
                            nsDependentCString("x-western"),
                            0.0,
                            PR_FALSE, PR_FALSE, PR_FALSE);
 
        nsRefPtr<gfxFontGroup> fontGroup =
            gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style, nsnull);
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -173,29 +173,34 @@ static NS_DEFINE_CID(kLookAndFeelCID,  N
 
 nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
   : mType(aType), mDocument(aDocument), mTextZoom(1.0), mFullZoom(1.0),
     mPageSize(-1, -1), mPPScale(1.0f),
     mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO),
     mImageAnimationModePref(imgIContainer::kNormalAnimMode),
     // Font sizes default to zero; they will be set in GetFontPreferences
     mDefaultVariableFont("serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
-                         NS_FONT_WEIGHT_NORMAL, 0, 0),
+                         NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 0),
     mDefaultFixedFont("monospace", NS_FONT_STYLE_NORMAL,
-                      NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL, 0, 0),
+                      NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                      NS_FONT_STRETCH_NORMAL, 0, 0),
     mDefaultSerifFont("serif", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
-                      NS_FONT_WEIGHT_NORMAL, 0, 0),
+                      NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 0),
     mDefaultSansSerifFont("sans-serif", NS_FONT_STYLE_NORMAL,
-                          NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL, 0, 0),
+                          NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                          NS_FONT_STRETCH_NORMAL, 0, 0),
     mDefaultMonospaceFont("monospace", NS_FONT_STYLE_NORMAL,
-                          NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL, 0, 0),
+                          NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                          NS_FONT_STRETCH_NORMAL, 0, 0),
     mDefaultCursiveFont("cursive", NS_FONT_STYLE_NORMAL,
-                        NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL, 0, 0),
+                        NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                        NS_FONT_STRETCH_NORMAL, 0, 0),
     mDefaultFantasyFont("fantasy", NS_FONT_STYLE_NORMAL,
-                        NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL, 0, 0),
+                        NS_FONT_VARIANT_NORMAL, NS_FONT_WEIGHT_NORMAL,
+                        NS_FONT_STRETCH_NORMAL, 0, 0),
     mCanPaginatedScroll(PR_FALSE),
     mIsRootPaginatedDocument(PR_FALSE), mSupressResizeReflow(PR_FALSE)
 {
   // NOTE! nsPresContext::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
   mDoScaledTwips = PR_TRUE;
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -7688,17 +7688,17 @@ void ReflowCountMgr::PaintCount(const ch
       nsnull != mIndiFrameCounts && 
       aFrame != nsnull) {
     char * key = new char[16];
     sprintf(key, "%p", (void*)aFrame);
     IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key);
     if (counter != nsnull && counter->mName.EqualsASCII(aName)) {
       aRenderingContext->PushState();
       nsFont font("Times", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL,
-                  NS_FONT_WEIGHT_NORMAL, 0,
+                  NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0,
                   nsPresContext::CSSPixelsToAppUnits(11));
 
       nsCOMPtr<nsIFontMetrics> fm = aPresContext->GetMetricsFor(font);
       aRenderingContext->SetFont(fm);
       char buf[16];
       sprintf(buf, "%d", counter->mCount);
       nscoord x = 0, y;
       nscoord width, height;
--- a/layout/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -433,27 +433,28 @@
 #define NS_STYLE_FONT_SIZE_LARGE                4
 #define NS_STYLE_FONT_SIZE_XLARGE               5
 #define NS_STYLE_FONT_SIZE_XXLARGE              6
 #define NS_STYLE_FONT_SIZE_XXXLARGE             7  // Only used by <font size="7">. Not specifiable in CSS.
 #define NS_STYLE_FONT_SIZE_LARGER               8
 #define NS_STYLE_FONT_SIZE_SMALLER              9
 
 // See nsStyleFont
-#define NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED   -4
-#define NS_STYLE_FONT_STRETCH_EXTRA_CONDENSED   -3
-#define NS_STYLE_FONT_STRETCH_CONDENSED         -2
-#define NS_STYLE_FONT_STRETCH_SEMI_CONDENSED    -1
-#define NS_STYLE_FONT_STRETCH_NORMAL            0
-#define NS_STYLE_FONT_STRETCH_SEMI_EXPANDED     1
-#define NS_STYLE_FONT_STRETCH_EXPANDED          2
-#define NS_STYLE_FONT_STRETCH_EXTRA_EXPANDED    3
-#define NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED    4
-#define NS_STYLE_FONT_STRETCH_WIDER             10
-#define NS_STYLE_FONT_STRETCH_NARROWER          -10
+// We should eventually stop using the NS_STYLE_* variants here.
+#define NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED   NS_FONT_STRETCH_ULTRA_CONDENSED
+#define NS_STYLE_FONT_STRETCH_EXTRA_CONDENSED   NS_FONT_STRETCH_EXTRA_CONDENSED
+#define NS_STYLE_FONT_STRETCH_CONDENSED         NS_FONT_STRETCH_CONDENSED
+#define NS_STYLE_FONT_STRETCH_SEMI_CONDENSED    NS_FONT_STRETCH_SEMI_CONDENSED
+#define NS_STYLE_FONT_STRETCH_NORMAL            NS_FONT_STRETCH_NORMAL
+#define NS_STYLE_FONT_STRETCH_SEMI_EXPANDED     NS_FONT_STRETCH_SEMI_EXPANDED
+#define NS_STYLE_FONT_STRETCH_EXPANDED          NS_FONT_STRETCH_EXPANDED
+#define NS_STYLE_FONT_STRETCH_EXTRA_EXPANDED    NS_FONT_STRETCH_EXTRA_EXPANDED
+#define NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED    NS_FONT_STRETCH_ULTRA_EXPANDED
+#define NS_STYLE_FONT_STRETCH_WIDER             NS_FONT_STRETCH_WIDER
+#define NS_STYLE_FONT_STRETCH_NARROWER          NS_FONT_STRETCH_NARROWER
 
 // See nsStyleFont - system fonts
 #define NS_STYLE_FONT_CAPTION                   1		// css2
 #define NS_STYLE_FONT_ICON                      2
 #define NS_STYLE_FONT_MENU                      3
 #define NS_STYLE_FONT_MESSAGE_BOX               4
 #define NS_STYLE_FONT_SMALL_CAPTION             5
 #define NS_STYLE_FONT_STATUS_BAR                6
--- a/layout/mathml/base/src/nsMathMLChar.cpp
+++ b/layout/mathml/base/src/nsMathMLChar.cpp
@@ -801,17 +801,17 @@ InitGlobals(nsPresContext* aPresContext)
   value.Truncate();
   rv = LoadProperties(value, mathfontProp);
   if (NS_FAILED(rv)) return rv;
 
   // Get the list of mathfonts having special glyph tables to be used for
   // stretchy characters.
   // We just want to iterate over the font-family list using the
   // callback mechanism that nsFont has...
-  nsFont font("", 0, 0, 0, 0, 0);
+  nsFont font("", 0, 0, 0, 0, 0, 0);
   NS_NAMED_LITERAL_CSTRING(defaultKey, "font.mathfont-glyph-tables");
   rv = mathfontProp->GetStringProperty(defaultKey, font.name);
   if (NS_FAILED(rv)) return rv;
 
   // Parse the font list and append an entry for each family to gGlyphTableList
   nsAutoString missingFamilyList;
 
 #if ALERT_MISSING_FONTS
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -5737,17 +5737,17 @@ CSSParserImpl::ParseFontDescriptorValue(
     if (!ParseFamily(aValue) ||
         aValue.GetUnit() != eCSSUnit_String)
       return PR_FALSE;
 
     // the style parameters to the nsFont constructor are ignored,
     // because it's only being used to call EnumerateFamilies
     nsAutoString valueStr;
     aValue.GetStringValue(valueStr);
-    nsFont font(valueStr, 0, 0, 0, 0, 0);
+    nsFont font(valueStr, 0, 0, 0, 0, 0, 0);
     ExtractFirstFamilyData dat;
 
     font.EnumerateFamilies(ExtractFirstFamily, (void*) &dat);
     if (!dat.mGood)
       return PR_FALSE;
 
     aValue.SetStringValue(dat.mFamilyName, eCSSUnit_String);
     return PR_TRUE;
@@ -7301,17 +7301,17 @@ CSSParserImpl::ParseFontSrc(nsCSSValue& 
         return PR_FALSE;
       if (!ParseOneFamily(family))
         return PR_FALSE;
       if (!ExpectSymbol(')', PR_TRUE))
         return PR_FALSE;
 
       // the style parameters to the nsFont constructor are ignored,
       // because it's only being used to call EnumerateFamilies
-      nsFont font(family, 0, 0, 0, 0, 0);
+      nsFont font(family, 0, 0, 0, 0, 0, 0);
       ExtractFirstFamilyData dat;
 
       font.EnumerateFamilies(ExtractFirstFamily, (void*) &dat);
       if (!dat.mGood)
         return PR_FALSE;
 
       cur.SetStringValue(dat.mFamilyName, eCSSUnit_Local_Font);
       values.AppendElement(cur);
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -415,17 +415,17 @@ CSS_PROP_DISPLAY(display, display, Displ
 CSS_PROP_BACKENDONLY(elevation, elevation, Elevation, 0, Aural, mElevation, eCSSType_Value, kElevationKTable)
 CSS_PROP_TABLEBORDER(empty-cells, empty_cells, EmptyCells, 0, Table, mEmptyCells, eCSSType_Value, kEmptyCellsKTable)
 CSS_PROP_DISPLAY(float, float, CssFloat, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER, Display, mFloat, eCSSType_Value, kFloatKTable)
 CSS_PROP_BORDER(-moz-float-edge, float_edge, MozFloatEdge, 0, Margin, mFloatEdge, eCSSType_Value, kFloatEdgeKTable) // XXX bug 3935
 CSS_PROP_SHORTHAND(font, font, Font, 0)
 CSS_PROP_FONT(font-family, font_family, FontFamily, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE, Font, mFamily, eCSSType_Value, nsnull)
 CSS_PROP_FONT(font-size, font_size, FontSize, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE, Font, mSize, eCSSType_Value, kFontSizeKTable)
 CSS_PROP_FONT(font-size-adjust, font_size_adjust, FontSizeAdjust, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE, Font, mSizeAdjust, eCSSType_Value, nsnull)
-CSS_PROP_BACKENDONLY(font-stretch, font_stretch, FontStretch, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE, Font, mStretch, eCSSType_Value, kFontStretchKTable)
+CSS_PROP_FONT(font-stretch, font_stretch, FontStretch, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE, Font, mStretch, eCSSType_Value, kFontStretchKTable)
 CSS_PROP_FONT(font-style, font_style, FontStyle, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE, Font, mStyle, eCSSType_Value, kFontStyleKTable)
 CSS_PROP_FONT(font-variant, font_variant, FontVariant, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE, Font, mVariant, eCSSType_Value, kFontVariantKTable)
 CSS_PROP_FONT(font-weight, font_weight, FontWeight, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE, Font, mWeight, eCSSType_Value, kFontWeightKTable)
 CSS_PROP_UIRESET(-moz-force-broken-image-icon, force_broken_image_icon, MozForceBrokenImageIcon, 0, UserInterface, mForceBrokenImageIcon, eCSSType_Value, nsnull) // bug 58646
 CSS_PROP_POSITION(height, height, Height, 0, Position, mHeight, eCSSType_Value, nsnull)
 CSS_PROP_LIST(-moz-image-region, image_region, MozImageRegion, 0, List, mImageRegion, eCSSType_Rect, nsnull)
 CSS_PROP_UIRESET(ime-mode, ime_mode, ImeMode, 0, UserInterface, mIMEMode, eCSSType_Value, kIMEModeKTable)
 CSS_PROP_POSITION(left, left, Left, 0, Position, mOffset.mLeft, eCSSType_Value, nsnull)
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -68,16 +68,17 @@
 #include "nsIDocument.h"
 
 #include "nsCSSPseudoElements.h"
 #include "nsStyleSet.h"
 #include "imgIRequest.h"
 #include "nsInspectorCSSUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsFrameManager.h"
+#include "prlog.h"
 #include "nsCSSKeywords.h"
 #include "nsStyleCoord.h"
 #include "nsDisplayList.h"
 
 #if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
 #define DEBUG_ComputedDOMStyle
 #endif
 
@@ -1084,16 +1085,46 @@ nsComputedDOMStyle::GetFontSizeAdjust(ns
   } else {
     val->SetIdent(eCSSKeyword_none);
   }
 
   return CallQueryInterface(val, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetFontStretch(nsIDOMCSSValue** aValue)
+{
+  nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
+  NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
+
+  const nsStyleFont* font = GetStyleFont();
+
+  // The computed value space isn't actually representable in string
+  // form, so just represent anything with widers or narrowers in it as
+  // 'wider' or 'narrower'.
+  PR_STATIC_ASSERT(NS_FONT_STRETCH_NARROWER % 2 == 0);
+  PR_STATIC_ASSERT(NS_FONT_STRETCH_WIDER % 2 == 0);
+  PR_STATIC_ASSERT(NS_FONT_STRETCH_NARROWER + NS_FONT_STRETCH_WIDER == 0);
+  PR_STATIC_ASSERT(NS_FONT_STRETCH_NARROWER < 0);
+  PRInt16 stretch = font->mFont.stretch;
+  if (stretch == NS_FONT_STRETCH_NORMAL) {
+    val->SetIdent(eCSSKeyword_normal);
+  } else if (stretch <= NS_FONT_STRETCH_NARROWER / 2) {
+    val->SetIdent(eCSSKeyword_narrower);
+  } else if (stretch >= NS_FONT_STRETCH_WIDER / 2) {
+    val->SetIdent(eCSSKeyword_wider);
+  } else {
+    val->SetIdent(
+      nsCSSProps::ValueToKeywordEnum(stretch, nsCSSProps::kFontStretchKTable));
+  }
+
+  return CallQueryInterface(val, aValue);
+}
+
+nsresult
 nsComputedDOMStyle::GetFontStyle(nsIDOMCSSValue** aValue)
 {
   nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
   NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
 
   const nsStyleFont* font = GetStyleFont();
 
   if (font->mFont.style != NS_STYLE_FONT_STYLE_NORMAL) {
@@ -1109,16 +1140,17 @@ nsComputedDOMStyle::GetFontStyle(nsIDOMC
 nsresult
 nsComputedDOMStyle::GetFontWeight(nsIDOMCSSValue** aValue)
 {
   nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
   NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
 
   const nsStyleFont* font = GetStyleFont();
 
+  // XXX This doesn't deal with bolder/lighter very well.
   const nsCSSKeyword enum_weight =
     nsCSSProps::ValueToKeywordEnum(font->mFont.weight,
                                    nsCSSProps::kFontWeightKTable);
   if (enum_weight != eCSSKeyword_UNKNOWN) {
     val->SetIdent(enum_weight);
   } else {
     val->SetNumber(font->mFont.weight);
   }
@@ -4020,17 +4052,17 @@ nsComputedDOMStyle::GetQueryableProperty
     COMPUTED_STYLE_MAP_ENTRY(display,                       Display),
     // COMPUTED_STYLE_MAP_ENTRY(elevation,                  Elevation),
     COMPUTED_STYLE_MAP_ENTRY(empty_cells,                   EmptyCells),
     COMPUTED_STYLE_MAP_ENTRY(float,                         CssFloat),
     //// COMPUTED_STYLE_MAP_ENTRY(font,                     Font),
     COMPUTED_STYLE_MAP_ENTRY(font_family,                   FontFamily),
     COMPUTED_STYLE_MAP_ENTRY(font_size,                     FontSize),
     COMPUTED_STYLE_MAP_ENTRY(font_size_adjust,              FontSizeAdjust),
-    // COMPUTED_STYLE_MAP_ENTRY(font_stretch,               FontStretch),
+    COMPUTED_STYLE_MAP_ENTRY(font_stretch,                  FontStretch),
     COMPUTED_STYLE_MAP_ENTRY(font_style,                    FontStyle),
     COMPUTED_STYLE_MAP_ENTRY(font_variant,                  FontVariant),
     COMPUTED_STYLE_MAP_ENTRY(font_weight,                   FontWeight),
     COMPUTED_STYLE_MAP_ENTRY(height,                        Height),
     COMPUTED_STYLE_MAP_ENTRY(left,                          Left),
     COMPUTED_STYLE_MAP_ENTRY(letter_spacing,                LetterSpacing),
     COMPUTED_STYLE_MAP_ENTRY(line_height,                   LineHeight),
     //// COMPUTED_STYLE_MAP_ENTRY(list_style,               ListStyle),
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -141,19 +141,20 @@ private:
   nsresult GetTop(nsIDOMCSSValue** aValue);
   nsresult GetRight(nsIDOMCSSValue** aValue);
   nsresult GetBottom(nsIDOMCSSValue** aValue);
   nsresult GetStackSizing(nsIDOMCSSValue** aValue);
 
   /* Font properties */
   nsresult GetColor(nsIDOMCSSValue** aValue);
   nsresult GetFontFamily(nsIDOMCSSValue** aValue);
-  nsresult GetFontStyle(nsIDOMCSSValue** aValue);
   nsresult GetFontSize(nsIDOMCSSValue** aValue);
   nsresult GetFontSizeAdjust(nsIDOMCSSValue** aValue);
+  nsresult GetFontStretch(nsIDOMCSSValue** aValue);
+  nsresult GetFontStyle(nsIDOMCSSValue** aValue);
   nsresult GetFontWeight(nsIDOMCSSValue** aValue);
   nsresult GetFontVariant(nsIDOMCSSValue** aValue);
 
   /* Background properties */
   nsresult GetBackgroundAttachment(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundColor(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundImage(nsIDOMCSSValue** aValue);
   nsresult GetBackgroundPosition(nsIDOMCSSValue** aValue);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -908,28 +908,32 @@ static nsRuleNode::RuleDetail
 CheckFontCallback(const nsRuleDataStruct& aData,
                   nsRuleNode::RuleDetail aResult)
 {
   const nsRuleDataFont& fontData =
       static_cast<const nsRuleDataFont&>(aData);
 
   // em, ex, percent, 'larger', and 'smaller' values on font-size depend
   // on the parent context's font-size
-  // Likewise, 'lighter' and 'bolder' values of 'font-weight' depend on
-  // the parent.
+  // Likewise, 'lighter' and 'bolder' values of 'font-weight', and 'wider'
+  // and 'narrower' values of 'font-stretch' depend on the parent.
   const nsCSSValue& size = fontData.mSize;
   const nsCSSValue& weight = fontData.mWeight;
+  const nsCSSValue& stretch = fontData.mStretch;
   if ((size.IsRelativeLengthUnit() && size.GetUnit() != eCSSUnit_Pixel) ||
       size.GetUnit() == eCSSUnit_Percent ||
       (size.GetUnit() == eCSSUnit_Enumerated &&
        (size.GetIntValue() == NS_STYLE_FONT_SIZE_SMALLER ||
         size.GetIntValue() == NS_STYLE_FONT_SIZE_LARGER)) ||
 #ifdef MOZ_MATHML
       fontData.mScriptLevel.GetUnit() == eCSSUnit_Integer ||
 #endif
+      (stretch.GetUnit() == eCSSUnit_Enumerated &&
+       (stretch.GetIntValue() == NS_FONT_STRETCH_NARROWER ||
+        stretch.GetIntValue() == NS_FONT_STRETCH_WIDER)) ||
       (weight.GetUnit() == eCSSUnit_Enumerated &&
        (weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_BOLDER ||
         weight.GetIntValue() == NS_STYLE_FONT_WEIGHT_LIGHTER))) {
     NS_ASSERTION(aResult == nsRuleNode::eRulePartialReset ||
                  aResult == nsRuleNode::eRuleFullReset ||
                  aResult == nsRuleNode::eRulePartialMixed ||
                  aResult == nsRuleNode::eRuleFullMixed,
                  "we know we already have a reset-counted property");
@@ -2604,16 +2608,36 @@ nsRuleNode::SetFont(nsPresContext* aPres
     SetDiscrete(aFontData.mWeight, aFont->mFont.weight, aInherited,
                 SETDSC_INTEGER | SETDSC_NORMAL | SETDSC_SYSTEM_FONT,
                 aParentFont->mFont.weight,
                 defaultVariableFont->weight,
                 0, 0,
                 NS_STYLE_FONT_WEIGHT_NORMAL,
                 systemFont.weight);
 
+  // font-stretch: enum, normal, inherit
+  if (eCSSUnit_Enumerated == aFontData.mStretch.GetUnit()) {
+    PRInt32 value = aFontData.mStretch.GetIntValue();
+    switch (value) {
+      case NS_FONT_STRETCH_WIDER:
+      case NS_FONT_STRETCH_NARROWER:
+        aInherited = PR_TRUE;
+        aFont->mFont.stretch = aParentFont->mFont.stretch + value;
+        break;
+      default:
+        aFont->mFont.stretch = value;
+        break;
+    }
+  } else
+    SetDiscrete(aFontData.mStretch, aFont->mFont.stretch, aInherited,
+                SETDSC_NORMAL | SETDSC_SYSTEM_FONT,
+                aParentFont->mFont.stretch,
+                defaultVariableFont->stretch,
+                0, 0, NS_FONT_STRETCH_NORMAL, systemFont.stretch);
+
 #ifdef MOZ_MATHML
   // Compute scriptlevel, scriptminsize and scriptsizemultiplier now so
   // they're available for font-size computation.
 
   // -moz-script-min-size: length
   if (aFontData.mScriptMinSize.IsLengthUnit()) {
     // scriptminsize in font units (em, ex) has to be interpreted relative
     // to the parent font, or the size definitions are circular and we
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -197,16 +197,17 @@ nsStyleFont::UnZoomText(nsPresContext *a
 nsChangeHint nsStyleFont::CalcFontDifference(const nsFont& aFont1, const nsFont& aFont2)
 {
   if ((aFont1.size == aFont2.size) && 
       (aFont1.sizeAdjust == aFont2.sizeAdjust) && 
       (aFont1.style == aFont2.style) &&
       (aFont1.variant == aFont2.variant) &&
       (aFont1.familyNameQuirks == aFont2.familyNameQuirks) &&
       (aFont1.weight == aFont2.weight) &&
+      (aFont1.stretch == aFont2.stretch) &&
       (aFont1.name == aFont2.name)) {
     if ((aFont1.decorations == aFont2.decorations)) {
       return NS_STYLE_HINT_NONE;
     }
     return NS_STYLE_HINT_VISUAL;
   }
   return NS_STYLE_HINT_REFLOW;
 }
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1035,17 +1035,16 @@ var gCSSProperties = {
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "none" ],
 		other_values: [ "0.3", "0.5", "0.7" ],
 		invalid_values: []
 	},
 	"font-stretch": {
 		domProp: "fontStretch",
 		inherited: true,
-		backend_only: true,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "normal" ],
 		other_values: [ "wider", "narrower", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded" ],
 		invalid_values: []
 	},
 	"font-style": {
 		domProp: "fontStyle",
 		inherited: true,
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp
+++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp
@@ -1272,18 +1272,18 @@ nsSVGGlyphFrame::EnsureTextRun(float *aD
       textRunSize = size*contextScale;
       textRunSize = PR_MAX(textRunSize, CLAMP_MIN_SIZE);
       textRunSize = PR_MIN(textRunSize, CLAMP_MAX_SIZE);
     }
 
     const nsFont& font = fontData->mFont;
     PRBool printerFont = (presContext->Type() == nsPresContext::eContext_PrintPreview ||
                           presContext->Type() == nsPresContext::eContext_Print);
-    gfxFontStyle fontStyle(font.style, font.weight, textRunSize, langGroup,
-                           font.sizeAdjust, font.systemFont,
+    gfxFontStyle fontStyle(font.style, font.weight, font.stretch, textRunSize,
+                           langGroup, font.sizeAdjust, font.systemFont,
                            font.familyNameQuirks,
                            printerFont);
 
     nsRefPtr<gfxFontGroup> fontGroup =
       gfxPlatform::GetPlatform()->CreateFontGroup(font.name, &fontStyle, presContext->GetUserFontSet());
 
     PRUint32 flags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX |
       nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(), GetStyleText(), GetStyleFont());