1 /* 2 * Copyright 2011 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 "Benchmark.h" 9 #include "Resources.h" 10 #include "SkCanvas.h" 11 #include "SkPaint.h" 12 #include "SkRandom.h" 13 #include "SkStream.h" 14 #include "SkString.h" 15 #include "SkTemplates.h" 16 #include "SkTypeface.h" 17 18 enum FontQuality { 19 kBW, 20 kAA, 21 kLCD, 22 }; 23 24 static const char* fontQualityName(const SkPaint& paint) { 25 if (!paint.isAntiAlias()) { 26 return "BW"; 27 } 28 if (paint.isLCDRenderText()) { 29 return "LCD"; 30 } 31 return "AA"; 32 } 33 34 /* Some considerations for performance: 35 short -vs- long strings (measuring overhead) 36 tiny -vs- large pointsize (measure blit -vs- overhead) 37 1 -vs- many point sizes (measure cache lookup) 38 normal -vs- subpixel -vs- lineartext (minor) 39 force purge after each draw to measure scaler 40 textencoding? 41 text -vs- postext - pathtext 42 */ 43 class TextBench : public Benchmark { 44 SkPaint fPaint; 45 SkString fText; 46 SkString fName; 47 FontQuality fFQ; 48 bool fDoPos; 49 bool fDoColorEmoji; 50 sk_sp<SkTypeface> fColorEmojiTypeface; 51 SkPoint* fPos; 52 public: 53 TextBench(const char text[], int ps, 54 SkColor color, FontQuality fq, bool doColorEmoji = false, bool doPos = false) 55 : fText(text) 56 , fFQ(fq) 57 , fDoPos(doPos) 58 , fDoColorEmoji(doColorEmoji) 59 , fPos(nullptr) { 60 fPaint.setAntiAlias(kBW != fq); 61 fPaint.setLCDRenderText(kLCD == fq); 62 fPaint.setTextSize(SkIntToScalar(ps)); 63 fPaint.setColor(color); 64 } 65 66 ~TextBench() override { 67 delete[] fPos; 68 } 69 70 protected: 71 void onDelayedSetup() override { 72 if (fDoColorEmoji) { 73 SkASSERT(kBW == fFQ); 74 fColorEmojiTypeface = MakeResourceAsTypeface("fonts/Funkster.ttf"); 75 } 76 77 if (fDoPos) { 78 size_t len = fText.size(); 79 SkScalar* adv = new SkScalar[len]; 80 fPaint.getTextWidths(fText.c_str(), len, adv); 81 fPos = new SkPoint[len]; 82 SkScalar x = 0; 83 for (size_t i = 0; i < len; ++i) { 84 fPos[i].set(x, SkIntToScalar(50)); 85 x += adv[i]; 86 } 87 delete[] adv; 88 } 89 } 90 91 92 const char* onGetName() override { 93 fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize())); 94 if (fDoPos) { 95 fName.append("_pos"); 96 } 97 fName.appendf("_%s", fontQualityName(fPaint)); 98 if (SK_ColorBLACK == fPaint.getColor()) { 99 fName.append("_BK"); 100 } else if (SK_ColorWHITE == fPaint.getColor()) { 101 fName.append("_WT"); 102 } else { 103 fName.appendf("_%02X", fPaint.getAlpha()); 104 } 105 106 if (fDoColorEmoji) { 107 fName.append("_ColorEmoji"); 108 } 109 110 return fName.c_str(); 111 } 112 113 void onDraw(int loops, SkCanvas* canvas) override { 114 const SkIPoint dim = this->getSize(); 115 SkRandom rand; 116 117 SkPaint paint(fPaint); 118 this->setupPaint(&paint); 119 // explicitly need these 120 paint.setColor(fPaint.getColor()); 121 paint.setAntiAlias(kBW != fFQ); 122 paint.setLCDRenderText(kLCD == fFQ); 123 124 if (fDoColorEmoji && fColorEmojiTypeface) { 125 paint.setTypeface(fColorEmojiTypeface); 126 } 127 128 const SkScalar x0 = SkIntToScalar(-10); 129 const SkScalar y0 = SkIntToScalar(-10); 130 131 if (fDoPos) { 132 // realistically, the matrix is often at least translated, so we 133 // do that since it exercises different code in drawPosText. 134 canvas->translate(SK_Scalar1, SK_Scalar1); 135 } 136 137 for (int i = 0; i < loops; i++) { 138 if (fDoPos) { 139 canvas->drawPosText(fText.c_str(), fText.size(), fPos, paint); 140 } else { 141 SkScalar x = x0 + rand.nextUScalar1() * dim.fX; 142 SkScalar y = y0 + rand.nextUScalar1() * dim.fY; 143 canvas->drawString(fText, x, y, paint); 144 } 145 } 146 } 147 148 private: 149 typedef Benchmark INHERITED; 150 }; 151 152 /////////////////////////////////////////////////////////////////////////////// 153 154 #define STR "Hamburgefons" 155 156 DEF_BENCH( return new TextBench(STR, 16, 0xFFFFFFFF, kBW); ) 157 DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kBW); ) 158 DEF_BENCH( return new TextBench(STR, 16, 0xFFFF0000, kBW); ) 159 DEF_BENCH( return new TextBench(STR, 16, 0x88FF0000, kBW); ) 160 161 DEF_BENCH( return new TextBench(STR, 16, 0xFFFFFFFF, kAA); ) 162 DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kAA); ) 163 DEF_BENCH( return new TextBench(STR, 16, 0xFFFF0000, kAA); ) 164 DEF_BENCH( return new TextBench(STR, 16, 0x88FF0000, kAA); ) 165 166 DEF_BENCH( return new TextBench(STR, 16, 0xFFFFFFFF, kLCD); ) 167 DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kLCD); ) 168 DEF_BENCH( return new TextBench(STR, 16, 0xFFFF0000, kLCD); ) 169 DEF_BENCH( return new TextBench(STR, 16, 0x88FF0000, kLCD); ) 170 171 DEF_BENCH( return new TextBench(STR, 16, 0xFFFFFFFF, kBW, true); ) 172 DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kBW, true); ) 173 DEF_BENCH( return new TextBench(STR, 16, 0xFFFF0000, kBW, true); ) 174 DEF_BENCH( return new TextBench(STR, 16, 0x88FF0000, kBW, true); ) 175 176 DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kBW, true, true); ) 177 DEF_BENCH( return new TextBench(STR, 16, 0xFF000000, kAA, false, true); ) 178