Just expose factories for patheffects
bug: skia:11957 Change-Id: If2983fcd1b520a7ae77650d7e5ab226af9db52e0 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/410782 Commit-Queue: Mike Reed <reed@google.com> Reviewed-by: Tyler Denniston <tdenniston@google.com>
This commit is contained in:
parent
298de8a345
commit
ec87dc1b76
@ -73,7 +73,6 @@ samples_sources = [
|
||||
"$_samplecode/SampleStrokeRect.cpp",
|
||||
"$_samplecode/SampleStrokeVerb.cpp",
|
||||
"$_samplecode/SampleTextBox.cpp",
|
||||
"$_samplecode/SampleTextEffects.cpp",
|
||||
"$_samplecode/SampleTextureUpload.cpp",
|
||||
"$_samplecode/SampleThinAA.cpp",
|
||||
"$_samplecode/SampleTiming.cpp",
|
||||
|
@ -8,37 +8,9 @@
|
||||
#ifndef Sk1DPathEffect_DEFINED
|
||||
#define Sk1DPathEffect_DEFINED
|
||||
|
||||
#include "include/core/SkFlattenable.h"
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkPathEffect.h"
|
||||
|
||||
class SkPathMeasure;
|
||||
|
||||
// This class is not exported to java.
|
||||
class SK_API Sk1DPathEffect : public SkPathEffect {
|
||||
public:
|
||||
protected:
|
||||
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
|
||||
|
||||
/** Called at the start of each contour, returns the initial offset
|
||||
into that contour.
|
||||
*/
|
||||
virtual SkScalar begin(SkScalar contourLength) const = 0;
|
||||
/** Called with the current distance along the path, with the current matrix
|
||||
for the point/tangent at the specified distance.
|
||||
Return the distance to travel for the next call. If return <= 0, then that
|
||||
contour is done.
|
||||
*/
|
||||
virtual SkScalar next(SkPath* dst, SkScalar dist, SkPathMeasure&) const = 0;
|
||||
|
||||
private:
|
||||
// For simplicity, assume fast bounds cannot be computed
|
||||
bool computeFastBounds(SkRect*) const override { return false; }
|
||||
|
||||
using INHERITED = SkPathEffect;
|
||||
};
|
||||
|
||||
class SK_API SkPath1DPathEffect : public Sk1DPathEffect {
|
||||
class SK_API SkPath1DPathEffect {
|
||||
public:
|
||||
enum Style {
|
||||
kTranslate_Style, // translate the shape to each position
|
||||
@ -57,24 +29,7 @@ public:
|
||||
*/
|
||||
static sk_sp<SkPathEffect> Make(const SkPath& path, SkScalar advance, SkScalar phase, Style);
|
||||
|
||||
protected:
|
||||
SkPath1DPathEffect(const SkPath& path, SkScalar advance, SkScalar phase, Style);
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
bool onFilterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const override;
|
||||
|
||||
// overrides from Sk1DPathEffect
|
||||
SkScalar begin(SkScalar contourLength) const override;
|
||||
SkScalar next(SkPath*, SkScalar, SkPathMeasure&) const override;
|
||||
|
||||
private:
|
||||
SK_FLATTENABLE_HOOKS(SkPath1DPathEffect)
|
||||
|
||||
SkPath fPath; // copied from constructor
|
||||
SkScalar fAdvance; // copied from constructor
|
||||
SkScalar fInitialOffset; // computed from phase
|
||||
Style fStyle; // copied from constructor
|
||||
|
||||
using INHERITED = Sk1DPathEffect;
|
||||
static void RegisterFlattenables();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -8,101 +8,23 @@
|
||||
#ifndef Sk2DPathEffect_DEFINED
|
||||
#define Sk2DPathEffect_DEFINED
|
||||
|
||||
#include "include/core/SkFlattenable.h"
|
||||
#include "include/core/SkMatrix.h"
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkPathEffect.h"
|
||||
|
||||
class SK_API Sk2DPathEffect : public SkPathEffect {
|
||||
protected:
|
||||
/** New virtual, to be overridden by subclasses.
|
||||
This is called once from filterPath, and provides the
|
||||
uv parameter bounds for the path. Subsequent calls to
|
||||
next() will receive u and v values within these bounds,
|
||||
and then a call to end() will signal the end of processing.
|
||||
*/
|
||||
virtual void begin(const SkIRect& uvBounds, SkPath* dst) const;
|
||||
virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const;
|
||||
virtual void end(SkPath* dst) const;
|
||||
class SkMatrix;
|
||||
class SkPath;
|
||||
|
||||
/** Low-level virtual called per span of locations in the u-direction.
|
||||
The default implementation calls next() repeatedly with each
|
||||
location.
|
||||
*/
|
||||
virtual void nextSpan(int u, int v, int ucount, SkPath* dst) const;
|
||||
class SK_API SkLine2DPathEffect {
|
||||
public:
|
||||
static sk_sp<SkPathEffect> Make(SkScalar width, const SkMatrix& matrix);
|
||||
|
||||
const SkMatrix& getMatrix() const { return fMatrix; }
|
||||
|
||||
// protected so that subclasses can call this during unflattening
|
||||
explicit Sk2DPathEffect(const SkMatrix& mat);
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
bool onFilterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const override;
|
||||
|
||||
private:
|
||||
SkMatrix fMatrix, fInverse;
|
||||
bool fMatrixIsInvertible;
|
||||
|
||||
// For simplicity, assume fast bounds cannot be computed
|
||||
bool computeFastBounds(SkRect*) const override { return false; }
|
||||
|
||||
// illegal
|
||||
Sk2DPathEffect(const Sk2DPathEffect&);
|
||||
Sk2DPathEffect& operator=(const Sk2DPathEffect&);
|
||||
|
||||
friend class Sk2DPathEffectBlitter;
|
||||
using INHERITED = SkPathEffect;
|
||||
static void RegisterFlattenables();
|
||||
};
|
||||
|
||||
class SK_API SkLine2DPathEffect : public Sk2DPathEffect {
|
||||
class SK_API SkPath2DPathEffect {
|
||||
public:
|
||||
static sk_sp<SkPathEffect> Make(SkScalar width, const SkMatrix& matrix) {
|
||||
if (!(width >= 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
return sk_sp<SkPathEffect>(new SkLine2DPathEffect(width, matrix));
|
||||
}
|
||||
static sk_sp<SkPathEffect> Make(const SkMatrix& matrix, const SkPath& path);
|
||||
|
||||
|
||||
protected:
|
||||
SkLine2DPathEffect(SkScalar width, const SkMatrix& matrix)
|
||||
: Sk2DPathEffect(matrix), fWidth(width) {
|
||||
SkASSERT(width >= 0);
|
||||
}
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override;
|
||||
|
||||
void nextSpan(int u, int v, int ucount, SkPath*) const override;
|
||||
|
||||
private:
|
||||
SK_FLATTENABLE_HOOKS(SkLine2DPathEffect)
|
||||
|
||||
SkScalar fWidth;
|
||||
|
||||
using INHERITED = Sk2DPathEffect;
|
||||
};
|
||||
|
||||
class SK_API SkPath2DPathEffect : public Sk2DPathEffect {
|
||||
public:
|
||||
/**
|
||||
* Stamp the specified path to fill the shape, using the matrix to define
|
||||
* the latice.
|
||||
*/
|
||||
static sk_sp<SkPathEffect> Make(const SkMatrix& matrix, const SkPath& path) {
|
||||
return sk_sp<SkPathEffect>(new SkPath2DPathEffect(matrix, path));
|
||||
}
|
||||
|
||||
protected:
|
||||
SkPath2DPathEffect(const SkMatrix&, const SkPath&);
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
|
||||
void next(const SkPoint&, int u, int v, SkPath*) const override;
|
||||
|
||||
private:
|
||||
SK_FLATTENABLE_HOOKS(SkPath2DPathEffect)
|
||||
|
||||
SkPath fPath;
|
||||
|
||||
using INHERITED = Sk2DPathEffect;
|
||||
static void RegisterFlattenables();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,172 +0,0 @@
|
||||
/*
|
||||
* 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(); )
|
@ -16,68 +16,119 @@
|
||||
// Put in a governor to limit crash values from looping too long (and allocating too much ram).
|
||||
#define MAX_REASONABLE_ITERATIONS 100000
|
||||
|
||||
bool Sk1DPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
|
||||
SkStrokeRec*, const SkRect*) const {
|
||||
SkPathMeasure meas(src, false);
|
||||
do {
|
||||
int governor = MAX_REASONABLE_ITERATIONS;
|
||||
SkScalar length = meas.getLength();
|
||||
SkScalar distance = this->begin(length);
|
||||
while (distance < length && --governor >= 0) {
|
||||
SkScalar delta = this->next(dst, distance, meas);
|
||||
if (delta <= 0) {
|
||||
break;
|
||||
class Sk1DPathEffect : public SkPathEffect {
|
||||
public:
|
||||
protected:
|
||||
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override {
|
||||
SkPathMeasure meas(src, false);
|
||||
do {
|
||||
int governor = MAX_REASONABLE_ITERATIONS;
|
||||
SkScalar length = meas.getLength();
|
||||
SkScalar distance = this->begin(length);
|
||||
while (distance < length && --governor >= 0) {
|
||||
SkScalar delta = this->next(dst, distance, meas);
|
||||
if (delta <= 0) {
|
||||
break;
|
||||
}
|
||||
distance += delta;
|
||||
}
|
||||
distance += delta;
|
||||
}
|
||||
} while (meas.nextContour());
|
||||
return true;
|
||||
}
|
||||
} while (meas.nextContour());
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Called at the start of each contour, returns the initial offset
|
||||
into that contour.
|
||||
*/
|
||||
virtual SkScalar begin(SkScalar contourLength) const = 0;
|
||||
/** Called with the current distance along the path, with the current matrix
|
||||
for the point/tangent at the specified distance.
|
||||
Return the distance to travel for the next call. If return <= 0, then that
|
||||
contour is done.
|
||||
*/
|
||||
virtual SkScalar next(SkPath* dst, SkScalar dist, SkPathMeasure&) const = 0;
|
||||
|
||||
private:
|
||||
// For simplicity, assume fast bounds cannot be computed
|
||||
bool computeFastBounds(SkRect*) const override { return false; }
|
||||
|
||||
using INHERITED = SkPathEffect;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance, SkScalar phase,
|
||||
Style style) : fPath(path) {
|
||||
SkASSERT(advance > 0 && !path.isEmpty());
|
||||
SkASSERT((unsigned)style <= kMorph_Style);
|
||||
class SkPath1DPathEffectImpl : public Sk1DPathEffect {
|
||||
public:
|
||||
SkPath1DPathEffectImpl(const SkPath& path, SkScalar advance, SkScalar phase,
|
||||
SkPath1DPathEffect::Style style) : fPath(path) {
|
||||
SkASSERT(advance > 0 && !path.isEmpty());
|
||||
|
||||
// Make the path thread-safe.
|
||||
fPath.updateBoundsCache();
|
||||
(void)fPath.getGenerationID();
|
||||
// Make the path thread-safe.
|
||||
fPath.updateBoundsCache();
|
||||
(void)fPath.getGenerationID();
|
||||
|
||||
// cleanup their phase parameter, inverting it so that it becomes an
|
||||
// offset along the path (to match the interpretation in PostScript)
|
||||
if (phase < 0) {
|
||||
phase = -phase;
|
||||
if (phase > advance) {
|
||||
phase = SkScalarMod(phase, advance);
|
||||
// cleanup their phase parameter, inverting it so that it becomes an
|
||||
// offset along the path (to match the interpretation in PostScript)
|
||||
if (phase < 0) {
|
||||
phase = -phase;
|
||||
if (phase > advance) {
|
||||
phase = SkScalarMod(phase, advance);
|
||||
}
|
||||
} else {
|
||||
if (phase > advance) {
|
||||
phase = SkScalarMod(phase, advance);
|
||||
}
|
||||
phase = advance - phase;
|
||||
}
|
||||
} else {
|
||||
if (phase > advance) {
|
||||
phase = SkScalarMod(phase, advance);
|
||||
// now catch the edge case where phase == advance (within epsilon)
|
||||
if (phase >= advance) {
|
||||
phase = 0;
|
||||
}
|
||||
phase = advance - phase;
|
||||
}
|
||||
// now catch the edge case where phase == advance (within epsilon)
|
||||
if (phase >= advance) {
|
||||
phase = 0;
|
||||
}
|
||||
SkASSERT(phase >= 0);
|
||||
SkASSERT(phase >= 0);
|
||||
|
||||
fAdvance = advance;
|
||||
fInitialOffset = phase;
|
||||
|
||||
if ((unsigned)style > kMorph_Style) {
|
||||
SkDEBUGF("SkPath1DPathEffect style enum out of range %d\n", style);
|
||||
fAdvance = advance;
|
||||
fInitialOffset = phase;
|
||||
fStyle = style;
|
||||
}
|
||||
fStyle = style;
|
||||
}
|
||||
|
||||
bool SkPath1DPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
|
||||
SkStrokeRec* rec, const SkRect* cullRect) const {
|
||||
rec->setFillStyle();
|
||||
return this->INHERITED::onFilterPath(dst, src, rec, cullRect);
|
||||
}
|
||||
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
|
||||
const SkRect* cullRect) const override {
|
||||
rec->setFillStyle();
|
||||
return this->INHERITED::onFilterPath(dst, src, rec, cullRect);
|
||||
}
|
||||
|
||||
SkScalar begin(SkScalar contourLength) const override {
|
||||
return fInitialOffset;
|
||||
}
|
||||
|
||||
SkScalar next(SkPath*, SkScalar, SkPathMeasure&) const override;
|
||||
|
||||
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
|
||||
SkScalar advance = buffer.readScalar();
|
||||
SkPath path;
|
||||
buffer.readPath(&path);
|
||||
SkScalar phase = buffer.readScalar();
|
||||
SkPath1DPathEffect::Style style = buffer.read32LE(SkPath1DPathEffect::kLastEnum_Style);
|
||||
return buffer.isValid() ? SkPath1DPathEffect::Make(path, advance, phase, style) : nullptr;
|
||||
}
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
buffer.writeScalar(fAdvance);
|
||||
buffer.writePath(fPath);
|
||||
buffer.writeScalar(fInitialOffset);
|
||||
buffer.writeUInt(fStyle);
|
||||
}
|
||||
|
||||
Factory getFactory() const override { return CreateProc; }
|
||||
const char* getTypeName() const override { return "SkPath1DPathEffect"; }
|
||||
|
||||
private:
|
||||
SkPath fPath; // copied from constructor
|
||||
SkScalar fAdvance; // copied from constructor
|
||||
SkScalar fInitialOffset; // computed from phase
|
||||
SkPath1DPathEffect::Style fStyle; // copied from constructor
|
||||
|
||||
using INHERITED = Sk1DPathEffect;
|
||||
};
|
||||
|
||||
static bool morphpoints(SkPoint dst[], const SkPoint src[], int count,
|
||||
SkPathMeasure& meas, SkScalar dist) {
|
||||
@ -153,52 +204,29 @@ static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas,
|
||||
}
|
||||
}
|
||||
|
||||
SkScalar SkPath1DPathEffect::begin(SkScalar contourLength) const {
|
||||
return fInitialOffset;
|
||||
}
|
||||
|
||||
sk_sp<SkFlattenable> SkPath1DPathEffect::CreateProc(SkReadBuffer& buffer) {
|
||||
SkScalar advance = buffer.readScalar();
|
||||
SkPath path;
|
||||
buffer.readPath(&path);
|
||||
SkScalar phase = buffer.readScalar();
|
||||
Style style = buffer.read32LE(kLastEnum_Style);
|
||||
return buffer.isValid() ? SkPath1DPathEffect::Make(path, advance, phase, style) : nullptr;
|
||||
}
|
||||
|
||||
void SkPath1DPathEffect::flatten(SkWriteBuffer& buffer) const {
|
||||
buffer.writeScalar(fAdvance);
|
||||
buffer.writePath(fPath);
|
||||
buffer.writeScalar(fInitialOffset);
|
||||
buffer.writeUInt(fStyle);
|
||||
}
|
||||
|
||||
SkScalar SkPath1DPathEffect::next(SkPath* dst, SkScalar distance,
|
||||
SkPathMeasure& meas) const {
|
||||
SkScalar SkPath1DPathEffectImpl::next(SkPath* dst, SkScalar distance,
|
||||
SkPathMeasure& meas) const {
|
||||
#if defined(SK_BUILD_FOR_FUZZER)
|
||||
if (dst->countPoints() > 100000) {
|
||||
return fAdvance;
|
||||
}
|
||||
#endif
|
||||
switch (fStyle) {
|
||||
case kTranslate_Style: {
|
||||
case SkPath1DPathEffect::kTranslate_Style: {
|
||||
SkPoint pos;
|
||||
if (meas.getPosTan(distance, &pos, nullptr)) {
|
||||
dst->addPath(fPath, pos.fX, pos.fY);
|
||||
}
|
||||
} break;
|
||||
case kRotate_Style: {
|
||||
case SkPath1DPathEffect::kRotate_Style: {
|
||||
SkMatrix matrix;
|
||||
if (meas.getMatrix(distance, &matrix)) {
|
||||
dst->addPath(fPath, matrix);
|
||||
}
|
||||
} break;
|
||||
case kMorph_Style:
|
||||
case SkPath1DPathEffect::kMorph_Style:
|
||||
morphpath(dst, fPath, meas, distance);
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("unknown Style enum");
|
||||
break;
|
||||
}
|
||||
return fAdvance;
|
||||
}
|
||||
@ -210,5 +238,9 @@ sk_sp<SkPathEffect> SkPath1DPathEffect::Make(const SkPath& path, SkScalar advanc
|
||||
if (advance <= 0 || !SkScalarIsFinite(advance) || !SkScalarIsFinite(phase) || path.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return sk_sp<SkPathEffect>(new SkPath1DPathEffect(path, advance, phase, style));
|
||||
return sk_sp<SkPathEffect>(new SkPath1DPathEffectImpl(path, advance, phase, style));
|
||||
}
|
||||
|
||||
void SkPath1DPathEffect::RegisterFlattenables() {
|
||||
SK_REGISTER_FLATTENABLE(SkPath1DPathEffectImpl);
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "include/core/SkPath.h"
|
||||
#include "include/core/SkRegion.h"
|
||||
#include "include/core/SkStrokeRec.h"
|
||||
@ -13,128 +12,199 @@
|
||||
#include "src/core/SkReadBuffer.h"
|
||||
#include "src/core/SkWriteBuffer.h"
|
||||
|
||||
Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
|
||||
// Calling invert will set the type mask on both matrices, making them thread safe.
|
||||
fMatrixIsInvertible = fMatrix.invert(&fInverse);
|
||||
}
|
||||
class Sk2DPathEffect : public SkPathEffect {
|
||||
public:
|
||||
Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
|
||||
// Calling invert will set the type mask on both matrices, making them thread safe.
|
||||
fMatrixIsInvertible = fMatrix.invert(&fInverse);
|
||||
}
|
||||
|
||||
bool Sk2DPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
|
||||
SkStrokeRec*, const SkRect*) const {
|
||||
if (!fMatrixIsInvertible) {
|
||||
protected:
|
||||
/** New virtual, to be overridden by subclasses.
|
||||
This is called once from filterPath, and provides the
|
||||
uv parameter bounds for the path. Subsequent calls to
|
||||
next() will receive u and v values within these bounds,
|
||||
and then a call to end() will signal the end of processing.
|
||||
*/
|
||||
virtual void begin(const SkIRect& uvBounds, SkPath* dst) const {}
|
||||
virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
|
||||
virtual void end(SkPath* dst) const {}
|
||||
|
||||
/** Low-level virtual called per span of locations in the u-direction.
|
||||
The default implementation calls next() repeatedly with each
|
||||
location.
|
||||
*/
|
||||
virtual void nextSpan(int x, int y, int ucount, SkPath* path) const {
|
||||
if (!fMatrixIsInvertible) {
|
||||
return;
|
||||
}
|
||||
#if defined(SK_BUILD_FOR_FUZZER)
|
||||
if (count > 100) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const SkMatrix& mat = this->getMatrix();
|
||||
SkPoint src, dst;
|
||||
|
||||
src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
|
||||
do {
|
||||
mat.mapPoints(&dst, &src, 1);
|
||||
this->next(dst, x++, y, path);
|
||||
src.fX += SK_Scalar1;
|
||||
} while (--ucount > 0);
|
||||
}
|
||||
|
||||
const SkMatrix& getMatrix() const { return fMatrix; }
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeMatrix(fMatrix);
|
||||
}
|
||||
|
||||
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
|
||||
const SkRect* cullRect) const override {
|
||||
if (!fMatrixIsInvertible) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkPath tmp;
|
||||
SkIRect ir;
|
||||
|
||||
src.transform(fInverse, &tmp);
|
||||
tmp.getBounds().round(&ir);
|
||||
if (!ir.isEmpty()) {
|
||||
this->begin(ir, dst);
|
||||
|
||||
SkRegion rgn;
|
||||
rgn.setPath(tmp, SkRegion(ir));
|
||||
SkRegion::Iterator iter(rgn);
|
||||
for (; !iter.done(); iter.next()) {
|
||||
const SkIRect& rect = iter.rect();
|
||||
for (int y = rect.fTop; y < rect.fBottom; ++y) {
|
||||
this->nextSpan(rect.fLeft, y, rect.width(), dst);
|
||||
}
|
||||
}
|
||||
|
||||
this->end(dst);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
SkMatrix fMatrix, fInverse;
|
||||
bool fMatrixIsInvertible;
|
||||
|
||||
// For simplicity, assume fast bounds cannot be computed
|
||||
bool computeFastBounds(SkRect*) const override { return false; }
|
||||
|
||||
friend class Sk2DPathEffectBlitter;
|
||||
using INHERITED = SkPathEffect;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkLine2DPathEffectImpl : public Sk2DPathEffect {
|
||||
public:
|
||||
SkLine2DPathEffectImpl(SkScalar width, const SkMatrix& matrix)
|
||||
: Sk2DPathEffect(matrix)
|
||||
, fWidth(width)
|
||||
{
|
||||
SkASSERT(width >= 0);
|
||||
}
|
||||
|
||||
bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
|
||||
const SkRect* cullRect) const override {
|
||||
if (this->INHERITED::onFilterPath(dst, src, rec, cullRect)) {
|
||||
rec->setStrokeStyle(fWidth);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SkPath tmp;
|
||||
SkIRect ir;
|
||||
void nextSpan(int u, int v, int ucount, SkPath* dst) const override {
|
||||
if (ucount > 1) {
|
||||
SkPoint src[2], dstP[2];
|
||||
|
||||
src.transform(fInverse, &tmp);
|
||||
tmp.getBounds().round(&ir);
|
||||
if (!ir.isEmpty()) {
|
||||
this->begin(ir, dst);
|
||||
src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
|
||||
src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
|
||||
this->getMatrix().mapPoints(dstP, src, 2);
|
||||
|
||||
SkRegion rgn;
|
||||
rgn.setPath(tmp, SkRegion(ir));
|
||||
SkRegion::Iterator iter(rgn);
|
||||
for (; !iter.done(); iter.next()) {
|
||||
const SkIRect& rect = iter.rect();
|
||||
for (int y = rect.fTop; y < rect.fBottom; ++y) {
|
||||
this->nextSpan(rect.fLeft, y, rect.width(), dst);
|
||||
}
|
||||
dst->moveTo(dstP[0]);
|
||||
dst->lineTo(dstP[1]);
|
||||
}
|
||||
|
||||
this->end(dst);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path) const {
|
||||
if (!fMatrixIsInvertible) {
|
||||
return;
|
||||
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
|
||||
SkMatrix matrix;
|
||||
buffer.readMatrix(&matrix);
|
||||
SkScalar width = buffer.readScalar();
|
||||
return SkLine2DPathEffect::Make(width, matrix);
|
||||
}
|
||||
#if defined(SK_BUILD_FOR_FUZZER)
|
||||
if (count > 100) {
|
||||
return;
|
||||
|
||||
void flatten(SkWriteBuffer &buffer) const override {
|
||||
buffer.writeMatrix(this->getMatrix());
|
||||
buffer.writeScalar(fWidth);
|
||||
}
|
||||
#endif
|
||||
|
||||
const SkMatrix& mat = this->getMatrix();
|
||||
SkPoint src, dst;
|
||||
Factory getFactory() const override { return CreateProc; }
|
||||
const char* getTypeName() const override { return "SkLine2DPathEffect"; }
|
||||
|
||||
src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
|
||||
do {
|
||||
mat.mapPoints(&dst, &src, 1);
|
||||
this->next(dst, x++, y, path);
|
||||
src.fX += SK_Scalar1;
|
||||
} while (--count > 0);
|
||||
}
|
||||
private:
|
||||
SkScalar fWidth;
|
||||
|
||||
void Sk2DPathEffect::begin(const SkIRect& uvBounds, SkPath* dst) const {}
|
||||
void Sk2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) const {}
|
||||
void Sk2DPathEffect::end(SkPath* dst) const {}
|
||||
using INHERITED = Sk2DPathEffect;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Sk2DPathEffect::flatten(SkWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeMatrix(fMatrix);
|
||||
}
|
||||
class SK_API SkPath2DPathEffectImpl : public Sk2DPathEffect {
|
||||
public:
|
||||
SkPath2DPathEffectImpl(const SkMatrix& m, const SkPath& p) : INHERITED(m), fPath(p) {}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkLine2DPathEffect::onFilterPath(SkPath* dst, const SkPath& src,
|
||||
SkStrokeRec* rec, const SkRect* cullRect) const {
|
||||
if (this->INHERITED::onFilterPath(dst, src, rec, cullRect)) {
|
||||
rec->setStrokeStyle(fWidth);
|
||||
return true;
|
||||
void next(const SkPoint& loc, int u, int v, SkPath* dst) const override {
|
||||
dst->addPath(fPath, loc.fX, loc.fY);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SkLine2DPathEffect::nextSpan(int u, int v, int ucount, SkPath* dst) const {
|
||||
if (ucount > 1) {
|
||||
SkPoint src[2], dstP[2];
|
||||
|
||||
src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
|
||||
src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf);
|
||||
this->getMatrix().mapPoints(dstP, src, 2);
|
||||
|
||||
dst->moveTo(dstP[0]);
|
||||
dst->lineTo(dstP[1]);
|
||||
static sk_sp<SkFlattenable> CreateProc(SkReadBuffer& buffer) {
|
||||
SkMatrix matrix;
|
||||
buffer.readMatrix(&matrix);
|
||||
SkPath path;
|
||||
buffer.readPath(&path);
|
||||
return SkPath2DPathEffect::Make(matrix, path);
|
||||
}
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
buffer.writeMatrix(this->getMatrix());
|
||||
buffer.writePath(fPath);
|
||||
}
|
||||
|
||||
Factory getFactory() const override { return CreateProc; }
|
||||
const char* getTypeName() const override { return "SkPath2DPathEffect"; }
|
||||
|
||||
private:
|
||||
SkPath fPath;
|
||||
|
||||
using INHERITED = Sk2DPathEffect;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkPathEffect> SkLine2DPathEffect::Make(SkScalar width, const SkMatrix& matrix) {
|
||||
if (!(width >= 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
return sk_sp<SkPathEffect>(new SkLine2DPathEffectImpl(width, matrix));
|
||||
}
|
||||
|
||||
sk_sp<SkFlattenable> SkLine2DPathEffect::CreateProc(SkReadBuffer& buffer) {
|
||||
SkMatrix matrix;
|
||||
buffer.readMatrix(&matrix);
|
||||
SkScalar width = buffer.readScalar();
|
||||
return SkLine2DPathEffect::Make(width, matrix);
|
||||
sk_sp<SkPathEffect> SkPath2DPathEffect::Make(const SkMatrix& matrix, const SkPath& path) {
|
||||
return sk_sp<SkPathEffect>(new SkPath2DPathEffectImpl(matrix, path));
|
||||
}
|
||||
|
||||
void SkLine2DPathEffect::flatten(SkWriteBuffer &buffer) const {
|
||||
buffer.writeMatrix(this->getMatrix());
|
||||
buffer.writeScalar(fWidth);
|
||||
void SkLine2DPathEffect::RegisterFlattenables() {
|
||||
SK_REGISTER_FLATTENABLE(SkLine2DPathEffectImpl);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPath2DPathEffect::SkPath2DPathEffect(const SkMatrix& m, const SkPath& p)
|
||||
: INHERITED(m), fPath(p) {
|
||||
}
|
||||
|
||||
sk_sp<SkFlattenable> SkPath2DPathEffect::CreateProc(SkReadBuffer& buffer) {
|
||||
SkMatrix matrix;
|
||||
buffer.readMatrix(&matrix);
|
||||
SkPath path;
|
||||
buffer.readPath(&path);
|
||||
return SkPath2DPathEffect::Make(matrix, path);
|
||||
}
|
||||
|
||||
void SkPath2DPathEffect::flatten(SkWriteBuffer& buffer) const {
|
||||
buffer.writeMatrix(this->getMatrix());
|
||||
buffer.writePath(fPath);
|
||||
}
|
||||
|
||||
void SkPath2DPathEffect::next(const SkPoint& loc, int u, int v,
|
||||
SkPath* dst) const {
|
||||
dst->addPath(fPath, loc.fX, loc.fY);
|
||||
void SkPath2DPathEffect::RegisterFlattenables() {
|
||||
SK_REGISTER_FLATTENABLE(SkPath2DPathEffectImpl);
|
||||
}
|
||||
|
@ -89,11 +89,11 @@
|
||||
SK_REGISTER_FLATTENABLE(SkCornerPathEffect);
|
||||
SK_REGISTER_FLATTENABLE(SkDashImpl);
|
||||
SK_REGISTER_FLATTENABLE(SkDiscretePathEffect);
|
||||
SK_REGISTER_FLATTENABLE(SkLine2DPathEffect);
|
||||
SkLine2DPathEffect::RegisterFlattenables();
|
||||
SkPath2DPathEffect::RegisterFlattenables();
|
||||
SK_REGISTER_FLATTENABLE(SkMatrixPE);
|
||||
SK_REGISTER_FLATTENABLE(SkOpPE);
|
||||
SK_REGISTER_FLATTENABLE(SkPath1DPathEffect);
|
||||
SK_REGISTER_FLATTENABLE(SkPath2DPathEffect);
|
||||
SkPath1DPathEffect::RegisterFlattenables();
|
||||
SK_REGISTER_FLATTENABLE(SkStrokePE);
|
||||
SK_REGISTER_FLATTENABLE(SkStrokeAndFillPE);
|
||||
SK_REGISTER_FLATTENABLE(SkTrimPE);
|
||||
|
Loading…
Reference in New Issue
Block a user