From a7c4c98a223f6dd1370f3a7a00e65b8e94f2e742 Mon Sep 17 00:00:00 2001
From: bungeman <bungeman@google.com>
Date: Thu, 28 Aug 2014 11:42:29 -0700
Subject: [PATCH] <third_party/skia> Fix error handling in DirectWrite with
 tiny text.

If there is an error while trying to determine the metrics,
we need to bail instead of potentially using uninitialized data.

R=reed@google.com, mtklein@google.com

Author: bungeman@google.com

Review URL: https://codereview.chromium.org/511783003

Change-Id: I03abc22567396b7e174380e10fc0007523355473
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
---
 .../skia/src/ports/SkScalerContext_win_dw.cpp | 86 ++++++++++++-------
 .../skia/src/ports/SkScalerContext_win_dw.h   |  8 +-
 2 files changed, 57 insertions(+), 37 deletions(-)

diff --git a/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.cpp b/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.cpp
index e1fc92fc09c..67a6c4ff1d2 100644
--- a/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.cpp
+++ b/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.cpp
@@ -404,10 +404,10 @@ void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) {
     glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY);
 }
 
-void SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
-                                        DWRITE_RENDERING_MODE renderingMode,
-                                        DWRITE_TEXTURE_TYPE textureType,
-                                        RECT* bbox)
+HRESULT SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
+                                           DWRITE_RENDERING_MODE renderingMode,
+                                           DWRITE_TEXTURE_TYPE textureType,
+                                           RECT* bbox)
 {
     //Measure raster size.
     fXform.dx = SkFixedToFloat(glyph->getSubXFixed());
@@ -432,50 +432,70 @@ void SkScalerContext_DW::getBoundingBox(SkGlyph* glyph,
     run.glyphOffsets = &offset;
 
     SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis;
-    HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis(
-             &run,
-             1.0f, // pixelsPerDip,
-             &fXform,
-             renderingMode,
-             fMeasuringMode,
-             0.0f, // baselineOriginX,
-             0.0f, // baselineOriginY,
-             &glyphRunAnalysis),
-         "Could not create glyph run analysis.");
+    HRM(fTypeface->fFactory->CreateGlyphRunAnalysis(
+            &run,
+            1.0f, // pixelsPerDip,
+            &fXform,
+            renderingMode,
+            fMeasuringMode,
+            0.0f, // baselineOriginX,
+            0.0f, // baselineOriginY,
+            &glyphRunAnalysis),
+        "Could not create glyph run analysis.");
+
+    HRM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
+        "Could not get texture bounds.");
+
+    return S_OK;
+}
 
-    HRVM(glyphRunAnalysis->GetAlphaTextureBounds(textureType, bbox),
-         "Could not get texture bounds.");
+/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
+ *  { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
+ *  for small, but not quite zero, sized glyphs.
+ *  Only set as non-empty if the returned bounds are non-empty.
+ */
+static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
+    if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
+        return false;
+    }
+    glyph->fWidth = SkToU16(bbox.right - bbox.left);
+    glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
+    glyph->fLeft = SkToS16(bbox.left);
+    glyph->fTop = SkToS16(bbox.top);
+    return true;
 }
 
 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) {
     glyph->fWidth = 0;
+    glyph->fHeight = 0;
+    glyph->fLeft = 0;
+    glyph->fTop = 0;
 
     this->generateAdvance(glyph);
 
     RECT bbox;
-    this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox);
+    HRVM(this->getBoundingBox(glyph, fRenderingMode, fTextureType, &bbox),
+         "Requested bounding box could not be determined.");
+
+    if (glyph_check_and_set_bounds(glyph, bbox)) {
+        return;
+    }
 
     // GetAlphaTextureBounds succeeds but returns an empty RECT if there are no
     // glyphs of the specified texture type. When this happens, try with the
     // alternate texture type.
-    if (bbox.left == bbox.right || bbox.top == bbox.bottom) {
-        if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
-            this->getBoundingBox(glyph,
-                                 DWRITE_RENDERING_MODE_ALIASED,
-                                 DWRITE_TEXTURE_ALIASED_1x1,
-                                 &bbox);
-            if (bbox.left != bbox.right && bbox.top != bbox.bottom) {
-                glyph->fForceBW = 1;
-            }
+    if (DWRITE_TEXTURE_CLEARTYPE_3x1 == fTextureType) {
+        HRVM(this->getBoundingBox(glyph,
+                                  DWRITE_RENDERING_MODE_ALIASED,
+                                  DWRITE_TEXTURE_ALIASED_1x1,
+                                  &bbox),
+             "Fallback bounding box could not be determined.");
+        if (glyph_check_and_set_bounds(glyph, bbox)) {
+            glyph->fForceBW = 1;
         }
-        // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
-        // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
     }
-
-    glyph->fWidth = SkToU16(bbox.right - bbox.left);
-    glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
-    glyph->fLeft = SkToS16(bbox.left);
-    glyph->fTop = SkToS16(bbox.top);
+    // TODO: handle the case where a request for DWRITE_TEXTURE_ALIASED_1x1
+    // fails, and try DWRITE_TEXTURE_CLEARTYPE_3x1.
 }
 
 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx,
diff --git a/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.h b/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.h
index 0edd869d05d..3af90a73bb7 100644
--- a/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.h
+++ b/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.h
@@ -38,10 +38,10 @@ private:
                            DWRITE_RENDERING_MODE renderingMode,
                            DWRITE_TEXTURE_TYPE textureType);
 
-    void getBoundingBox(SkGlyph* glyph,
-                        DWRITE_RENDERING_MODE renderingMode,
-                        DWRITE_TEXTURE_TYPE textureType,
-                        RECT* bbox);
+    HRESULT getBoundingBox(SkGlyph* glyph,
+                           DWRITE_RENDERING_MODE renderingMode,
+                           DWRITE_TEXTURE_TYPE textureType,
+                           RECT* bbox);
 
     SkTDArray<uint8_t> fBits;
     /** The total matrix without the text height scale. */
-- 
GitLab