Bug 648472 - [OS/2] avoid crashes when FcFontMatch() fails; r=wuno a=NPOTB DONTBUILD
authorRich Walsh <dragtext@e-vertise.com>
Sat, 09 Apr 2011 23:32:09 -0400
changeset 63399 be7d2d8c53e349e5970144fd55cb83e1b5e45eb9
parent 63398 cbe443e3f0e5076c2566cd518d818f627d764978
child 63400 66ccb8edc1cc314d2a37aef65a147f4717ecba87
child 63401 a351bc91fab25bd15ffc1fc26ec6b624465e74ac
push id53
push usereakhgari@mozilla.com
push dateMon, 11 Apr 2011 21:02:42 +0000
reviewerswuno, NPOTB
bugs648472
milestone2.0.1pre
Bug 648472 - [OS/2] avoid crashes when FcFontMatch() fails; r=wuno a=NPOTB DONTBUILD
gfx/thebes/gfxOS2Fonts.cpp
--- a/gfx/thebes/gfxOS2Fonts.cpp
+++ b/gfx/thebes/gfxOS2Fonts.cpp
@@ -157,28 +157,34 @@ const gfxFont::Metrics& gfxOS2Font::GetM
     // whatever happens below, we can always create the metrics
     mMetrics = new gfxFont::Metrics;
     mSpaceGlyph = 0;
 
     // round size to integer pixels, this is to get full pixels for layout
     // together with internal/external leading (see below)
     mMetrics->emHeight = NS_floor(GetStyle()->size + 0.5);
 
-    FT_Face face = cairo_ft_scaled_font_lock_face(CairoScaledFont());
+    cairo_scaled_font_t* scaledFont = CairoScaledFont();
+    if (!scaledFont) {
+        FillMetricsDefaults(mMetrics);
+        return *mMetrics;
+    }
+
+    FT_Face face = cairo_ft_scaled_font_lock_face(scaledFont);
     if (!face) {
         // Abort here already, otherwise we crash in the following
         // this can happen if the font-size requested is zero.
         FillMetricsDefaults(mMetrics);
         return *mMetrics;
     }
     if (!face->charmap) {
         // Also abort, if the charmap isn't loaded; then the char
         // lookups won't work. This happens for fonts without Unicode
         // charmap.
-        cairo_ft_scaled_font_unlock_face(CairoScaledFont());
+        cairo_ft_scaled_font_unlock_face(scaledFont);
         FillMetricsDefaults(mMetrics);
         return *mMetrics;
     }
 
     // compute font scaling factors
     gfxFloat emUnit = 1.0 * face->units_per_EM;
     gfxFloat xScale = face->size->metrics.x_ppem / emUnit;
     gfxFloat yScale = face->size->metrics.y_ppem / emUnit;
@@ -300,17 +306,17 @@ const gfxFont::Metrics& gfxOS2Font::GetM
            mMetrics->superscriptOffset, mMetrics->subscriptOffset,
            mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
            mMetrics->underlineOffset, mMetrics->underlineSize,
            mMetrics->internalLeading, mMetrics->externalLeading,
            mMetrics->emAscent, mMetrics->emDescent, mMetrics->maxHeight,
            mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance
           );
 #endif
