Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "gm.h"
      9 
     10 #include "Resources.h"
     11 #include "SkBlurMask.h"
     12 #include "SkBlurMaskFilter.h"
     13 #include "SkCanvas.h"
     14 #include "SkGradientShader.h"
     15 #include "SkImage.h"
     16 #include "SkRandom.h"
     17 #include "SkStream.h"
     18 #include "SkSurface.h"
     19 #include "SkTextBlob.h"
     20 #include "SkTypeface.h"
     21 
     22 namespace skiagm {
     23 class TextBlobMixedSizes : public GM {
     24 public:
     25     // This gm tests that textblobs of mixed sizes with a large glyph will render properly
     26     TextBlobMixedSizes(bool useDFT) : fUseDFT(useDFT) {}
     27 
     28 protected:
     29     void onOnceBeforeDraw() override {
     30         SkAutoTUnref<SkTypeface> typeface(GetResourceAsTypeface("/fonts/HangingS.ttf"));
     31         SkTextBlobBuilder builder;
     32 
     33         // make textblob.  To stress distance fields, we choose sizes appropriately
     34         SkPaint paint;
     35         paint.setAntiAlias(true);
     36         paint.setSubpixelText(true);
     37         paint.setLCDRenderText(true);
     38         paint.setTypeface(typeface);
     39 
     40         const char* text = "Skia";
     41 
     42         // extra large
     43         paint.setTextSize(262);
     44 
     45         sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, 0);
     46 
     47         // large
     48         SkRect bounds;
     49         paint.measureText(text, strlen(text), &bounds);
     50         SkScalar yOffset = bounds.height();
     51         paint.setTextSize(162);
     52 
     53         sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset);
     54 
     55         // Medium
     56         paint.measureText(text, strlen(text), &bounds);
     57         yOffset += bounds.height();
     58         paint.setTextSize(72);
     59 
     60         sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset);
     61 
     62         // Small
     63         paint.measureText(text, strlen(text), &bounds);
     64         yOffset += bounds.height();
     65         paint.setTextSize(32);
     66 
     67         sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset);
     68 
     69         // micro (will fall out of distance field text even if distance field text is enabled)
     70         paint.measureText(text, strlen(text), &bounds);
     71         yOffset += bounds.height();
     72         paint.setTextSize(14);
     73 
     74         sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset);
     75 
     76         // build
     77         fBlob.reset(builder.build());
     78     }
     79 
     80     SkString onShortName() override {
     81         SkString name("textblobmixedsizes");
     82         if (fUseDFT) {
     83             name.appendf("_df");
     84         }
     85         return name;
     86     }
     87 
     88     SkISize onISize() override {
     89         return SkISize::Make(kWidth, kHeight);
     90     }
     91 
     92     void onDraw(SkCanvas* inputCanvas) override {
     93         SkCanvas* canvas = inputCanvas;
     94         SkAutoTUnref<SkSurface> surface;
     95         if (fUseDFT) {
     96 #if SK_SUPPORT_GPU
     97             // Create a new Canvas to enable DFT
     98             GrContext* ctx = inputCanvas->getGrContext();
     99             SkImageInfo info = SkImageInfo::MakeN32Premul(onISize());
    100             SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag,
    101                                  SkSurfaceProps::kLegacyFontHost_InitType);
    102             surface.reset(SkSurface::NewRenderTarget(ctx, SkBudgeted::kNo, info, 0,
    103                                                      &props));
    104             canvas = surface.get() ? surface->getCanvas() : inputCanvas;
    105             // init our new canvas with the old canvas's matrix
    106             canvas->setMatrix(inputCanvas->getTotalMatrix());
    107 #endif
    108         }
    109         canvas->drawColor(sk_tool_utils::color_to_565(SK_ColorWHITE));
    110 
    111         SkRect bounds = fBlob->bounds();
    112 
    113         static const int kPadX = SkScalarFloorToInt(bounds.width() / 3);
    114         static const int kPadY = SkScalarFloorToInt(bounds.height() / 3);
    115 
    116         int rowCount = 0;
    117         canvas->translate(SkIntToScalar(kPadX), SkIntToScalar(kPadY));
    118         canvas->save();
    119         SkRandom random;
    120 
    121         SkPaint paint;
    122         if (!fUseDFT) {
    123             paint.setColor(sk_tool_utils::color_to_565(SK_ColorWHITE));
    124         }
    125         paint.setAntiAlias(false);
    126 
    127         static const SkScalar kSigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(8));
    128 
    129         // setup blur paint
    130         SkPaint blurPaint(paint);
    131         blurPaint.setColor(sk_tool_utils::color_to_565(SK_ColorBLACK));
    132         SkAutoTUnref<SkMaskFilter> mf(SkBlurMaskFilter::Create(kNormal_SkBlurStyle, kSigma));
    133         blurPaint.setMaskFilter(mf);
    134 
    135         for (int i = 0; i < 4; i++) {
    136             canvas->save();
    137             switch (i % 2) {
    138                 case 0:
    139                     canvas->rotate(random.nextF() * 45.f);
    140                     break;
    141                 case 1:
    142                     canvas->rotate(-random.nextF() * 45.f);
    143                     break;
    144             }
    145             if (!fUseDFT) {
    146                 canvas->drawTextBlob(fBlob, 0, 0, blurPaint);
    147             }
    148             canvas->drawTextBlob(fBlob, 0, 0, paint);
    149             canvas->restore();
    150             canvas->translate(bounds.width() + SK_Scalar1 * kPadX, 0);
    151             ++rowCount;
    152             if ((bounds.width() + 2 * kPadX) * rowCount > kWidth) {
    153                 canvas->restore();
    154                 canvas->translate(0, bounds.height() + SK_Scalar1 * kPadY);
    155                 canvas->save();
    156                 rowCount = 0;
    157             }
    158         }
    159         canvas->restore();
    160 
    161 #if SK_SUPPORT_GPU
    162         // render offscreen buffer
    163         if (surface) {
    164             SkAutoCanvasRestore acr(inputCanvas, true);
    165             // since we prepended this matrix already, we blit using identity
    166             inputCanvas->resetMatrix();
    167             SkImage* image = surface->newImageSnapshot();
    168             inputCanvas->drawImage(image, 0, 0, nullptr);
    169             image->unref();
    170         }
    171 #endif
    172     }
    173 
    174 private:
    175     SkAutoTUnref<const SkTextBlob> fBlob;
    176 
    177     static const int kWidth = 2000;
    178     static const int kHeight = 2000;
    179 
    180     bool fUseDFT;
    181 
    182     typedef GM INHERITED;
    183 };
    184 
    185 //////////////////////////////////////////////////////////////////////////////
    186 
    187 DEF_GM( return new TextBlobMixedSizes(false); )
    188 #if SK_SUPPORT_GPU
    189 DEF_GM( return new TextBlobMixedSizes(true); )
    190 #endif
    191 }
    192