skia2/gm/variedtext.cpp
Ben Wagner 12857d405c Fix gms placing text in bounds.
In the operation of taking the bounds of (horizontal text) and then
drawing the text within those bounds it is necessary to draw the text at
the origin of the bounds and not at the left edge of the bounds.

Change-Id: I712e1713ca5e0be929b11f526f224141a5310cc2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/319776
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2020-09-28 16:35:13 +00:00

171 lines
5.8 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/gm.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/utils/SkRandom.h"
#include "tools/ToolUtils.h"
/**
* Draws text with random parameters. The text draws each get their own clip rect. It is also
* used as a bench to measure how well the GPU backend combines draw ops for text draws.
*/
class VariedTextGM : public skiagm::GM {
public:
VariedTextGM(bool effectiveClip, bool lcd)
: fEffectiveClip(effectiveClip)
, fLCD(lcd) {
}
protected:
SkString onShortName() override {
SkString name("varied_text");
if (fEffectiveClip) {
name.append("_clipped");
} else {
name.append("_ignorable_clip");
}
if (fLCD) {
name.append("_lcd");
} else {
name.append("_no_lcd");
}
return name;
}
SkISize onISize() override {
return SkISize::Make(640, 480);
}
void onOnceBeforeDraw() override {
fPaint.setAntiAlias(true);
fFont.setEdging(fLCD ? SkFont::Edging::kSubpixelAntiAlias : SkFont::Edging::kAntiAlias);
SkISize size = this->getISize();
SkScalar w = SkIntToScalar(size.fWidth);
SkScalar h = SkIntToScalar(size.fHeight);
static_assert(4 == SK_ARRAY_COUNT(fTypefaces), "typeface_cnt");
fTypefaces[0] = ToolUtils::create_portable_typeface("sans-serif", SkFontStyle());
fTypefaces[1] = ToolUtils::create_portable_typeface("sans-serif", SkFontStyle::Bold());
fTypefaces[2] = ToolUtils::create_portable_typeface("serif", SkFontStyle());
fTypefaces[3] = ToolUtils::create_portable_typeface("serif", SkFontStyle::Bold());
SkRandom random;
for (int i = 0; i < kCnt; ++i) {
int length = random.nextRangeU(kMinLength, kMaxLength);
char text[kMaxLength];
for (int j = 0; j < length; ++j) {
text[j] = (char)random.nextRangeU('!', 'z');
}
fStrings[i].set(text, length);
fColors[i] = random.nextU();
fColors[i] |= 0xFF000000;
fColors[i] = ToolUtils::color_to_565(fColors[i]);
constexpr SkScalar kMinPtSize = 8.f;
constexpr SkScalar kMaxPtSize = 32.f;
fPtSizes[i] = random.nextRangeScalar(kMinPtSize, kMaxPtSize);
fTypefaceIndices[i] = random.nextULessThan(SK_ARRAY_COUNT(fTypefaces));
SkRect r;
fPaint.setColor(fColors[i]);
fFont.setTypeface(fTypefaces[fTypefaceIndices[i]]);
fFont.setSize(fPtSizes[i]);
fFont.measureText(fStrings[i].c_str(), fStrings[i].size(), SkTextEncoding::kUTF8, &r);
// The set of x,y offsets which place the bounding box inside the GM's border.
SkRect safeRect = SkRect::MakeLTRB(-r.fLeft, -r.fTop, w - r.fRight, h - r.fBottom);
if (safeRect.isEmpty()) {
// If the bounds don't fit then allow any offset in the GM's border.
safeRect = SkRect::MakeWH(w, h);
}
fOffsets[i].fX = random.nextRangeScalar(safeRect.fLeft, safeRect.fRight);
fOffsets[i].fY = random.nextRangeScalar(safeRect.fTop, safeRect.fBottom);
fClipRects[i] = r;
fClipRects[i].offset(fOffsets[i].fX, fOffsets[i].fY);
fClipRects[i].outset(2.f, 2.f);
if (fEffectiveClip) {
fClipRects[i].fRight -= 0.25f * fClipRects[i].width();
}
}
}
void onDraw(SkCanvas* canvas) override {
for (int i = 0; i < kCnt; ++i) {
fPaint.setColor(fColors[i]);
fFont.setSize(fPtSizes[i]);
fFont.setTypeface(fTypefaces[fTypefaceIndices[i]]);
canvas->save();
canvas->clipRect(fClipRects[i]);
canvas->translate(fOffsets[i].fX, fOffsets[i].fY);
canvas->drawSimpleText(fStrings[i].c_str(), fStrings[i].size(), SkTextEncoding::kUTF8,
0, 0, fFont, fPaint);
canvas->restore();
}
// Visualize the clips, but not in bench mode.
if (kBench_Mode != this->getMode()) {
SkPaint wirePaint;
wirePaint.setAntiAlias(true);
wirePaint.setStrokeWidth(0);
wirePaint.setStyle(SkPaint::kStroke_Style);
for (int i = 0; i < kCnt; ++i) {
canvas->drawRect(fClipRects[i], wirePaint);
}
}
}
bool runAsBench() const override { return true; }
private:
static constexpr int kCnt = 30;
static constexpr int kMinLength = 15;
static constexpr int kMaxLength = 40;
bool fEffectiveClip;
bool fLCD;
sk_sp<SkTypeface> fTypefaces[4];
SkPaint fPaint;
SkFont fFont;
// precomputed for each text draw
SkString fStrings[kCnt];
SkColor fColors[kCnt];
SkScalar fPtSizes[kCnt];
int fTypefaceIndices[kCnt];
SkPoint fOffsets[kCnt];
SkRect fClipRects[kCnt];
using INHERITED = skiagm::GM;
};
DEF_GM(return new VariedTextGM(false, false);)
DEF_GM(return new VariedTextGM(true, false);)
DEF_GM(return new VariedTextGM(false, true);)
DEF_GM(return new VariedTextGM(true, true);)