-    cairo_ft_scaled_font_unlock_face(CairoScaledFont());
+    cairo_ft_scaled_font_unlock_face(scaledFont);
     return *mMetrics;
 }
 
 // weight list copied from fontconfig.h
 // unfortunately, the OS/2 version so far only supports regular and bold
 static const PRInt8 nFcWeight = 2; // 10; // length of weight list
 static const int fcWeight[] = {
     //FC_WEIGHT_THIN,
@@ -386,16 +392,35 @@ cairo_font_face_t *gfxOS2Font::CairoFont
 
         // add the size we want
         FcPatternAddDouble(fcPattern, FC_PIXEL_SIZE,
                            mAdjustedSize ? mAdjustedSize : GetStyle()->size);
 
         // finally find a matching font
         FcResult fcRes;
         FcPattern *fcMatch = FcFontMatch(NULL, fcPattern, &fcRes);
+
+        // Most code that depends on FcFontMatch() assumes it won't fail,
+        // then crashes when it does.  For now, at least, substitute the
+        // default serif font when it fails to avoid those crashes.
+        if (!fcMatch) {
+//#ifdef DEBUG
+            printf("Could not match font for:\n"
+                   "  family=%s, weight=%d, slant=%d, size=%f\n",
+                   NS_LossyConvertUTF16toASCII(GetName()).get(),
+                   GetStyle()->weight, GetStyle()->style, GetStyle()->size);
+//#endif
+            // FcPatternAddString() will free the existing FC_FAMILY string
+            FcPatternAddString(fcPattern, FC_FAMILY, (FcChar8*)"SERIF");
+            fcMatch = FcFontMatch(NULL, fcPattern, &fcRes);
+//#ifdef DEBUG
+            printf("Attempt to substitute default SERIF font %s\n",
+                   fcMatch ? "succeeded" : "failed");
+//#endif
+        }
         FcPatternDestroy(fcPattern);
 
         if (fcMatch) {
             int w = FC_WEIGHT_REGULAR;
             FcPatternGetInteger(fcMatch, FC_WEIGHT, 0, &w);
             if (fcW >= FC_WEIGHT_DEMIBOLD && w < FC_WEIGHT_DEMIBOLD) {
                 // if we want a bold font, but the selected font doesn't have a
                 // bold counterpart, artificially embolden it
@@ -403,23 +428,16 @@ cairo_font_face_t *gfxOS2Font::CairoFont
             }
             FcPatternAddBool(fcMatch, FC_ANTIALIAS, mAntialias);
             FcPatternAddInteger(fcMatch, FC_HINT_STYLE, mHinting);
 
             // and ask cairo to return a font face for this
             mFontFace = cairo_ft_font_face_create_for_pattern(fcMatch);
 
             FcPatternDestroy(fcMatch);
-        } else {
-#ifdef DEBUG
-            printf("Could not match font for:\n"
-                   "  family=%s, weight=%d, slant=%d, size=%f\n",
-                   NS_LossyConvertUTF16toASCII(GetName()).get(),
-                   GetStyle()->weight, GetStyle()->style, GetStyle()->size);
-#endif
         }
     }
 
     NS_ASSERTION(mFontFace, "Failed to make font face");
     return mFontFace;
 }
 
 cairo_scaled_font_t *gfxOS2Font::CairoScaledFont()
@@ -443,18 +461,23 @@ cairo_scaled_font_t *gfxOS2Font::CairoSc
     if (!mFontEntry->mItalic &&
         (mStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)))
     {
         const double kSkewFactor = 0.2126; // 12 deg skew as used in e.g. ftview
         cairo_matrix_init(&fontMatrix, size, 0, -kSkewFactor*size, size, 0, 0);
     } else {
         cairo_matrix_init_scale(&fontMatrix, size, size);
     }
+
+    cairo_font_face_t * face = CairoFontFace();
+    if (!face)
+        return nsnull;
+
     cairo_font_options_t *fontOptions = cairo_font_options_create();
-    mScaledFont = cairo_scaled_font_create(CairoFontFace(), &fontMatrix,
+    mScaledFont = cairo_scaled_font_create(face, &fontMatrix,
                                            &identityMatrix, fontOptions);
     cairo_font_options_destroy(fontOptions);
 
     NS_ASSERTION(cairo_scaled_font_status(mScaledFont) == CAIRO_STATUS_SUCCESS,
                  "Failed to make scaled font");
     return mScaledFont;
 }
 
@@ -474,17 +497,17 @@ PRBool gfxOS2Font::SetupCairoFont(gfxCon
 #ifdef DEBUG_thebes_2
     printf("gfxOS2Font[%#x]::SetupCairoFont(%#x)\n",
            (unsigned)this, (unsigned) aContext);
 #endif
     // gfxPangoFont checks the CTM but Windows doesn't so leave away here, too
 
     // this implicitely ensures that mScaledFont is created if NULL
     cairo_scaled_font_t *scaledFont = CairoScaledFont();
-    if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
+    if (!scaledFont || cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
         // Don't cairo_set_scaled_font as that would propagate the error to
         // the cairo_t, precluding any further drawing.
         return PR_FALSE;
     }
     cairo_set_scaled_font(aContext->GetCairo(), scaledFont);
     return PR_TRUE;
 }