| Index: gm/typeface.cpp | 
| diff --git a/gm/typeface.cpp b/gm/typeface.cpp | 
| index e4e0d24867bde99524c45b0901e29373dc5f27d4..8b6a64866bb259291f3e7c2557a12e205a3ccffe 100644 | 
| --- a/gm/typeface.cpp | 
| +++ b/gm/typeface.cpp | 
| @@ -6,8 +6,10 @@ | 
| */ | 
|  | 
| #include "gm.h" | 
| +#include "Resources.h" | 
| #include "SkCanvas.h" | 
| #include "SkString.h" | 
| +#include "SkSurfaceProps.h" | 
| #include "SkTypeface.h" | 
| #include "SkTypes.h" | 
|  | 
| @@ -152,7 +154,128 @@ private: | 
| typedef skiagm::GM INHERITED; | 
| }; | 
|  | 
| +static void rotate_about(SkCanvas* canvas, | 
| +                         SkScalar degrees, | 
| +                         SkScalar px, SkScalar py) { | 
| +    canvas->translate(px, py); | 
| +    canvas->rotate(degrees); | 
| +    canvas->translate(-px, -py); | 
| +} | 
| + | 
| +class TypefaceRenderingGM : public skiagm::GM { | 
| +    sk_sp<SkTypeface> fFace; | 
| + | 
| +public: | 
| +    TypefaceRenderingGM() { } | 
| + | 
| +protected: | 
| +    void onOnceBeforeDraw() override { | 
| +        fFace = MakeResourceAsTypeface("/fonts/hintgasp.ttf"); | 
| +    } | 
| + | 
| +    SkString onShortName() override { | 
| +        SkString name("typefacerendering"); | 
| +        name.append(sk_tool_utils::major_platform_os_name()); | 
| +        return name; | 
| +    } | 
| + | 
| +    SkISize onISize() override { | 
| +        return SkISize::Make(640, 480); | 
| +    } | 
| + | 
| +    void onDraw(SkCanvas* canvas) override { | 
| +        struct AliasType { | 
| +            bool antiAlias; | 
| +            bool subpixelAntitalias; | 
| +            bool inLayer; | 
| +        } constexpr aliasTypes[] { | 
| +            { false, false, false },  // aliased | 
| +            { true,  false, false },  // anti-aliased | 
| +            { true,  true , false },  // subpixel anti-aliased | 
| +            { true,  false, true  },  // anti-aliased in layer (flat pixel geometry) | 
| +            { true,  true , true  },  // subpixel anti-aliased in layer (flat pixel geometry) | 
| +        }; | 
| + | 
| +        // The hintgasp.ttf is designed for the following sizes to be different. | 
| +        // GASP_DOGRAY                                      0x0002   0<=ppem<=10 | 
| +        // GASP_SYMMETRIC_SMOOTHING                         0x0008   0<=ppem<=10 | 
| +        // GASP_GRIDFIT                                     0x0001  11<=ppem<=12 | 
| +        // GASP_SYMMETRIC_GRIDFIT                           0x0004  11<=ppem<=12 | 
| +        // GASP_DOGRAY|GASP_GRIDFIT                         0x0003  13<=ppem<=14 | 
| +        // GASP_SYMMETRIC_SMOOTHING|GASP_SYMMETRIC_GRIDFIT  0x000C  13<=ppem<=14 | 
| +        // (neither)                                        0x0000  15<=ppem | 
| +        constexpr SkScalar textSizes[] = { 10, 12, 14, 16 }; | 
| + | 
| +        constexpr SkPaint::Hinting hintingTypes[] = { SkPaint::kNo_Hinting, | 
| +                                                      SkPaint::kSlight_Hinting, | 
| +                                                      SkPaint::kNormal_Hinting, | 
| +                                                      SkPaint::kFull_Hinting }; | 
| + | 
| +        struct SubpixelType { | 
| +            bool requested; | 
| +            SkVector offset; | 
| +        } constexpr subpixelTypes[] = { | 
| +            { false, { 0.00, 0.00 } }, | 
| +            { true , { 0.00, 0.00 } }, | 
| +            { true , { 0.25, 0.00 } }, | 
| +            { true , { 0.25, 0.25 } }, | 
| +        }; | 
| + | 
| +        constexpr bool rotateABitTypes[] = { false, true }; | 
| + | 
| +        SkPaint paint; | 
| +        SkScalar x = 0; | 
| +        SkScalar xMax = x; | 
| +        SkScalar xBase = 0; | 
| +        SkScalar y = 0;  // The baseline of the previous output | 
| +        for (const SubpixelType subpixel : subpixelTypes) { | 
| +            y = 0; | 
| +            paint.setSubpixelText(subpixel.requested); | 
| + | 
| +            for (const AliasType& alias : aliasTypes) { | 
| +                paint.setAntiAlias(alias.antiAlias); | 
| +                paint.setLCDRenderText(alias.subpixelAntitalias); | 
| +                SkAutoCanvasRestore acr(canvas, false); | 
| +                if (alias.inLayer) { | 
| +                    canvas->saveLayer(nullptr, &paint); | 
| +                } | 
| + | 
| +                for (const SkScalar& textSize : textSizes) { | 
| +                    x = xBase + 5; | 
| +                    paint.setTextSize(textSize); | 
| + | 
| +                    SkScalar dy = SkScalarCeilToScalar(paint.getFontMetrics(nullptr)); | 
| +                    y += dy; | 
| +                    for (const SkPaint::Hinting& hinting : hintingTypes) { | 
| +                        paint.setHinting(hinting); | 
| + | 
| +                        for (const bool& rotateABit : rotateABitTypes) { | 
| +                            SkAutoCanvasRestore acr(canvas, true); | 
| +                            if (rotateABit) { | 
| +                                rotate_about(canvas, 2, x + subpixel.offset.x(), | 
| +                                                        y + subpixel.offset.y()); | 
| +                            } | 
| +                            canvas->drawText("A", 1, x + subpixel.offset.x(), | 
| +                                                     y + subpixel.offset.y(), paint); | 
| + | 
| +                            SkScalar dx = SkScalarCeilToScalar(paint.measureText("A", 1)) + 5; | 
| +                            x += dx; | 
| +                            xMax = SkTMax(x, xMax); | 
| +                        } | 
| +                    } | 
| +                } | 
| +                y += 10; | 
| +            } | 
| +            xBase = xMax; | 
| +        } | 
| +    } | 
| + | 
| +private: | 
| +    typedef skiagm::GM INHERITED; | 
| +}; | 
| + | 
| /////////////////////////////////////////////////////////////////////////////// | 
|  | 
| DEF_GM( return new TypefaceStylesGM(false); ) | 
| DEF_GM( return new TypefaceStylesGM(true); ) | 
| +DEF_GM( return new TypefaceRenderingGM(); ) | 
|  |