skia2/gm/textblob.cpp
Mike Reed 5f50f5776d New plan -- aa and lcd DO belong on SkFont
edging settings are needed for metrics calls, as well as drawing, hence
we really have to include them in almost every SkFont call/usage, so I
guess we can just accept them as real.

This seems to imply that we have to document what happens in drawTextBlob,
since it has a bunch of SkFonts (runs) AND a paint. This is the situation
today of course, and I had hoped to simplify it, but I think I've failed.

Proposal dox for drawTextBlob.

drawTextBlob respects the paint when drawing the blog, but it IGNORES the
paint's antialias (and lcdrender) flags, as these are already specified in
the blob's runs.

Bug: skia:2664, skia:8494
Change-Id: I8f69186c9c337d98d058919f53b7901ff830a16e
Reviewed-on: https://skia-review.googlesource.com/c/170352
Auto-Submit: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Mike Reed <reed@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2018-11-12 19:30:16 +00:00

203 lines
6.9 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 "SkCanvas.h"
#include "SkColor.h"
#include "SkFontStyle.h"
#include "SkPaint.h"
#include "SkPoint.h"
#include "SkRect.h"
#include "SkRefCnt.h"
#include "SkScalar.h"
#include "SkSize.h"
#include "SkString.h"
#include "SkTDArray.h"
#include "SkTextBlob.h"
#include "SkTypeface.h"
#include "SkTypes.h"
#include "gm.h"
#include "sk_tool_utils.h"
#include <cstring>
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)
: fText(txt) {
}
protected:
void onOnceBeforeDraw() override {
fTypeface = sk_tool_utils::create_portable_typeface("serif", SkFontStyle());
SkPaint p;
p.setTypeface(fTypeface);
size_t txtLen = strlen(fText);
int glyphCount = p.textToGlyphs(fText, txtLen, nullptr);
fGlyphs.append(glyphCount);
p.textToGlyphs(fText, txtLen, fGlyphs.begin());
}
SkString onShortName() override {
return SkString("textblob");
}
SkISize onISize() override {
return SkISize::Make(640, 480);
}
void onDraw(SkCanvas* canvas) override {
for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) {
sk_sp<SkTextBlob> blob(this->makeBlob(b));
SkPaint p;
p.setAntiAlias(true);
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);
p.setAntiAlias(false);
canvas->drawRect(box, p);
}
}
private:
sk_sp<SkTextBlob> makeBlob(unsigned blobIndex) {
SkTextBlobBuilder builder;
SkFont font;
font.setSubpixel(true);
font.setEdging(SkFont::Edging::kAntiAlias);
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.setSize(kFontSize * cfg->scale);
const SkScalar advanceX = font.getSize() * 0.85f;
const SkScalar advanceY = font.getSize() * 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:
SK_ABORT("unhandled pos value");
}
currentGlyph += count;
}
}
return builder.make();
}
SkTDArray<uint16_t> fGlyphs;
sk_sp<SkTypeface> fTypeface;
const char* fText;
typedef skiagm::GM INHERITED;
};
DEF_GM(return new TextBlobGM("hamburgefons");)