skia2/samplecode/SampleTextEffects.cpp
Michael Ludwig 4e1c1a77ad Implement computeFastBounds for PathEffects
Makes computeFastBounds not part of the public API, it's only accessible
to subclasses of SkPathEffect, GrStyle, and SkPaint. Subclasses can
invoke it other path effects using SkPathEffectPriv::ComputeFastBounds.

Changes the internal function to
  bool computeFastBounds(SkRect* bounds) const;

Subclasses of SkPathEffect must implement this, and can choose to return
false when fast bounds aren't computable.

Provides implementations of computeFastBounds() for path effects
bundled with Skia.

Bug: skia:11974
Change-Id: I545ccf99b4e669d3af9df13acfac28573306fab8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/406140
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Mike Reed <reed@google.com>
2021-05-11 17:01:59 +00:00

173 lines
4.7 KiB
C++

/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkColorPriv.h"
#include "include/core/SkPath.h"
#include "include/core/SkRegion.h"
#include "include/core/SkShader.h"
#include "include/core/SkStrokeRec.h"
#include "include/core/SkTypeface.h"
#include "include/effects/SkGradientShader.h"
#include "include/utils/SkTextUtils.h"
#include "samplecode/Sample.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "src/utils/SkUTF.h"
#include "include/effects/SkGradientShader.h"
#include "include/effects/Sk2DPathEffect.h"
class Dot2DPathEffect : public Sk2DPathEffect {
public:
Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix,
SkTDArray<SkPoint>* pts)
: Sk2DPathEffect(matrix), fRadius(radius), fPts(pts) {}
SK_FLATTENABLE_HOOKS(Dot2DPathEffect)
protected:
void begin(const SkIRect& uvBounds, SkPath* dst) const override {
if (fPts) {
fPts->reset();
}
this->INHERITED::begin(uvBounds, dst);
}
void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
if (fPts) {
*fPts->append() = loc;
}
dst->addCircle(loc.fX, loc.fY, fRadius);
}
void flatten(SkWriteBuffer& buffer) const override {
buffer.writeMatrix(this->getMatrix());
buffer.writeScalar(fRadius);
}
private:
SkScalar fRadius;
SkTDArray<SkPoint>* fPts;
using INHERITED = Sk2DPathEffect;
};
// Register this path effect as deserializable before main().
namespace {
static struct Initializer {
Initializer() {
SK_REGISTER_FLATTENABLE(Dot2DPathEffect);
}
} initializer;
} // namespace
sk_sp<SkFlattenable> Dot2DPathEffect::CreateProc(SkReadBuffer& buffer) {
SkMatrix matrix;
buffer.readMatrix(&matrix);
return sk_make_sp<Dot2DPathEffect>(buffer.readScalar(), matrix, nullptr);
}
class InverseFillPE : public SkPathEffect {
public:
InverseFillPE() {}
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override {
*dst = src;
dst->setFillType(SkPathFillType::kInverseWinding);
return true;
}
private:
SK_FLATTENABLE_HOOKS(InverseFillPE)
bool computeFastBounds(SkRect* bounds) const override { return false; }
using INHERITED = SkPathEffect;
};
sk_sp<SkFlattenable> InverseFillPE::CreateProc(SkReadBuffer& buffer) {
return sk_make_sp<InverseFillPE>();
}
static sk_sp<SkPathEffect> makepe(float interp, SkTDArray<SkPoint>* pts) {
SkMatrix lattice;
SkScalar rad = 3 + SkIntToScalar(4) * (1 - interp);
lattice.setScale(rad*2, rad*2, 0, 0);
lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
return sk_make_sp<Dot2DPathEffect>(rad, lattice, pts);
}
class TextEffectsView : public Sample {
sk_sp<SkTypeface> fFace;
SkScalar fInterp;
SkScalar fDx;
public:
TextEffectsView() {
fFace = SkTypeface::MakeFromFile("/Users/reed/Downloads/p052024l.pfb");
fInterp = 0;
fDx = SK_Scalar1/64;
}
protected:
SkString name() override { return SkString("Text Effects"); }
void drawBG(SkCanvas* canvas) {
canvas->drawColor(SK_ColorWHITE);
}
void drawdots(SkCanvas* canvas, SkString s, SkScalar x, SkScalar y, const SkFont& font) {
SkTDArray<SkPoint> pts;
auto pe = makepe(fInterp, &pts);
SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
SkPath path, dstPath;
SkTextUtils::GetPath(s.c_str(), s.size(), SkTextEncoding::kUTF8, x, y, font, &path);
pe->filterPath(&dstPath, path, &rec, nullptr);
SkPaint paint;
paint.setAntiAlias(true);
paint.setStrokeWidth(10);
paint.setColor(SK_ColorRED);
canvas->drawPoints(SkCanvas::kPoints_PointMode, pts.count(), pts.begin(), paint);
}
void onDrawContent(SkCanvas* canvas) override {
this->drawBG(canvas);
SkScalar x = SkIntToScalar(20);
SkScalar y = SkIntToScalar(300);
SkFont font(SkTypeface::MakeFromName("sans-serif", SkFontStyle::Bold()), 240);
SkString str("9");
canvas->drawString(str, x, y, font, SkPaint());
drawdots(canvas, str, x, y, font);
if (false) {
fInterp += fDx;
if (fInterp > 1) {
fInterp = 1;
fDx = -fDx;
} else if (fInterp < 0) {
fInterp = 0;
fDx = -fDx;
}
}
}
private:
using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
DEF_SAMPLE( return new TextEffectsView(); )