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