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 "sk_tool_utils.h"
     10 
     11 #include "SkCanvas.h"
     12 #include "SkPoint.h"
     13 #include "SkTextBlob.h"
     14 #include "SkTDArray.h"
     15 
     16 namespace  {
     17 
     18 enum Pos {
     19     kDefault_Pos = 0,
     20     kScalar_Pos  = 1,
     21     kPoint_Pos   = 2,
     22 };
     23 
     24 const struct BlobCfg {
     25     unsigned count;
     26     Pos      pos;
     27     SkScalar scale;
     28 } blobConfigs[][3][3] = {
     29     {
     30         { { 1024, kDefault_Pos, 1 }, { 0, kDefault_Pos, 0 }, { 0, kDefault_Pos, 0 } },
     31         { { 1024,  kScalar_Pos, 1 }, { 0,  kScalar_Pos, 0 }, { 0,  kScalar_Pos, 0 } },
     32         { { 1024,   kPoint_Pos, 1 }, { 0,   kPoint_Pos, 0 }, { 0,   kPoint_Pos, 0 } },
     33     },
     34     {
     35         { { 4, kDefault_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4, kDefault_Pos, 1 } },
     36         { { 4,  kScalar_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
     37         { { 4,   kPoint_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
     38     },
     39 
     40     {
     41         { { 4, kDefault_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
     42         { { 4,  kScalar_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
     43         { { 4,   kPoint_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1 } },
     44     },
     45 
     46     {
     47         { { 4, kDefault_Pos, 1 },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1 } },
     48         { { 4,  kScalar_Pos, 1 },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1 } },
     49         { { 4,   kPoint_Pos, 1 },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1 } },
     50     },
     51 
     52     {
     53         { { 4, kDefault_Pos, .75f },     { 4, kDefault_Pos, 1 },  { 4,  kScalar_Pos, 1.25f } },
     54         { { 4,  kScalar_Pos, .75f },     { 4,  kScalar_Pos, 1 },  { 4,   kPoint_Pos, 1.25f } },
     55         { { 4,   kPoint_Pos, .75f },     { 4,   kPoint_Pos, 1 },  { 4, kDefault_Pos, 1.25f } },
     56     },
     57 
     58     {
     59         { { 4, kDefault_Pos, 1 },     { 4,  kScalar_Pos, .75f },  { 4,   kPoint_Pos, 1.25f } },
     60         { { 4,  kScalar_Pos, 1 },     { 4,   kPoint_Pos, .75f },  { 4, kDefault_Pos, 1.25f } },
     61         { { 4,   kPoint_Pos, 1 },     { 4, kDefault_Pos, .75f },  { 4,  kScalar_Pos, 1.25f } },
     62     },
     63 };
     64 
     65 const SkScalar kFontSize = 16;
     66 }
     67 
     68 class TextBlobGM : public skiagm::GM {
     69 public:
     70     TextBlobGM(const char* txt)
     71         : fText(txt) {
     72     }
     73 
     74 protected:
     75     void onOnceBeforeDraw() override {
     76         fTypeface = sk_tool_utils::create_portable_typeface("serif", SkFontStyle());
     77         SkPaint p;
     78         p.setTypeface(fTypeface);
     79         size_t txtLen = strlen(fText);
     80         int glyphCount = p.textToGlyphs(fText, txtLen, nullptr);
     81 
     82         fGlyphs.append(glyphCount);
     83         p.textToGlyphs(fText, txtLen, fGlyphs.begin());
     84     }
     85 
     86     SkString onShortName() override {
     87         return SkString("textblob");
     88     }
     89 
     90     SkISize onISize() override {
     91         return SkISize::Make(640, 480);
     92     }
     93 
     94     void onDraw(SkCanvas* canvas) override {
     95         for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) {
     96             sk_sp<SkTextBlob> blob(this->makeBlob(b));
     97 
     98             SkPaint p;
     99             SkPoint offset = SkPoint::Make(SkIntToScalar(10 + 300 * (b % 2)),
    100                                            SkIntToScalar(20 + 150 * (b / 2)));
    101 
    102             canvas->drawTextBlob(blob, offset.x(), offset.y(), p);
    103 
    104             p.setColor(SK_ColorBLUE);
    105             p.setStyle(SkPaint::kStroke_Style);
    106             SkRect box = blob->bounds();
    107             box.offset(offset);
    108             canvas->drawRect(box, p);
    109 
    110         }
    111     }
    112 
    113 private:
    114     sk_sp<SkTextBlob> makeBlob(unsigned blobIndex) {
    115         SkTextBlobBuilder builder;
    116 
    117         SkPaint font;
    118         font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    119         font.setAntiAlias(true);
    120         font.setSubpixelText(true);
    121         font.setTypeface(fTypeface);
    122 
    123         for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) {
    124             unsigned currentGlyph = 0;
    125 
    126             for (unsigned c = 0; c < SK_ARRAY_COUNT(blobConfigs[blobIndex][l]); ++c) {
    127                 const BlobCfg* cfg = &blobConfigs[blobIndex][l][c];
    128                 unsigned count = cfg->count;
    129 
    130                 if (count > fGlyphs.count() - currentGlyph) {
    131                     count = fGlyphs.count() - currentGlyph;
    132                 }
    133                 if (0 == count) {
    134                     break;
    135                 }
    136 
    137                 font.setTextSize(kFontSize * cfg->scale);
    138                 const SkScalar advanceX = font.getTextSize() * 0.85f;
    139                 const SkScalar advanceY = font.getTextSize() * 1.5f;
    140 
    141                 SkPoint offset = SkPoint::Make(currentGlyph * advanceX + c * advanceX,
    142                                                advanceY * l);
    143                 switch (cfg->pos) {
    144                 case kDefault_Pos: {
    145                     const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, count,
    146                                                                                offset.x(),
    147                                                                                offset.y());
    148                     memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
    149                 } break;
    150                 case kScalar_Pos: {
    151                     const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPosH(font, count,
    152                                                                                    offset.y());
    153                     SkTDArray<SkScalar> pos;
    154                     for (unsigned i = 0; i < count; ++i) {
    155                         *pos.append() = offset.x() + i * advanceX;
    156                     }
    157 
    158                     memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
    159                     memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar));
    160                 } break;
    161                 case kPoint_Pos: {
    162                     const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPos(font, count);
    163 
    164                     SkTDArray<SkScalar> pos;
    165                     for (unsigned i = 0; i < count; ++i) {
    166                         *pos.append() = offset.x() + i * advanceX;
    167                         *pos.append() = offset.y() + i * (advanceY / count);
    168                     }
    169 
    170                     memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
    171                     memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar) * 2);
    172                 } break;
    173                 default:
    174                     SK_ABORT("unhandled pos value");
    175                 }
    176 
    177                 currentGlyph += count;
    178             }
    179         }
    180 
    181         return builder.make();
    182     }
    183 
    184     SkTDArray<uint16_t> fGlyphs;
    185     sk_sp<SkTypeface>   fTypeface;
    186     const char*         fText;
    187     typedef skiagm::GM INHERITED;
    188 };
    189 
    190 DEF_GM(return new TextBlobGM("hamburgefons");)
    191