skia2/gm/textblob.cpp
fmalita acb882c239 Ensure blob typeface information survives SkGPipe serialization.
When flattening text blobs to the temp buffer, we need to collect
typeface info and ship it across the pipe explicitly.

R=mtklein@google.com, reed@google.com, robertphillips@google.com, bungeman@google.com
BUG=412445

Author: fmalita@chromium.org

Review URL: https://codereview.chromium.org/563783003
2014-09-16 17:58:34 -07:00

186 lines
6.6 KiB
C++

/*
* 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 } },
},
{
{ { 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 } },
},
{
{ { 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 } },
},
{
{ { 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 } },
},
};
const SkScalar kFontSize = 16;
}
class TextBlobGM : public skiagm::GM {
public:
TextBlobGM(const char* txt)
: fTypeface(sk_tool_utils::create_portable_typeface("Times", SkTypeface::kNormal)) {
SkPaint p;
p.setTypeface(fTypeface);
size_t txtLen = strlen(txt);
int glyphCount = p.textToGlyphs(txt, txtLen, NULL);
fGlyphs.append(glyphCount);
p.textToGlyphs(txt, txtLen, fGlyphs.begin());
}
protected:
virtual SkString onShortName() SK_OVERRIDE {
return SkString("textblob");
}
virtual SkISize onISize() SK_OVERRIDE {
return SkISize::Make(640, 480);
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) {
SkAutoTUnref<const SkTextBlob> blob(this->makeBlob(b));
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);
font.setAntiAlias(true);
font.setSubpixelText(true);
font.setTypeface(fTypeface);
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:
SkFAIL("unhandled pos value");
}
currentGlyph += count;
}
}
return builder.build();
}
SkTDArray<uint16_t> fGlyphs;
SkAutoTUnref<SkTypeface> fTypeface;
typedef skiagm::GM INHERITED;
};
DEF_GM( return SkNEW_ARGS(TextBlobGM, ("hamburgefons")); )