Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2014 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 #include "SkCanvas.h"
     10 #include "SkPath.h"
     11 #include "SkTypeface.h"
     12 #include "SkRandom.h"
     13 
     14 /**
     15  * Draws text with random parameters. The text draws each get their own clip rect. It is also
     16  * used as a bench to measure how well the GPU backend batches text draws.
     17  */
     18 
     19 class VariedTextGM : public skiagm::GM {
     20 public:
     21     VariedTextGM(bool effectiveClip, bool lcd)
     22         : fEffectiveClip(effectiveClip)
     23         , fLCD(lcd) {
     24         memset(fTypefacesToUnref, 0, sizeof(fTypefacesToUnref));
     25     }
     26 
     27     ~VariedTextGM() {
     28         for (size_t i = 0; i < SK_ARRAY_COUNT(fTypefacesToUnref); ++i) {
     29             SkSafeUnref(fTypefacesToUnref[i]);
     30         }
     31     }
     32 
     33 protected:
     34     virtual SkString onShortName() SK_OVERRIDE {
     35         SkString name("varied_text");
     36         if (fEffectiveClip) {
     37             name.append("_clipped");
     38         } else {
     39             name.append("_ignorable_clip");
     40         }
     41         if (fLCD) {
     42             name.append("_lcd");
     43         } else {
     44             name.append("_no_lcd");
     45         }
     46         return name;
     47     }
     48 
     49     virtual SkISize onISize() SK_OVERRIDE {
     50         return SkISize::Make(640, 480);
     51     }
     52 
     53     virtual void onOnceBeforeDraw() SK_OVERRIDE {
     54         fPaint.setAntiAlias(true);
     55         fPaint.setLCDRenderText(fLCD);
     56 
     57         SkISize size = this->getISize();
     58         SkScalar w = SkIntToScalar(size.fWidth);
     59         SkScalar h = SkIntToScalar(size.fHeight);
     60 
     61         SK_COMPILE_ASSERT(4 == SK_ARRAY_COUNT(fTypefacesToUnref), typeface_cnt);
     62         fTypefacesToUnref[0] = sk_tool_utils::create_portable_typeface("sans-serif", SkTypeface::kNormal);
     63         fTypefacesToUnref[1] = sk_tool_utils::create_portable_typeface("sans-serif", SkTypeface::kBold);
     64         fTypefacesToUnref[2] = sk_tool_utils::create_portable_typeface("serif", SkTypeface::kNormal);
     65         fTypefacesToUnref[3] = sk_tool_utils::create_portable_typeface("serif", SkTypeface::kBold);
     66 
     67         SkRandom random;
     68         for (int i = 0; i < kCnt; ++i) {
     69             int length = random.nextRangeU(kMinLength, kMaxLength);
     70             char text[kMaxLength];
     71             for (int j = 0; j < length; ++j) {
     72                 text[j] = (char)random.nextRangeU('!', 'z');
     73             }
     74             fStrings[i].set(text, length);
     75 
     76             fColors[i] = random.nextU();
     77             fColors[i] |= 0xFF000000;
     78 
     79             static const SkScalar kMinPtSize = 8.f;
     80             static const SkScalar kMaxPtSize = 32.f;
     81 
     82             fPtSizes[i] = random.nextRangeScalar(kMinPtSize, kMaxPtSize);
     83 
     84             fTypefaces[i] = fTypefacesToUnref[
     85                 random.nextULessThan(SK_ARRAY_COUNT(fTypefacesToUnref))];
     86 
     87             SkRect r;
     88             fPaint.setColor(fColors[i]);
     89             fPaint.setTypeface(fTypefaces[i]);
     90             fPaint.setTextSize(fPtSizes[i]);
     91 
     92             fPaint.measureText(fStrings[i].c_str(), fStrings[i].size(), &r);
     93             // safeRect is set of x,y positions where we can draw the string without hitting
     94             // the GM's border.
     95             SkRect safeRect = SkRect::MakeLTRB(-r.fLeft, -r.fTop, w - r.fRight, h - r.fBottom);
     96             if (safeRect.isEmpty()) {
     97                 // If we don't fit then just don't worry about how we get cliped to the device
     98                 // border.
     99                 safeRect = SkRect::MakeWH(w, h);
    100             }
    101             fPositions[i].fX = random.nextRangeScalar(safeRect.fLeft, safeRect.fRight);
    102             fPositions[i].fY = random.nextRangeScalar(safeRect.fTop, safeRect.fBottom);
    103 
    104             fClipRects[i] = r;
    105             fClipRects[i].offset(fPositions[i].fX, fPositions[i].fY);
    106             fClipRects[i].outset(2.f, 2.f);
    107 
    108             if (fEffectiveClip) {
    109                 fClipRects[i].fRight -= 0.25f * fClipRects[i].width();
    110             }
    111         }
    112     }
    113 
    114     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
    115         for (int i = 0; i < kCnt; ++i) {
    116             fPaint.setColor(fColors[i]);
    117             fPaint.setTextSize(fPtSizes[i]);
    118             fPaint.setTypeface(fTypefaces[i]);
    119 
    120             canvas->save();
    121                 canvas->clipRect(fClipRects[i]);
    122                 canvas->translate(fPositions[i].fX, fPositions[i].fY);
    123                 canvas->drawText(fStrings[i].c_str(), fStrings[i].size(), 0, 0, fPaint);
    124             canvas->restore();
    125         }
    126 
    127         // Visualize the clips, but not in bench mode.
    128         if (kBench_Mode != this->getMode()) {
    129             SkPaint wirePaint;
    130             wirePaint.setAntiAlias(true);
    131             wirePaint.setStrokeWidth(0);
    132             wirePaint.setStyle(SkPaint::kStroke_Style);
    133             for (int i = 0; i < kCnt; ++i) {
    134                 canvas->drawRect(fClipRects[i], wirePaint);
    135             }
    136         }
    137     }
    138 
    139     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    140         // The aa hairline stroked rects used to visualize the clip draw slightly differently in
    141         // quilt mode in dm.
    142         return kAsBench_Flag | kSkipTiled_Flag;
    143     }
    144 
    145 private:
    146     static const int kCnt = 30;
    147     static const int kMinLength = 15;
    148     static const int kMaxLength = 40;
    149 
    150     bool        fEffectiveClip;
    151     bool        fLCD;
    152     SkTypeface* fTypefacesToUnref[4];
    153     SkPaint     fPaint;
    154 
    155     // precomputed for each text draw
    156     SkString        fStrings[kCnt];
    157     SkColor         fColors[kCnt];
    158     SkScalar        fPtSizes[kCnt];
    159     SkTypeface*     fTypefaces[kCnt];
    160     SkPoint         fPositions[kCnt];
    161     SkRect          fClipRects[kCnt];
    162 
    163     typedef skiagm::GM INHERITED;
    164 };
    165 
    166 DEF_GM( return SkNEW(VariedTextGM(false, false)); )
    167 DEF_GM( return SkNEW(VariedTextGM(true, false)); )
    168 DEF_GM( return SkNEW(VariedTextGM(false, true)); )
    169 DEF_GM( return SkNEW(VariedTextGM(true, true)); )
    170