2014-08-21 15:53:26 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2014 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gm.h"
|
|
|
|
|
|
|
|
#include "SkCanvas.h"
|
|
|
|
#include "SkPoint.h"
|
|
|
|
#include "SkTextBlob.h"
|
|
|
|
#include "SkTDArray.h"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
enum Pos {
|
|
|
|
kDefault_Pos = 0,
|
|
|
|
kScalar_Pos = 1,
|
|
|
|
kPoint_Pos = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct BlobCfg {
|
|
|
|
unsigned count;
|
|
|
|
Pos pos;
|
|
|
|
SkScalar scale;
|
|
|
|
} blobConfigs[][3][3] = {
|
|
|
|
{
|
|
|
|
{ { 1024, kDefault_Pos, 1 }, { 0, kDefault_Pos, 0 }, { 0, kDefault_Pos, 0 } },
|
|
|
|
{ { 1024, kScalar_Pos, 1 }, { 0, kScalar_Pos, 0 }, { 0, kScalar_Pos, 0 } },
|
|
|
|
{ { 1024, kPoint_Pos, 1 }, { 0, kPoint_Pos, 0 }, { 0, kPoint_Pos, 0 } },
|
|
|
|
},
|
|
|
|
{
|
2014-08-22 16:01:19 +00:00
|
|
|
{ { 4, kDefault_Pos, 1 }, { 4, kDefault_Pos, 1 }, { 4, kDefault_Pos, 1 } },
|
|
|
|
{ { 4, kScalar_Pos, 1 }, { 4, kScalar_Pos, 1 }, { 4, kScalar_Pos, 1 } },
|
|
|
|
{ { 4, kPoint_Pos, 1 }, { 4, kPoint_Pos, 1 }, { 4, kPoint_Pos, 1 } },
|
2014-08-21 15:53:26 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2014-08-22 16:01:19 +00:00
|
|
|
{ { 4, kDefault_Pos, 1 }, { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, 1 } },
|
|
|
|
{ { 4, kScalar_Pos, 1 }, { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, 1 } },
|
|
|
|
{ { 4, kPoint_Pos, 1 }, { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, 1 } },
|
2014-08-21 15:53:26 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
{
|
2014-08-22 16:01:19 +00:00
|
|
|
{ { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, 1 } },
|
|
|
|
{ { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, 1 } },
|
|
|
|
{ { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, 1 } },
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
{ { 4, kDefault_Pos, .75f }, { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, 1.25f } },
|
|
|
|
{ { 4, kScalar_Pos, .75f }, { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, 1.25f } },
|
|
|
|
{ { 4, kPoint_Pos, .75f }, { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, 1.25f } },
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
{ { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, .75f }, { 4, kPoint_Pos, 1.25f } },
|
|
|
|
{ { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, .75f }, { 4, kDefault_Pos, 1.25f } },
|
|
|
|
{ { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, .75f }, { 4, kScalar_Pos, 1.25f } },
|
2014-08-21 15:53:26 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const SkScalar kFontSize = 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
class TextBlobGM : public skiagm::GM {
|
|
|
|
public:
|
2014-09-17 00:58:34 +00:00
|
|
|
TextBlobGM(const char* txt)
|
2015-05-21 13:15:28 +00:00
|
|
|
: fText(txt) {
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void onOnceBeforeDraw() override {
|
2016-05-12 17:09:30 +00:00
|
|
|
fTypeface = sk_tool_utils::create_portable_typeface("serif", SkTypeface::kNormal);
|
2014-08-21 15:53:26 +00:00
|
|
|
SkPaint p;
|
2014-09-17 00:58:34 +00:00
|
|
|
p.setTypeface(fTypeface);
|
2015-05-21 13:15:28 +00:00
|
|
|
size_t txtLen = strlen(fText);
|
2015-08-27 14:41:13 +00:00
|
|
|
int glyphCount = p.textToGlyphs(fText, txtLen, nullptr);
|
2014-08-21 15:53:26 +00:00
|
|
|
|
|
|
|
fGlyphs.append(glyphCount);
|
2015-05-21 13:15:28 +00:00
|
|
|
p.textToGlyphs(fText, txtLen, fGlyphs.begin());
|
2014-08-21 15:53:26 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkString onShortName() override {
|
2014-08-21 15:53:26 +00:00
|
|
|
return SkString("textblob");
|
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkISize onISize() override {
|
2014-08-21 15:53:26 +00:00
|
|
|
return SkISize::Make(640, 480);
|
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2014-08-21 15:53:26 +00:00
|
|
|
for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) {
|
2014-08-22 16:01:19 +00:00
|
|
|
SkAutoTUnref<const SkTextBlob> blob(this->makeBlob(b));
|
2014-08-21 15:53:26 +00:00
|
|
|
|
|
|
|
SkPaint p;
|
|
|
|
SkPoint offset = SkPoint::Make(SkIntToScalar(10 + 300 * (b % 2)),
|
|
|
|
SkIntToScalar(20 + 150 * (b / 2)));
|
|
|
|
|
|
|
|
canvas->drawTextBlob(blob, offset.x(), offset.y(), p);
|
|
|
|
|
|
|
|
p.setColor(SK_ColorBLUE);
|
|
|
|
p.setStyle(SkPaint::kStroke_Style);
|
|
|
|
SkRect box = blob->bounds();
|
|
|
|
box.offset(offset);
|
|
|
|
canvas->drawRect(box, p);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const SkTextBlob* makeBlob(unsigned blobIndex) {
|
|
|
|
SkTextBlobBuilder builder;
|
|
|
|
|
|
|
|
SkPaint font;
|
|
|
|
font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
2014-08-22 16:01:19 +00:00
|
|
|
font.setAntiAlias(true);
|
|
|
|
font.setSubpixelText(true);
|
2014-09-17 00:58:34 +00:00
|
|
|
font.setTypeface(fTypeface);
|
2014-08-21 15:53:26 +00:00
|
|
|
|
|
|
|
for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) {
|
|
|
|
unsigned currentGlyph = 0;
|
|
|
|
|
|
|
|
for (unsigned c = 0; c < SK_ARRAY_COUNT(blobConfigs[blobIndex][l]); ++c) {
|
|
|
|
const BlobCfg* cfg = &blobConfigs[blobIndex][l][c];
|
|
|
|
unsigned count = cfg->count;
|
|
|
|
|
|
|
|
if (count > fGlyphs.count() - currentGlyph) {
|
|
|
|
count = fGlyphs.count() - currentGlyph;
|
|
|
|
}
|
|
|
|
if (0 == count) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
font.setTextSize(kFontSize * cfg->scale);
|
|
|
|
const SkScalar advanceX = font.getTextSize() * 0.85f;
|
|
|
|
const SkScalar advanceY = font.getTextSize() * 1.5f;
|
|
|
|
|
|
|
|
SkPoint offset = SkPoint::Make(currentGlyph * advanceX + c * advanceX,
|
|
|
|
advanceY * l);
|
|
|
|
switch (cfg->pos) {
|
|
|
|
case kDefault_Pos: {
|
|
|
|
const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, count,
|
|
|
|
offset.x(),
|
|
|
|
offset.y());
|
|
|
|
memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
|
|
|
|
} break;
|
|
|
|
case kScalar_Pos: {
|
|
|
|
const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPosH(font, count,
|
|
|
|
offset.y());
|
|
|
|
SkTDArray<SkScalar> pos;
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
*pos.append() = offset.x() + i * advanceX;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
|
|
|
|
memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar));
|
|
|
|
} break;
|
|
|
|
case kPoint_Pos: {
|
|
|
|
const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPos(font, count);
|
|
|
|
|
|
|
|
SkTDArray<SkScalar> pos;
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
*pos.append() = offset.x() + i * advanceX;
|
|
|
|
*pos.append() = offset.y() + i * (advanceY / count);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
|
|
|
|
memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar) * 2);
|
|
|
|
} break;
|
|
|
|
default:
|
2016-01-29 16:51:04 +00:00
|
|
|
SK_ABORT("unhandled pos value");
|
2014-08-21 15:53:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
currentGlyph += count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
|
2016-05-12 17:09:30 +00:00
|
|
|
SkTDArray<uint16_t> fGlyphs;
|
|
|
|
sk_sp<SkTypeface> fTypeface;
|
|
|
|
const char* fText;
|
2014-08-21 15:53:26 +00:00
|
|
|
typedef skiagm::GM INHERITED;
|
|
|
|
};
|
|
|
|
|
2015-08-26 20:07:48 +00:00
|
|
|
DEF_GM(return new TextBlobGM("hamburgefons");)
|