5f50f5776d
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>
203 lines
6.9 KiB
C++
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");)
|