Import Cobalt 25.master.0.1033734
diff --git a/third_party/skia/samplecode/PerlinPatch.cpp b/third_party/skia/samplecode/PerlinPatch.cpp
deleted file mode 100644
index 43dce62..0000000
--- a/third_party/skia/samplecode/PerlinPatch.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2015 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/effects/SkGradientShader.h"
-#include "include/effects/SkPerlinNoiseShader.h"
-#include "samplecode/Sample.h"
-#include "src/utils/SkPatchUtils.h"
-#include "tools/skui/ModifierKey.h"
-
-static void draw_control_points(SkCanvas* canvas, const SkPoint cubics[12]) {
- //draw control points
- SkPaint paint;
- SkPoint bottom[SkPatchUtils::kNumPtsCubic];
- SkPatchUtils::GetBottomCubic(cubics, bottom);
- SkPoint top[SkPatchUtils::kNumPtsCubic];
- SkPatchUtils::GetTopCubic(cubics, top);
- SkPoint left[SkPatchUtils::kNumPtsCubic];
- SkPatchUtils::GetLeftCubic(cubics, left);
- SkPoint right[SkPatchUtils::kNumPtsCubic];
- SkPatchUtils::GetRightCubic(cubics, right);
-
- paint.setColor(SK_ColorBLACK);
- paint.setStrokeWidth(0.5f);
- SkPoint corners[4] = { bottom[0], bottom[3], top[0], top[3] };
- canvas->drawPoints(SkCanvas::kLines_PointMode, 4, bottom, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, bottom + 1, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 4, top, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 4, left, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 4, right, paint);
-
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, top + 1, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, left + 1, paint);
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, right + 1, paint);
-
- paint.setStrokeWidth(2);
-
- paint.setColor(SK_ColorRED);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, paint);
-
- paint.setColor(SK_ColorBLUE);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom + 1, paint);
-
- paint.setColor(SK_ColorCYAN);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top + 1, paint);
-
- paint.setColor(SK_ColorYELLOW);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left + 1, paint);
-
- paint.setColor(SK_ColorGREEN);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right + 1, paint);
-}
-
-// These are actually half the total width and hieghts
-const SkScalar TexWidth = 100.0f;
-const SkScalar TexHeight = 100.0f;
-
-class PerlinPatchView : public Sample {
- sk_sp<SkShader> fShader0;
- sk_sp<SkShader> fShader1;
- sk_sp<SkShader> fShaderCompose;
- SkScalar fXFreq;
- SkScalar fYFreq;
- SkScalar fSeed;
- SkPoint fPts[SkPatchUtils::kNumCtrlPts];
- SkScalar fTexX;
- SkScalar fTexY;
- SkScalar fTexScale;
- SkMatrix fInvMatrix;
- bool fShowGrid = false;
-
-public:
- PerlinPatchView() : fXFreq(0.025f), fYFreq(0.025f), fSeed(0.0f),
- fTexX(100.0), fTexY(50.0), fTexScale(1.0f) {
- const SkScalar s = 2;
- // The order of the colors and points is clockwise starting at upper-left corner.
- //top points
- fPts[0].set(100 * s, 100 * s);
- fPts[1].set(150 * s, 50 * s);
- fPts[2].set(250 * s, 150 * s);
- fPts[3].set(300 * s, 100 * s);
- //right points
- fPts[4].set(275 * s, 150 * s);
- fPts[5].set(350 * s, 250 * s);
- //bottom points
- fPts[6].set(300 * s, 300 * s);
- fPts[7].set(250 * s, 250 * s);
- //left points
- fPts[8].set(150 * s, 350 * s);
- fPts[9].set(100 * s, 300 * s);
- fPts[10].set(50 * s, 250 * s);
- fPts[11].set(150 * s, 150 * s);
-
- const SkColor colors[SkPatchUtils::kNumCorners] = {
- 0xFF5555FF, 0xFF8888FF, 0xFFCCCCFF
- };
- const SkPoint points[2] = { SkPoint::Make(0.0f, 0.0f),
- SkPoint::Make(100.0f, 100.0f) };
- fShader0 = SkGradientShader::MakeLinear(points,
- colors,
- nullptr,
- 3,
- SkTileMode::kMirror,
- 0,
- nullptr);
- }
-
-protected:
- SkString name() override { return SkString("PerlinPatch"); }
-
- bool onChar(SkUnichar uni) override {
- switch (uni) {
- case 'g': fShowGrid = !fShowGrid; return true;
- default: break;
- }
- return false;
- }
-
- bool onAnimate(double nanos) override {
- fSeed += 0.005f;
- return true;
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- if (!canvas->getTotalMatrix().invert(&fInvMatrix)) {
- return;
- }
-
- SkPaint paint;
-
- SkScalar texWidth = fTexScale * TexWidth;
- SkScalar texHeight = fTexScale * TexHeight;
- const SkPoint texCoords[SkPatchUtils::kNumCorners] = {
- { fTexX - texWidth, fTexY - texHeight},
- { fTexX + texWidth, fTexY - texHeight},
- { fTexX + texWidth, fTexY + texHeight},
- { fTexX - texWidth, fTexY + texHeight}}
- ;
-
- SkScalar scaleFreq = 2.0;
- fShader1 = SkPerlinNoiseShader::MakeImprovedNoise(fXFreq/scaleFreq, fYFreq/scaleFreq, 4,
- fSeed);
- fShaderCompose = SkShaders::Blend(SkBlendMode::kSrcOver, fShader0, fShader1);
-
- paint.setShader(fShaderCompose);
-
- const SkPoint* tex = texCoords;
- if (fShowGrid) {
- tex = nullptr;
- }
- canvas->drawPatch(fPts, nullptr, tex, SkBlendMode::kSrc, paint);
-
- draw_control_points(canvas, fPts);
- }
-
- class PtClick : public Click {
- public:
- int fIndex;
- PtClick(int index) : fIndex(index) {}
- };
-
- static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
- return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5);
- }
-
- Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
- modi &= ~skui::ModifierKey::kFirstPress; // ignore this
- if (skui::ModifierKey::kShift == modi) {
- return new PtClick(-1);
- }
- if (skui::ModifierKey::kControl == modi) {
- return new PtClick(-2);
- }
- SkPoint clickPoint = {x, y};
- fInvMatrix.mapPoints(&clickPoint, 1);
- for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
- if (hittest(fPts[i], clickPoint.fX, clickPoint.fY)) {
- return new PtClick((int)i);
- }
- }
- return nullptr;
- }
-
- bool onClick(Click* click) override {
- PtClick* ptClick = (PtClick*)click;
- if (ptClick->fIndex >= 0) {
- fPts[ptClick->fIndex].set(click->fCurr.fX , click->fCurr.fY );
- } else if (-1 == ptClick->fIndex) {
- SkScalar xDiff = click->fPrev.fX - click->fCurr.fX;
- SkScalar yDiff = click->fPrev.fY - click->fCurr.fY;
- fTexX += xDiff * fTexScale;
- fTexY += yDiff * fTexScale;
- } else if (-2 == ptClick->fIndex) {
- SkScalar yDiff = click->fCurr.fY - click->fPrev.fY;
- fTexScale += yDiff / 10.0f;
- fTexScale = SkTMax(0.1f, SkTMin(20.f, fTexScale));
- }
- return true;
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-DEF_SAMPLE( return new PerlinPatchView(); )
diff --git a/third_party/skia/samplecode/Sample.cpp b/third_party/skia/samplecode/Sample.cpp
index c2ba788..a69de8e 100644
--- a/third_party/skia/samplecode/Sample.cpp
+++ b/third_party/skia/samplecode/Sample.cpp
@@ -10,16 +10,16 @@
#include "samplecode/Sample.h"
#if SK_SUPPORT_GPU
-# include "include/gpu/GrContext.h"
+# include "include/gpu/GrDirectContext.h"
#else
-class GrContext;
+class GrDirectContext;
#endif
//////////////////////////////////////////////////////////////////////////////
void Sample::setSize(SkScalar width, SkScalar height) {
- width = SkMaxScalar(0, width);
- height = SkMaxScalar(0, height);
+ width = std::max(0.0f, width);
+ height = std::max(0.0f, height);
if (fWidth != width || fHeight != height)
{
@@ -49,9 +49,9 @@
SkAutoCanvasRestore acr(canvas, true);
this->onDrawContent(canvas);
#if SK_SUPPORT_GPU
- // Ensure the GrContext doesn't combine GrDrawOps across draw loops.
- if (GrContext* context = canvas->getGrContext()) {
- context->flush();
+ // Ensure the context doesn't combine GrDrawOps across draw loops.
+ if (auto direct = GrAsDirectContext(canvas->recordingContext())) {
+ direct->flushAndSubmit();
}
#endif
@@ -62,12 +62,13 @@
////////////////////////////////////////////////////////////////////////////
bool Sample::mouse(SkPoint point, skui::InputState clickState, skui::ModifierKey modifierKeys) {
+ auto dispatch = [this](Click* c) {
+ return c->fHasFunc ? c->fFunc(c) : this->onClick(c);
+ };
+
switch (clickState) {
case skui::InputState::kDown:
fClick = nullptr;
- if (point.x() < 0 || point.y() < 0 || point.x() >= fWidth || point.y() >= fHeight) {
- return false;
- }
fClick.reset(this->onFindClickHandler(point.x(), point.y(), modifierKeys));
if (!fClick) {
return false;
@@ -75,7 +76,7 @@
fClick->fPrev = fClick->fCurr = fClick->fOrig = point;
fClick->fState = skui::InputState::kDown;
fClick->fModifierKeys = modifierKeys;
- this->onClick(fClick.get());
+ dispatch(fClick.get());
return true;
case skui::InputState::kMove:
if (fClick) {
@@ -83,7 +84,7 @@
fClick->fCurr = point;
fClick->fState = skui::InputState::kMove;
fClick->fModifierKeys = modifierKeys;
- return this->onClick(fClick.get());
+ return dispatch(fClick.get());
}
return false;
case skui::InputState::kUp:
@@ -92,7 +93,7 @@
fClick->fCurr = point;
fClick->fState = skui::InputState::kUp;
fClick->fModifierKeys = modifierKeys;
- bool result = this->onClick(fClick.get());
+ bool result = dispatch(fClick.get());
fClick = nullptr;
return result;
}
diff --git a/third_party/skia/samplecode/Sample.h b/third_party/skia/samplecode/Sample.h
index d6ccf48..f1026bd 100644
--- a/third_party/skia/samplecode/Sample.h
+++ b/third_party/skia/samplecode/Sample.h
@@ -18,6 +18,8 @@
#include "tools/skui/InputState.h"
#include "tools/skui/ModifierKey.h"
+#include <functional>
+
class SkCanvas;
class Sample;
@@ -55,13 +57,19 @@
// Click handling
class Click {
public:
+ Click() {}
+ Click(std::function<bool(Click*)> f) : fFunc(f), fHasFunc(true) {}
virtual ~Click() = default;
+
SkPoint fOrig = {0, 0};
SkPoint fPrev = {0, 0};
SkPoint fCurr = {0, 0};
skui::InputState fState = skui::InputState::kDown;
skui::ModifierKey fModifierKeys = skui::ModifierKey::kNone;
SkMetaData fMeta;
+
+ std::function<bool(Click*)> fFunc;
+ bool fHasFunc = false;
};
bool mouse(SkPoint point, skui::InputState clickState, skui::ModifierKey modifierKeys);
diff --git a/third_party/skia/samplecode/Sample2PtRadial.cpp b/third_party/skia/samplecode/Sample2PtRadial.cpp
index 64f9e66..f404d14 100644
--- a/third_party/skia/samplecode/Sample2PtRadial.cpp
+++ b/third_party/skia/samplecode/Sample2PtRadial.cpp
@@ -14,9 +14,9 @@
TwoPtConicalView() {}
protected:
- virtual SkString name() { return SkString("2PtConical"); }
+ SkString name() override { return SkString("2PtConical"); }
- virtual void onDrawContent(SkCanvas* canvas) {
+ void onDrawContent(SkCanvas* canvas) override {
canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
@@ -32,7 +32,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/Sample3D.cpp b/third_party/skia/samplecode/Sample3D.cpp
new file mode 100644
index 0000000..7e958bc
--- /dev/null
+++ b/third_party/skia/samplecode/Sample3D.cpp
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2020 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/SkM44.h"
+#include "include/core/SkPaint.h"
+#include "include/core/SkRRect.h"
+#include "include/core/SkVertices.h"
+#include "include/utils/SkRandom.h"
+#include "samplecode/Sample.h"
+#include "tools/Resources.h"
+
+struct VSphere {
+ SkV2 fCenter;
+ SkScalar fRadius;
+
+ VSphere(SkV2 center, SkScalar radius) : fCenter(center), fRadius(radius) {}
+
+ bool contains(SkV2 v) const {
+ return (v - fCenter).length() <= fRadius;
+ }
+
+ SkV2 pinLoc(SkV2 p) const {
+ auto v = p - fCenter;
+ if (v.length() > fRadius) {
+ v *= (fRadius / v.length());
+ }
+ return fCenter + v;
+ }
+
+ SkV3 computeUnitV3(SkV2 v) const {
+ v = (v - fCenter) * (1 / fRadius);
+ SkScalar len2 = v.lengthSquared();
+ if (len2 > 1) {
+ v = v.normalize();
+ len2 = 1;
+ }
+ SkScalar z = SkScalarSqrt(1 - len2);
+ return {v.x, v.y, z};
+ }
+
+ struct RotateInfo {
+ SkV3 fAxis;
+ SkScalar fAngle;
+ };
+
+ RotateInfo computeRotationInfo(SkV2 a, SkV2 b) const {
+ SkV3 u = this->computeUnitV3(a);
+ SkV3 v = this->computeUnitV3(b);
+ SkV3 axis = u.cross(v);
+ SkScalar length = axis.length();
+
+ if (!SkScalarNearlyZero(length)) {
+ return {axis * (1.0f / length), acos(u.dot(v))};
+ }
+ return {{0, 0, 0}, 0};
+ }
+
+ SkM44 computeRotation(SkV2 a, SkV2 b) const {
+ auto [axis, angle] = this->computeRotationInfo(a, b);
+ return SkM44::Rotate(axis, angle);
+ }
+};
+
+static SkM44 inv(const SkM44& m) {
+ SkM44 inverse;
+ SkAssertResult(m.invert(&inverse));
+ return inverse;
+}
+
+// Compute the inverse transpose (of the upper-left 3x3) of a matrix, used to transform vectors
+static SkM44 normals(SkM44 m) {
+ m.setRow(3, {0, 0, 0, 1});
+ m.setCol(3, {0, 0, 0, 1});
+ SkAssertResult(m.invert(&m));
+ return m.transpose();
+}
+
+class Sample3DView : public Sample {
+protected:
+ float fNear = 0.05f;
+ float fFar = 4;
+ float fAngle = SK_ScalarPI / 12;
+
+ SkV3 fEye { 0, 0, 1.0f/tan(fAngle/2) - 1 };
+ SkV3 fCOA { 0, 0, 0 };
+ SkV3 fUp { 0, 1, 0 };
+
+public:
+ void concatCamera(SkCanvas* canvas, const SkRect& area, SkScalar zscale) {
+ SkM44 camera = SkM44::LookAt(fEye, fCOA, fUp),
+ perspective = SkM44::Perspective(fNear, fFar, fAngle),
+ viewport = SkM44::Translate(area.centerX(), area.centerY(), 0) *
+ SkM44::Scale(area.width()*0.5f, area.height()*0.5f, zscale);
+
+ canvas->concat(viewport * perspective * camera * inv(viewport));
+ }
+};
+
+struct Face {
+ SkScalar fRx, fRy;
+ SkColor fColor;
+
+ static SkM44 T(SkScalar x, SkScalar y, SkScalar z) {
+ return SkM44::Translate(x, y, z);
+ }
+
+ static SkM44 R(SkV3 axis, SkScalar rad) {
+ return SkM44::Rotate(axis, rad);
+ }
+
+ SkM44 asM44(SkScalar scale) const {
+ return R({0,1,0}, fRy) * R({1,0,0}, fRx) * T(0, 0, scale);
+ }
+};
+
+static bool front(const SkM44& m) {
+ SkM44 m2(SkM44::kUninitialized_Constructor);
+ if (!m.invert(&m2)) {
+ m2.setIdentity();
+ }
+ /*
+ * Classically we want to dot the transpose(inverse(ctm)) with our surface normal.
+ * In this case, the normal is known to be {0, 0, 1}, so we only actually need to look
+ * at the z-scale of the inverse (the transpose doesn't change the main diagonal, so
+ * no need to actually transpose).
+ */
+ return m2.rc(2,2) > 0;
+}
+
+const Face faces[] = {
+ { 0, 0, SK_ColorRED }, // front
+ { 0, SK_ScalarPI, SK_ColorGREEN }, // back
+
+ { SK_ScalarPI/2, 0, SK_ColorBLUE }, // top
+ {-SK_ScalarPI/2, 0, SK_ColorCYAN }, // bottom
+
+ { 0, SK_ScalarPI/2, SK_ColorMAGENTA }, // left
+ { 0,-SK_ScalarPI/2, SK_ColorYELLOW }, // right
+};
+
+#include "include/effects/SkRuntimeEffect.h"
+
+struct LightOnSphere {
+ SkV2 fLoc;
+ SkScalar fDistance;
+ SkScalar fRadius;
+
+ SkV3 computeWorldPos(const VSphere& s) const {
+ return s.computeUnitV3(fLoc) * fDistance;
+ }
+
+ void draw(SkCanvas* canvas) const {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawCircle(fLoc.x, fLoc.y, fRadius + 2, paint);
+ paint.setColor(SK_ColorBLACK);
+ canvas->drawCircle(fLoc.x, fLoc.y, fRadius, paint);
+ }
+};
+
+#include "include/core/SkTime.h"
+
+class RotateAnimator {
+ SkV3 fAxis = {0, 0, 0};
+ SkScalar fAngle = 0,
+ fPrevAngle = 1234567;
+ double fNow = 0,
+ fPrevNow = 0;
+
+ SkScalar fAngleSpeed = 0,
+ fAngleSign = 1;
+
+ inline static constexpr double kSlowDown = 4;
+ inline static constexpr SkScalar kMaxSpeed = 16;
+
+public:
+ void update(SkV3 axis, SkScalar angle) {
+ if (angle != fPrevAngle) {
+ fPrevAngle = fAngle;
+ fAngle = angle;
+
+ fPrevNow = fNow;
+ fNow = SkTime::GetSecs();
+
+ fAxis = axis;
+ }
+ }
+
+ SkM44 rotation() {
+ if (fAngleSpeed > 0) {
+ double now = SkTime::GetSecs();
+ double dtime = now - fPrevNow;
+ fPrevNow = now;
+ double delta = fAngleSign * fAngleSpeed * dtime;
+ fAngle += delta;
+ fAngleSpeed -= kSlowDown * dtime;
+ if (fAngleSpeed < 0) {
+ fAngleSpeed = 0;
+ }
+ }
+ return SkM44::Rotate(fAxis, fAngle);
+
+ }
+
+ void start() {
+ if (fPrevNow != fNow) {
+ fAngleSpeed = (fAngle - fPrevAngle) / (fNow - fPrevNow);
+ fAngleSign = fAngleSpeed < 0 ? -1 : 1;
+ fAngleSpeed = std::min(kMaxSpeed, std::abs(fAngleSpeed));
+ } else {
+ fAngleSpeed = 0;
+ }
+ fPrevNow = SkTime::GetSecs();
+ fAngle = 0;
+ }
+
+ void reset() {
+ fAngleSpeed = 0;
+ fAngle = 0;
+ fPrevAngle = 1234567;
+ }
+
+ bool isAnimating() const { return fAngleSpeed != 0; }
+};
+
+class SampleCubeBase : public Sample3DView {
+ enum {
+ DX = 400,
+ DY = 300
+ };
+
+ SkM44 fRotation; // part of model
+
+ RotateAnimator fRotateAnimator;
+
+protected:
+ enum Flags {
+ kCanRunOnCPU = 1 << 0,
+ kShowLightDome = 1 << 1,
+ };
+
+ LightOnSphere fLight = {{200 + DX, 200 + DY}, 800, 12};
+
+ VSphere fSphere;
+ Flags fFlags;
+
+public:
+ SampleCubeBase(Flags flags)
+ : fSphere({200 + DX, 200 + DY}, 400)
+ , fFlags(flags)
+ {}
+
+ bool onChar(SkUnichar uni) override {
+ switch (uni) {
+ case 'Z': fLight.fDistance += 10; return true;
+ case 'z': fLight.fDistance -= 10; return true;
+ }
+ return this->Sample3DView::onChar(uni);
+ }
+
+ virtual void drawContent(
+ SkCanvas* canvas, SkColor, int index, bool drawFront, const SkM44& localToWorld) = 0;
+
+ void onDrawContent(SkCanvas* canvas) override {
+ if (!canvas->recordingContext() && !(fFlags & kCanRunOnCPU)) {
+ return;
+ }
+
+ canvas->save();
+ canvas->translate(DX, DY);
+
+ this->concatCamera(canvas, {0, 0, 400, 400}, 200);
+
+ for (bool drawFront : {false, true}) {
+ int index = 0;
+ for (auto f : faces) {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ SkM44 trans = SkM44::Translate(200, 200, 0); // center of the rotation
+ SkM44 m = fRotateAnimator.rotation() * fRotation * f.asM44(200);
+
+ canvas->concat(trans);
+
+ // "World" space - content is centered at the origin, in device scale (+-200)
+ SkM44 localToWorld = m * inv(trans);
+
+ canvas->concat(localToWorld);
+ this->drawContent(canvas, f.fColor, index++, drawFront, localToWorld);
+ }
+ }
+
+ canvas->restore(); // camera & center the content in the window
+
+ if (fFlags & kShowLightDome){
+ fLight.draw(canvas);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(0x40FF0000);
+ canvas->drawCircle(fSphere.fCenter.x, fSphere.fCenter.y, fSphere.fRadius, paint);
+ canvas->drawLine(fSphere.fCenter.x, fSphere.fCenter.y - fSphere.fRadius,
+ fSphere.fCenter.x, fSphere.fCenter.y + fSphere.fRadius, paint);
+ canvas->drawLine(fSphere.fCenter.x - fSphere.fRadius, fSphere.fCenter.y,
+ fSphere.fCenter.x + fSphere.fRadius, fSphere.fCenter.y, paint);
+ }
+ }
+
+ Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
+ SkV2 p = fLight.fLoc - SkV2{x, y};
+ if (p.length() <= fLight.fRadius) {
+ Click* c = new Click();
+ c->fMeta.setS32("type", 0);
+ return c;
+ }
+ if (fSphere.contains({x, y})) {
+ Click* c = new Click();
+ c->fMeta.setS32("type", 1);
+
+ fRotation = fRotateAnimator.rotation() * fRotation;
+ fRotateAnimator.reset();
+ return c;
+ }
+ return nullptr;
+ }
+ bool onClick(Click* click) override {
+ if (click->fMeta.hasS32("type", 0)) {
+ fLight.fLoc = fSphere.pinLoc({click->fCurr.fX, click->fCurr.fY});
+ return true;
+ }
+ if (click->fMeta.hasS32("type", 1)) {
+ if (click->fState == skui::InputState::kUp) {
+ fRotation = fRotateAnimator.rotation() * fRotation;
+ fRotateAnimator.start();
+ } else {
+ auto [axis, angle] = fSphere.computeRotationInfo(
+ {click->fOrig.fX, click->fOrig.fY},
+ {click->fCurr.fX, click->fCurr.fY});
+ fRotateAnimator.update(axis, angle);
+ }
+ return true;
+ }
+ return true;
+ }
+
+ bool onAnimate(double nanos) override {
+ return fRotateAnimator.isAnimating();
+ }
+
+private:
+ using INHERITED = Sample3DView;
+};
+
+class SampleBump3D : public SampleCubeBase {
+ sk_sp<SkShader> fBmpShader, fImgShader;
+ sk_sp<SkRuntimeEffect> fEffect;
+ SkRRect fRR;
+
+public:
+ SampleBump3D() : SampleCubeBase(Flags(kCanRunOnCPU | kShowLightDome)) {}
+
+ SkString name() override { return SkString("bump3d"); }
+
+ void onOnceBeforeDraw() override {
+ fRR = SkRRect::MakeRectXY({20, 20, 380, 380}, 50, 50);
+ auto img = GetResourceAsImage("images/brickwork-texture.jpg");
+ fImgShader = img->makeShader(SkSamplingOptions(), SkMatrix::Scale(2, 2));
+ img = GetResourceAsImage("images/brickwork_normal-map.jpg");
+ fBmpShader = img->makeShader(SkSamplingOptions(), SkMatrix::Scale(2, 2));
+
+ const char code[] = R"(
+ uniform shader color_map;
+ uniform shader normal_map;
+
+ uniform float4x4 localToWorld;
+ uniform float4x4 localToWorldAdjInv;
+ uniform float3 lightPos;
+
+ float3 convert_normal_sample(half4 c) {
+ float3 n = 2 * c.rgb - 1;
+ n.y = -n.y;
+ return n;
+ }
+
+ half4 main(float2 p) {
+ float3 norm = convert_normal_sample(normal_map.eval(p));
+ float3 plane_norm = normalize(localToWorldAdjInv * norm.xyz0).xyz;
+
+ float3 plane_pos = (localToWorld * p.xy01).xyz;
+ float3 light_dir = normalize(lightPos - plane_pos);
+
+ float ambient = 0.2;
+ float dp = dot(plane_norm, light_dir);
+ float scale = min(ambient + max(dp, 0), 1);
+
+ return color_map.eval(p) * scale.xxx1;
+ }
+ )";
+ auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(code));
+ if (!effect) {
+ SkDebugf("runtime error %s\n", error.c_str());
+ }
+ fEffect = effect;
+ }
+
+ void drawContent(SkCanvas* canvas,
+ SkColor color,
+ int index,
+ bool drawFront,
+ const SkM44& localToWorld) override {
+ if (!drawFront || !front(canvas->getLocalToDevice())) {
+ return;
+ }
+
+ SkRuntimeShaderBuilder builder(fEffect);
+ builder.uniform("lightPos") = fLight.computeWorldPos(fSphere);
+ builder.uniform("localToWorld") = localToWorld;
+ builder.uniform("localToWorldAdjInv") = normals(localToWorld);
+
+ builder.child("color_map") = fImgShader;
+ builder.child("normal_map") = fBmpShader;
+
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setShader(builder.makeShader());
+
+ canvas->drawRRect(fRR, paint);
+ }
+};
+DEF_SAMPLE( return new SampleBump3D; )
+
+#include "modules/skottie/include/Skottie.h"
+
+class SampleSkottieCube : public SampleCubeBase {
+ sk_sp<skottie::Animation> fAnim[6];
+
+public:
+ SampleSkottieCube() : SampleCubeBase(kCanRunOnCPU) {}
+
+ SkString name() override { return SkString("skottie3d"); }
+
+ void onOnceBeforeDraw() override {
+ const char* files[] = {
+ "skottie/skottie-chained-mattes.json",
+ "skottie/skottie-gradient-ramp.json",
+ "skottie/skottie_sample_2.json",
+ "skottie/skottie-3d-3planes.json",
+ "skottie/skottie-text-animator-4.json",
+ "skottie/skottie-motiontile-effect-phase.json",
+
+ };
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(files); ++i) {
+ if (auto stream = GetResourceAsStream(files[i])) {
+ fAnim[i] = skottie::Animation::Make(stream.get());
+ }
+ }
+ }
+
+ void drawContent(
+ SkCanvas* canvas, SkColor color, int index, bool drawFront, const SkM44&) override {
+ if (!drawFront || !front(canvas->getLocalToDevice())) {
+ return;
+ }
+
+ SkPaint paint;
+ paint.setColor(color);
+ SkRect r = {0, 0, 400, 400};
+ canvas->drawRect(r, paint);
+ fAnim[index]->render(canvas, &r);
+ }
+
+ bool onAnimate(double nanos) override {
+ for (auto& anim : fAnim) {
+ SkScalar dur = anim->duration();
+ SkScalar t = fmod(1e-9 * nanos, dur) / dur;
+ anim->seek(t);
+ }
+ return true;
+ }
+};
+DEF_SAMPLE( return new SampleSkottieCube; )
diff --git a/third_party/skia/samplecode/SampleAAClip.cpp b/third_party/skia/samplecode/SampleAAClip.cpp
deleted file mode 100644
index 46e4fe2..0000000
--- a/third_party/skia/samplecode/SampleAAClip.cpp
+++ /dev/null
@@ -1,106 +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/SkPath.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkAAClip.h"
-
-static void testop(const SkIRect& r0, const SkIRect& r1, SkRegion::Op op,
- const SkIRect& expectedR) {
- SkAAClip c0, c1, c2;
- c0.setRect(r0);
- c1.setRect(r1);
- c2.op(c0, c1, op);
-
- SkDEBUGCODE(SkIRect r2 = c2.getBounds());
- SkASSERT(r2 == expectedR);
-}
-
-static const struct {
- SkIRect r0;
- SkIRect r1;
- SkRegion::Op op;
- SkIRect expectedR;
-} gRec[] = {
- {{ 1, 2, 9, 3 }, { -3, 2, 5, 11 }, SkRegion::kDifference_Op, { 5, 2, 9, 3 }},
- {{ 1, 10, 5, 13 }, { 1, 2, 5, 11 }, SkRegion::kDifference_Op, { 1, 11, 5, 13 }},
- {{ 1, 10, 5, 13 }, { 1, 2, 5, 11 }, SkRegion::kReverseDifference_Op, { 1, 2, 5, 10 }},
-};
-
-static void testop() {
- for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
- testop(gRec[i].r0, gRec[i].r1, gRec[i].op, gRec[i].expectedR);
- }
-}
-
-static void drawClip(SkCanvas* canvas, const SkAAClip& clip) {
- SkMask mask;
- SkBitmap bm;
-
- clip.copyToMask(&mask);
- SkAutoMaskFreeImage amfi(mask.fImage);
-
- bm.installMaskPixels(mask);
-
- SkPaint paint;
- canvas->drawBitmap(bm,
- SK_Scalar1 * mask.fBounds.fLeft,
- SK_Scalar1 * mask.fBounds.fTop,
- &paint);
-}
-
-class AAClipView : public Sample {
- SkString name() override { return SkString("AAClip"); }
-
- void onOnceBeforeDraw() override { testop(); }
-
- void onDrawContent(SkCanvas* canvas) override {
-#if 1
- SkAAClip aaclip;
- SkPath path;
- SkRect bounds;
-
- bounds.setLTRB(0, 0, 20, 20);
- bounds.inset(SK_ScalarHalf, SK_ScalarHalf);
-
-// path.addRect(bounds);
-// path.addOval(bounds);
- path.addRoundRect(bounds, 4, 4);
- aaclip.setPath(path);
- canvas->translate(30, 30);
- drawClip(canvas, aaclip);
-
- SkAAClip aaclip2;
- path.offset(10, 10);
- aaclip2.setPath(path);
- canvas->translate(30, 0);
- drawClip(canvas, aaclip2);
-
- SkAAClip aaclip3;
- aaclip3.op(aaclip, aaclip2, SkRegion::kIntersect_Op);
- canvas->translate(30, 0);
- drawClip(canvas, aaclip3);
-
-#endif
-
-#if 0
- SkRect r;
- r.set(0, 0, this->width(), this->height());
- r.inset(20, 20);
- canvas->clipRect(r);
-
- SkPath path;
- path.addRect(r);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SK_ColorRED);
- canvas->drawPath(path, paint);
-#endif
- }
-};
-DEF_SAMPLE( return new AAClipView(); )
diff --git a/third_party/skia/samplecode/SampleAAGeometry.cpp b/third_party/skia/samplecode/SampleAAGeometry.cpp
deleted file mode 100644
index b2aa97d..0000000
--- a/third_party/skia/samplecode/SampleAAGeometry.cpp
+++ /dev/null
@@ -1,1847 +0,0 @@
-/*
- * Copyright 2015 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/SkBitmap.h"
-#include "include/core/SkCanvas.h"
-#include "include/core/SkString.h"
-#include "include/private/SkMacros.h"
-#include "include/utils/SkTextUtils.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkGeometry.h"
-#include "src/core/SkPointPriv.h"
-#include "src/pathops/SkIntersections.h"
-#include "src/pathops/SkOpEdgeBuilder.h"
-
-#if 0
-void SkStrokeSegment::dump() const {
- SkDebugf("{{{%1.9g,%1.9g}, {%1.9g,%1.9g}", fPts[0].fX, fPts[0].fY, fPts[1].fX, fPts[1].fY);
- if (SkPath::kQuad_Verb == fVerb) {
- SkDebugf(", {%1.9g,%1.9g}", fPts[2].fX, fPts[2].fY);
- }
- SkDebugf("}}");
-#ifdef SK_DEBUG
- SkDebugf(" id=%d", fDebugID);
-#endif
- SkDebugf("\n");
-}
-
-void SkStrokeSegment::dumpAll() const {
- const SkStrokeSegment* segment = this;
- while (segment) {
- segment->dump();
- segment = segment->fNext;
- }
-}
-
-void SkStrokeTriple::dump() const {
- SkDebugf("{{{%1.9g,%1.9g}, {%1.9g,%1.9g}", fPts[0].fX, fPts[0].fY, fPts[1].fX, fPts[1].fY);
- if (SkPath::kQuad_Verb <= fVerb) {
- SkDebugf(", {%1.9g,%1.9g}", fPts[2].fX, fPts[2].fY);
- }
- if (SkPath::kCubic_Verb == fVerb) {
- SkDebugf(", {%1.9g,%1.9g}", fPts[3].fX, fPts[3].fY);
- } else if (SkPath::kConic_Verb == fVerb) {
- SkDebugf(", %1.9g", weight());
- }
- SkDebugf("}}");
-#ifdef SK_DEBUG
- SkDebugf(" triple id=%d", fDebugID);
-#endif
- SkDebugf("\ninner:\n");
- fInner->dumpAll();
- SkDebugf("outer:\n");
- fOuter->dumpAll();
- SkDebugf("join:\n");
- fJoin->dumpAll();
-}
-
-void SkStrokeTriple::dumpAll() const {
- const SkStrokeTriple* triple = this;
- while (triple) {
- triple->dump();
- triple = triple->fNext;
- }
-}
-
-void SkStrokeContour::dump() const {
-#ifdef SK_DEBUG
- SkDebugf("id=%d ", fDebugID);
-#endif
- SkDebugf("head:\n");
- fHead->dumpAll();
- SkDebugf("head cap:\n");
- fHeadCap->dumpAll();
- SkDebugf("tail cap:\n");
- fTailCap->dumpAll();
-}
-
-void SkStrokeContour::dumpAll() const {
- const SkStrokeContour* contour = this;
- while (contour) {
- contour->dump();
- contour = contour->fNext;
- }
-}
-#endif
-
-SkScalar gCurveDistance = 10;
-
-#if 0 // unused
-static SkPath::Verb get_path_verb(int index, const SkPath& path) {
- if (index < 0) {
- return SkPath::kMove_Verb;
- }
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::Iter iter(path, true);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- if (++counter < index) {
- continue;
- }
- return verb;
- }
- SkASSERT(0);
- return SkPath::kMove_Verb;
-}
-#endif
-
-static SkScalar get_path_weight(int index, const SkPath& path) {
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::Iter iter(path, true);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- if (++counter < index) {
- continue;
- }
- return verb == SkPath::kConic_Verb ? iter.conicWeight() : 1;
- }
- SkASSERT(0);
- return 0;
-}
-
-static void set_path_pt(int index, const SkPoint& pt, SkPath* path) {
- SkPath result;
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::RawIter iter(*path);
- int startIndex = 0;
- int endIndex = 0;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- switch (verb) {
- case SkPath::kMove_Verb:
- endIndex += 1;
- break;
- case SkPath::kLine_Verb:
- endIndex += 1;
- break;
- case SkPath::kQuad_Verb:
- case SkPath::kConic_Verb:
- endIndex += 2;
- break;
- case SkPath::kCubic_Verb:
- endIndex += 3;
- break;
- case SkPath::kClose_Verb:
- break;
- case SkPath::kDone_Verb:
- break;
- default:
- SkASSERT(0);
- }
- if (startIndex <= index && index < endIndex) {
- pts[index - startIndex] = pt;
- index = -1;
- }
- switch (verb) {
- case SkPath::kMove_Verb:
- result.moveTo(pts[0]);
- break;
- case SkPath::kLine_Verb:
- result.lineTo(pts[1]);
- startIndex += 1;
- break;
- case SkPath::kQuad_Verb:
- result.quadTo(pts[1], pts[2]);
- startIndex += 2;
- break;
- case SkPath::kConic_Verb:
- result.conicTo(pts[1], pts[2], iter.conicWeight());
- startIndex += 2;
- break;
- case SkPath::kCubic_Verb:
- result.cubicTo(pts[1], pts[2], pts[3]);
- startIndex += 3;
- break;
- case SkPath::kClose_Verb:
- result.close();
- startIndex += 1;
- break;
- case SkPath::kDone_Verb:
- break;
- default:
- SkASSERT(0);
- }
- }
-#if 0
- SkDebugf("\n\noriginal\n");
- path->dump();
- SkDebugf("\nedited\n");
- result.dump();
-#endif
- *path = result;
-}
-
-static void add_path_segment(int index, SkPath* path) {
- SkPath result;
- SkPoint pts[4];
- SkPoint firstPt = { 0, 0 }; // init to avoid warning
- SkPoint lastPt = { 0, 0 }; // init to avoid warning
- SkPath::Verb verb;
- SkPath::RawIter iter(*path);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- SkScalar weight SK_INIT_TO_AVOID_WARNING;
- if (++counter == index) {
- switch (verb) {
- case SkPath::kLine_Verb:
- result.lineTo((pts[0].fX + pts[1].fX) / 2, (pts[0].fY + pts[1].fY) / 2);
- break;
- case SkPath::kQuad_Verb: {
- SkPoint chop[5];
- SkChopQuadAtHalf(pts, chop);
- result.quadTo(chop[1], chop[2]);
- pts[1] = chop[3];
- } break;
- case SkPath::kConic_Verb: {
- SkConic chop[2];
- SkConic conic;
- conic.set(pts, iter.conicWeight());
- if (!conic.chopAt(0.5f, chop)) {
- return;
- }
- result.conicTo(chop[0].fPts[1], chop[0].fPts[2], chop[0].fW);
- pts[1] = chop[1].fPts[1];
- weight = chop[1].fW;
- } break;
- case SkPath::kCubic_Verb: {
- SkPoint chop[7];
- SkChopCubicAtHalf(pts, chop);
- result.cubicTo(chop[1], chop[2], chop[3]);
- pts[1] = chop[4];
- pts[2] = chop[5];
- } break;
- case SkPath::kClose_Verb: {
- result.lineTo((lastPt.fX + firstPt.fX) / 2, (lastPt.fY + firstPt.fY) / 2);
- } break;
- default:
- SkASSERT(0);
- }
- } else if (verb == SkPath::kConic_Verb) {
- weight = iter.conicWeight();
- }
- switch (verb) {
- case SkPath::kMove_Verb:
- result.moveTo(firstPt = pts[0]);
- break;
- case SkPath::kLine_Verb:
- result.lineTo(lastPt = pts[1]);
- break;
- case SkPath::kQuad_Verb:
- result.quadTo(pts[1], lastPt = pts[2]);
- break;
- case SkPath::kConic_Verb:
- result.conicTo(pts[1], lastPt = pts[2], weight);
- break;
- case SkPath::kCubic_Verb:
- result.cubicTo(pts[1], pts[2], lastPt = pts[3]);
- break;
- case SkPath::kClose_Verb:
- result.close();
- break;
- case SkPath::kDone_Verb:
- break;
- default:
- SkASSERT(0);
- }
- }
- *path = result;
-}
-
-static void delete_path_segment(int index, SkPath* path) {
- SkPath result;
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::RawIter iter(*path);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- if (++counter == index) {
- continue;
- }
- switch (verb) {
- case SkPath::kMove_Verb:
- result.moveTo(pts[0]);
- break;
- case SkPath::kLine_Verb:
- result.lineTo(pts[1]);
- break;
- case SkPath::kQuad_Verb:
- result.quadTo(pts[1], pts[2]);
- break;
- case SkPath::kConic_Verb:
- result.conicTo(pts[1], pts[2], iter.conicWeight());
- break;
- case SkPath::kCubic_Verb:
- result.cubicTo(pts[1], pts[2], pts[3]);
- break;
- case SkPath::kClose_Verb:
- result.close();
- break;
- case SkPath::kDone_Verb:
- break;
- default:
- SkASSERT(0);
- }
- }
- *path = result;
-}
-
-static void set_path_weight(int index, SkScalar w, SkPath* path) {
- SkPath result;
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::Iter iter(*path, true);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- ++counter;
- switch (verb) {
- case SkPath::kMove_Verb:
- result.moveTo(pts[0]);
- break;
- case SkPath::kLine_Verb:
- result.lineTo(pts[1]);
- break;
- case SkPath::kQuad_Verb:
- result.quadTo(pts[1], pts[2]);
- break;
- case SkPath::kConic_Verb:
- result.conicTo(pts[1], pts[2], counter == index ? w : iter.conicWeight());
- break;
- case SkPath::kCubic_Verb:
- result.cubicTo(pts[1], pts[2], pts[3]);
- break;
- case SkPath::kClose_Verb:
- result.close();
- break;
- case SkPath::kDone_Verb:
- break;
- default:
- SkASSERT(0);
- }
- }
- *path = result;
-}
-
-static void set_path_verb(int index, SkPath::Verb v, SkPath* path, SkScalar w) {
- SkASSERT(SkPath::kLine_Verb <= v && v <= SkPath::kCubic_Verb);
- SkPath result;
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::Iter iter(*path, true);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- SkScalar weight = verb == SkPath::kConic_Verb ? iter.conicWeight() : 1;
- if (++counter == index && v != verb) {
- SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb);
- switch (verb) {
- case SkPath::kLine_Verb:
- switch (v) {
- case SkPath::kConic_Verb:
- weight = w;
- case SkPath::kQuad_Verb:
- pts[2] = pts[1];
- pts[1].fX = (pts[0].fX + pts[2].fX) / 2;
- pts[1].fY = (pts[0].fY + pts[2].fY) / 2;
- break;
- case SkPath::kCubic_Verb:
- pts[3] = pts[1];
- pts[1].fX = (pts[0].fX * 2 + pts[3].fX) / 3;
- pts[1].fY = (pts[0].fY * 2 + pts[3].fY) / 3;
- pts[2].fX = (pts[0].fX + pts[3].fX * 2) / 3;
- pts[2].fY = (pts[0].fY + pts[3].fY * 2) / 3;
- break;
- default:
- SkASSERT(0);
- break;
- }
- break;
- case SkPath::kQuad_Verb:
- case SkPath::kConic_Verb:
- switch (v) {
- case SkPath::kLine_Verb:
- pts[1] = pts[2];
- break;
- case SkPath::kConic_Verb:
- weight = w;
- case SkPath::kQuad_Verb:
- break;
- case SkPath::kCubic_Verb: {
- SkDQuad dQuad;
- dQuad.set(pts);
- SkDCubic dCubic = dQuad.debugToCubic();
- pts[3] = pts[2];
- pts[1] = dCubic[1].asSkPoint();
- pts[2] = dCubic[2].asSkPoint();
- } break;
- default:
- SkASSERT(0);
- break;
- }
- break;
- case SkPath::kCubic_Verb:
- switch (v) {
- case SkPath::kLine_Verb:
- pts[1] = pts[3];
- break;
- case SkPath::kConic_Verb:
- weight = w;
- case SkPath::kQuad_Verb: {
- SkDCubic dCubic;
- dCubic.set(pts);
- SkDQuad dQuad = dCubic.toQuad();
- pts[1] = dQuad[1].asSkPoint();
- pts[2] = pts[3];
- } break;
- default:
- SkASSERT(0);
- break;
- }
- break;
- default:
- SkASSERT(0);
- break;
- }
- verb = v;
- }
- switch (verb) {
- case SkPath::kMove_Verb:
- result.moveTo(pts[0]);
- break;
- case SkPath::kLine_Verb:
- result.lineTo(pts[1]);
- break;
- case SkPath::kQuad_Verb:
- result.quadTo(pts[1], pts[2]);
- break;
- case SkPath::kConic_Verb:
- result.conicTo(pts[1], pts[2], weight);
- break;
- case SkPath::kCubic_Verb:
- result.cubicTo(pts[1], pts[2], pts[3]);
- break;
- case SkPath::kClose_Verb:
- result.close();
- break;
- default:
- SkASSERT(0);
- break;
- }
- }
- *path = result;
-}
-
-static void add_to_map(SkScalar coverage, int x, int y, uint8_t* distanceMap, int w, int h) {
- int byteCoverage = (int) (coverage * 256);
- if (byteCoverage < 0) {
- byteCoverage = 0;
- } else if (byteCoverage > 255) {
- byteCoverage = 255;
- }
- SkASSERT(x < w);
- SkASSERT(y < h);
- distanceMap[y * w + x] = SkTMax(distanceMap[y * w + x], (uint8_t) byteCoverage);
-}
-
-static void filter_coverage(const uint8_t* map, int len, uint8_t min, uint8_t max,
- uint8_t* filter) {
- for (int index = 0; index < len; ++index) {
- uint8_t in = map[index];
- filter[index] = in < min ? 0 : max < in ? 0 : in;
- }
-}
-
-static void construct_path(SkPath& path) {
- path.reset();
- path.moveTo(442, 101.5f);
- path.quadTo(413.5f, 691, 772, 514);
- path.lineTo(346, 721.5f);
- path.lineTo(154, 209);
- path.lineTo(442, 101.5f);
- path.close();
-}
-
-struct ButtonPaints {
- static const int kMaxStateCount = 3;
- SkPaint fDisabled;
- SkPaint fStates[kMaxStateCount];
- SkFont fLabelFont;
-
- ButtonPaints() {
- fStates[0].setAntiAlias(true);
- fStates[0].setStyle(SkPaint::kStroke_Style);
- fStates[0].setColor(0xFF3F0000);
- fStates[1] = fStates[0];
- fStates[1].setStrokeWidth(3);
- fStates[2] = fStates[1];
- fStates[2].setColor(0xFFcf0000);
- fLabelFont.setSize(25.0f);
- }
-};
-
-struct Button {
- SkRect fBounds;
- int fStateCount;
- int fState;
- char fLabel;
- bool fVisible;
-
- Button(char label) {
- fStateCount = 2;
- fState = 0;
- fLabel = label;
- fVisible = false;
- }
-
- Button(char label, int stateCount) {
- SkASSERT(stateCount <= ButtonPaints::kMaxStateCount);
- fStateCount = stateCount;
- fState = 0;
- fLabel = label;
- fVisible = false;
- }
-
- bool contains(const SkRect& rect) {
- return fVisible && fBounds.contains(rect);
- }
-
- bool enabled() {
- return SkToBool(fState);
- }
-
- void draw(SkCanvas* canvas, const ButtonPaints& paints) {
- if (!fVisible) {
- return;
- }
- canvas->drawRect(fBounds, paints.fStates[fState]);
- SkTextUtils::Draw(canvas, &fLabel, 1, SkTextEncoding::kUTF8, fBounds.centerX(), fBounds.fBottom - 5,
- paints.fLabelFont, SkPaint(), SkTextUtils::kCenter_Align);
- }
-
- void toggle() {
- if (++fState == fStateCount) {
- fState = 0;
- }
- }
-
- void setEnabled(bool enabled) {
- fState = (int) enabled;
- }
-};
-
-struct ControlPaints {
- SkPaint fOutline;
- SkPaint fIndicator;
- SkPaint fFill;
- SkPaint fLabel;
- SkPaint fValue;
-
- SkFont fLabelFont;
- SkFont fValueFont;
-
- ControlPaints() {
- fOutline.setAntiAlias(true);
- fOutline.setStyle(SkPaint::kStroke_Style);
- fIndicator = fOutline;
- fIndicator.setColor(SK_ColorRED);
- fFill.setAntiAlias(true);
- fFill.setColor(0x7fff0000);
- fLabel.setAntiAlias(true);
- fLabelFont.setSize(13.0f);
- fValue.setAntiAlias(true);
- fValueFont.setSize(11.0f);
- }
-};
-
-struct UniControl {
- SkString fName;
- SkRect fBounds;
- SkScalar fMin;
- SkScalar fMax;
- SkScalar fValLo;
- SkScalar fYLo;
- bool fVisible;
-
- UniControl(const char* name, SkScalar min, SkScalar max) {
- fName = name;
- fValLo = fMin = min;
- fMax = max;
- fVisible = false;
-
- }
-
- virtual ~UniControl() {}
-
- bool contains(const SkRect& rect) {
- return fVisible && fBounds.contains(rect);
- }
-
- virtual void draw(SkCanvas* canvas, const ControlPaints& paints) {
- if (!fVisible) {
- return;
- }
- canvas->drawRect(fBounds, paints.fOutline);
- fYLo = fBounds.fTop + (fValLo - fMin) * fBounds.height() / (fMax - fMin);
- canvas->drawLine(fBounds.fLeft - 5, fYLo, fBounds.fRight + 5, fYLo, paints.fIndicator);
- SkString label;
- label.printf("%0.3g", fValLo);
- canvas->drawString(label, fBounds.fLeft + 5, fYLo - 5, paints.fValueFont, paints.fValue);
- canvas->drawString(fName, fBounds.fLeft, fBounds.bottom() + 11, paints.fLabelFont,
- paints.fLabel);
- }
-};
-
-struct BiControl : public UniControl {
- SkScalar fValHi;
-
- BiControl(const char* name, SkScalar min, SkScalar max)
- : UniControl(name, min, max)
- , fValHi(fMax) {
- }
-
- virtual ~BiControl() {}
-
- virtual void draw(SkCanvas* canvas, const ControlPaints& paints) {
- UniControl::draw(canvas, paints);
- if (!fVisible || fValHi == fValLo) {
- return;
- }
- SkScalar yPos = fBounds.fTop + (fValHi - fMin) * fBounds.height() / (fMax - fMin);
- canvas->drawLine(fBounds.fLeft - 5, yPos, fBounds.fRight + 5, yPos, paints.fIndicator);
- SkString label;
- label.printf("%0.3g", fValHi);
- if (yPos < fYLo + 10) {
- yPos = fYLo + 10;
- }
- canvas->drawString(label, fBounds.fLeft + 5, yPos - 5, paints.fValueFont, paints.fValue);
- SkRect fill = { fBounds.fLeft, fYLo, fBounds.fRight, yPos };
- canvas->drawRect(fill, paints.fFill);
- }
-};
-
-
-class MyClick : public Sample::Click {
-public:
- enum ClickType {
- kInvalidType = -1,
- kPtType,
- kVerbType,
- kControlType,
- kPathType,
- } fType;
-
- enum ControlType {
- kInvalidControl = -1,
- kFirstControl,
- kFilterControl = kFirstControl,
- kResControl,
- kWeightControl,
- kWidthControl,
- kLastControl = kWidthControl,
- kFirstButton,
- kCubicButton = kFirstButton,
- kConicButton,
- kQuadButton,
- kLineButton,
- kLastVerbButton = kLineButton,
- kAddButton,
- kDeleteButton,
- kInOutButton,
- kFillButton,
- kSkeletonButton,
- kFilterButton,
- kBisectButton,
- kJoinButton,
- kLastButton = kJoinButton,
- kPathMove,
- } fControl;
-
- SkPath::Verb fVerb;
- SkScalar fWeight;
-
- MyClick(ClickType type, ControlType control)
- : fType(type)
- , fControl(control)
- , fVerb((SkPath::Verb) -1)
- , fWeight(1) {
- }
-
- MyClick(ClickType type, int index)
- : fType(type)
- , fControl((ControlType) index)
- , fVerb((SkPath::Verb) -1)
- , fWeight(1) {
- }
-
- MyClick(ClickType type, int index, SkPath::Verb verb, SkScalar weight)
- : fType(type)
- , fControl((ControlType) index)
- , fVerb(verb)
- , fWeight(weight) {
- }
-
- bool isButton() {
- return kFirstButton <= fControl && fControl <= kLastButton;
- }
-
- int ptHit() const {
- SkASSERT(fType == kPtType);
- return (int) fControl;
- }
-
- int verbHit() const {
- SkASSERT(fType == kVerbType);
- return (int) fControl;
- }
-};
-
-enum {
- kControlCount = MyClick::kLastControl - MyClick::kFirstControl + 1,
-};
-
-static struct ControlPair {
- UniControl* fControl;
- MyClick::ControlType fControlType;
-} kControlList[kControlCount];
-
-enum {
- kButtonCount = MyClick::kLastButton - MyClick::kFirstButton + 1,
- kVerbCount = MyClick::kLastVerbButton - MyClick::kFirstButton + 1,
-};
-
-static struct ButtonPair {
- Button* fButton;
- MyClick::ControlType fButtonType;
-} kButtonList[kButtonCount];
-
-static void enable_verb_button(MyClick::ControlType type) {
- for (int index = 0; index < kButtonCount; ++index) {
- MyClick::ControlType testType = kButtonList[index].fButtonType;
- if (MyClick::kFirstButton <= testType && testType <= MyClick::kLastVerbButton) {
- Button* button = kButtonList[index].fButton;
- button->setEnabled(testType == type);
- }
- }
-}
-
-struct Stroke;
-
-struct Active {
- Active* fNext;
- Stroke* fParent;
- SkScalar fStart;
- SkScalar fEnd;
-
- void reset() {
- fNext = nullptr;
- fStart = 0;
- fEnd = 1;
- }
-};
-
-struct Stroke {
- SkPath fPath;
- Active fActive;
- bool fInner;
-
- void reset() {
- fPath.reset();
- fActive.reset();
- }
-};
-
-struct PathUndo {
- SkPath fPath;
- std::unique_ptr<PathUndo> fNext;
-};
-
-class AAGeometryView : public Sample {
- SkPaint fActivePaint;
- SkPaint fComplexPaint;
- SkPaint fCoveragePaint;
- SkFont fLegendLeftFont;
- SkFont fLegendRightFont;
- SkPaint fPointPaint;
- SkPaint fSkeletonPaint;
- SkPaint fLightSkeletonPaint;
- SkPath fPath;
- ControlPaints fControlPaints;
- UniControl fResControl;
- UniControl fWeightControl;
- UniControl fWidthControl;
- BiControl fFilterControl;
- ButtonPaints fButtonPaints;
- Button fCubicButton;
- Button fConicButton;
- Button fQuadButton;
- Button fLineButton;
- Button fAddButton;
- Button fDeleteButton;
- Button fFillButton;
- Button fSkeletonButton;
- Button fFilterButton;
- Button fBisectButton;
- Button fJoinButton;
- Button fInOutButton;
- SkTArray<Stroke> fStrokes;
- std::unique_ptr<PathUndo> fUndo;
- int fActivePt;
- int fActiveVerb;
- bool fHandlePathMove;
- bool fShowLegend;
- bool fHideAll;
- const int kHitToleranace = 25;
-
-public:
-
- AAGeometryView()
- : fResControl("error", 0, 10)
- , fWeightControl("weight", 0, 5)
- , fWidthControl("width", FLT_EPSILON, 100)
- , fFilterControl("filter", 0, 255)
- , fCubicButton('C')
- , fConicButton('K')
- , fQuadButton('Q')
- , fLineButton('L')
- , fAddButton('+')
- , fDeleteButton('x')
- , fFillButton('p')
- , fSkeletonButton('s')
- , fFilterButton('f', 3)
- , fBisectButton('b')
- , fJoinButton('j')
- , fInOutButton('|')
- , fActivePt(-1)
- , fActiveVerb(-1)
- , fHandlePathMove(true)
- , fShowLegend(false)
- , fHideAll(false)
- {
- fCoveragePaint.setAntiAlias(true);
- fCoveragePaint.setColor(SK_ColorBLUE);
- SkPaint strokePaint;
- strokePaint.setAntiAlias(true);
- strokePaint.setStyle(SkPaint::kStroke_Style);
- fPointPaint = strokePaint;
- fPointPaint.setColor(0x99ee3300);
- fSkeletonPaint = strokePaint;
- fSkeletonPaint.setColor(SK_ColorRED);
- fLightSkeletonPaint = fSkeletonPaint;
- fLightSkeletonPaint.setColor(0xFFFF7f7f);
- fActivePaint = strokePaint;
- fActivePaint.setColor(0x99ee3300);
- fActivePaint.setStrokeWidth(5);
- fComplexPaint = fActivePaint;
- fComplexPaint.setColor(SK_ColorBLUE);
- fLegendLeftFont.setSize(13);
- fLegendRightFont = fLegendLeftFont;
- construct_path(fPath);
- fFillButton.fVisible = fSkeletonButton.fVisible = fFilterButton.fVisible
- = fBisectButton.fVisible = fJoinButton.fVisible = fInOutButton.fVisible = true;
- fSkeletonButton.setEnabled(true);
- fInOutButton.setEnabled(true);
- fJoinButton.setEnabled(true);
- fFilterControl.fValLo = 120;
- fFilterControl.fValHi = 141;
- fFilterControl.fVisible = fFilterButton.fState == 2;
- fResControl.fValLo = 5;
- fResControl.fVisible = true;
- fWidthControl.fValLo = 50;
- fWidthControl.fVisible = true;
- init_controlList();
- init_buttonList();
- }
-
- ~AAGeometryView() override {
- // Free linked list without deep recursion.
- std::unique_ptr<PathUndo> undo = std::move(fUndo);
- while (undo) {
- undo = std::move(undo->fNext);
- }
- }
-
- bool constructPath() {
- construct_path(fPath);
- return true;
- }
-
- void savePath(skui::InputState state) {
- if (state != skui::InputState::kDown) {
- return;
- }
- if (fUndo && fUndo->fPath == fPath) {
- return;
- }
- std::unique_ptr<PathUndo> undo(new PathUndo);
- undo->fPath = fPath;
- undo->fNext = std::move(fUndo);
- fUndo = std::move(undo);
- }
-
- bool undo() {
- if (!fUndo) {
- return false;
- }
- fPath = std::move(fUndo->fPath);
- fUndo = std::move(fUndo->fNext);
- validatePath();
- return true;
- }
-
- void validatePath() {}
-
- void set_controlList(int index, UniControl* control, MyClick::ControlType type) {
- kControlList[index].fControl = control;
- kControlList[index].fControlType = type;
- }
-
- #define SET_CONTROL(Name) set_controlList(index++, &f##Name##Control, \
- MyClick::k##Name##Control)
-
- bool hideAll() {
- fHideAll ^= true;
- return true;
- }
-
- void init_controlList() {
- int index = 0;
- SET_CONTROL(Width);
- SET_CONTROL(Res);
- SET_CONTROL(Filter);
- SET_CONTROL(Weight);
- }
-
- #undef SET_CONTROL
-
- void set_buttonList(int index, Button* button, MyClick::ControlType type) {
- kButtonList[index].fButton = button;
- kButtonList[index].fButtonType = type;
- }
-
- #define SET_BUTTON(Name) set_buttonList(index++, &f##Name##Button, \
- MyClick::k##Name##Button)
-
- void init_buttonList() {
- int index = 0;
- SET_BUTTON(Fill);
- SET_BUTTON(Skeleton);
- SET_BUTTON(Filter);
- SET_BUTTON(Bisect);
- SET_BUTTON(Join);
- SET_BUTTON(InOut);
- SET_BUTTON(Cubic);
- SET_BUTTON(Conic);
- SET_BUTTON(Quad);
- SET_BUTTON(Line);
- SET_BUTTON(Add);
- SET_BUTTON(Delete);
- }
-
- #undef SET_BUTTON
-
- SkString name() override { return SkString("AAGeometry"); }
-
- bool onChar(SkUnichar) override;
-
- void onSizeChange() override {
- setControlButtonsPos();
- this->INHERITED::onSizeChange();
- }
-
- bool pathDump() {
- fPath.dump();
- return true;
- }
-
- bool scaleDown() {
- SkMatrix matrix;
- SkRect bounds = fPath.getBounds();
- matrix.setScale(1.f / 1.5f, 1.f / 1.5f, bounds.centerX(), bounds.centerY());
- fPath.transform(matrix);
- validatePath();
- return true;
- }
-
- bool scaleToFit() {
- SkMatrix matrix;
- SkRect bounds = fPath.getBounds();
- SkScalar scale = SkTMin(this->width() / bounds.width(), this->height() / bounds.height())
- * 0.8f;
- matrix.setScale(scale, scale, bounds.centerX(), bounds.centerY());
- fPath.transform(matrix);
- bounds = fPath.getBounds();
- SkScalar offsetX = (this->width() - bounds.width()) / 2 - bounds.fLeft;
- SkScalar offsetY = (this->height() - bounds.height()) / 2 - bounds.fTop;
- fPath.offset(offsetX, offsetY);
- validatePath();
- return true;
- }
-
- bool scaleUp() {
- SkMatrix matrix;
- SkRect bounds = fPath.getBounds();
- matrix.setScale(1.5f, 1.5f, bounds.centerX(), bounds.centerY());
- fPath.transform(matrix);
- validatePath();
- return true;
- }
-
- void setControlButtonsPos() {
- SkScalar widthOffset = this->width() - 100;
- for (int index = 0; index < kControlCount; ++index) {
- if (kControlList[index].fControl->fVisible) {
- kControlList[index].fControl->fBounds.setXYWH(widthOffset, 30, 30, 400);
- widthOffset -= 50;
- }
- }
- SkScalar buttonOffset = 0;
- for (int index = 0; index < kButtonCount; ++index) {
- kButtonList[index].fButton->fBounds.setXYWH(this->width() - 50,
- buttonOffset += 50, 30, 30);
- }
- }
-
- bool showLegend() {
- fShowLegend ^= true;
- return true;
- }
-
- void draw_bisect(SkCanvas* canvas, const SkVector& lastVector, const SkVector& vector,
- const SkPoint& pt) {
- SkVector lastV = lastVector;
- SkScalar lastLen = lastVector.length();
- SkVector nextV = vector;
- SkScalar nextLen = vector.length();
- if (lastLen < nextLen) {
- lastV.setLength(nextLen);
- } else {
- nextV.setLength(lastLen);
- }
-
- SkVector bisect = { (lastV.fX + nextV.fX) / 2, (lastV.fY + nextV.fY) / 2 };
- bisect.setLength(fWidthControl.fValLo * 2);
- if (fBisectButton.enabled()) {
- canvas->drawLine(pt, pt + bisect, fSkeletonPaint);
- }
- lastV.setLength(fWidthControl.fValLo);
- if (fBisectButton.enabled()) {
- canvas->drawLine(pt, {pt.fX - lastV.fY, pt.fY + lastV.fX}, fSkeletonPaint);
- }
- nextV.setLength(fWidthControl.fValLo);
- if (fBisectButton.enabled()) {
- canvas->drawLine(pt, {pt.fX + nextV.fY, pt.fY - nextV.fX}, fSkeletonPaint);
- }
- if (fJoinButton.enabled()) {
- SkScalar r = fWidthControl.fValLo;
- SkRect oval = { pt.fX - r, pt.fY - r, pt.fX + r, pt.fY + r};
- SkScalar startAngle = SkScalarATan2(lastV.fX, -lastV.fY) * 180.f / SK_ScalarPI;
- SkScalar endAngle = SkScalarATan2(-nextV.fX, nextV.fY) * 180.f / SK_ScalarPI;
- if (endAngle > startAngle) {
- canvas->drawArc(oval, startAngle, endAngle - startAngle, false, fSkeletonPaint);
- } else {
- canvas->drawArc(oval, startAngle, 360 - (startAngle - endAngle), false,
- fSkeletonPaint);
- }
- }
- }
-
- void draw_bisects(SkCanvas* canvas, bool activeOnly) {
- SkVector firstVector, lastVector, nextLast, vector;
- SkPoint pts[4];
- SkPoint firstPt = { 0, 0 }; // init to avoid warning;
- SkPath::Verb verb;
- SkPath::Iter iter(fPath, true);
- bool foundFirst = false;
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- ++counter;
- if (activeOnly && counter != fActiveVerb && counter - 1 != fActiveVerb
- && counter + 1 != fActiveVerb
- && (fActiveVerb != 1 || counter != fPath.countVerbs())) {
- continue;
- }
- switch (verb) {
- case SkPath::kLine_Verb:
- nextLast = pts[0] - pts[1];
- vector = pts[1] - pts[0];
- break;
- case SkPath::kQuad_Verb: {
- nextLast = pts[1] - pts[2];
- if (SkScalarNearlyZero(nextLast.length())) {
- nextLast = pts[0] - pts[2];
- }
- vector = pts[1] - pts[0];
- if (SkScalarNearlyZero(vector.length())) {
- vector = pts[2] - pts[0];
- }
- if (!fBisectButton.enabled()) {
- break;
- }
- SkScalar t = SkFindQuadMaxCurvature(pts);
- if (0 < t && t < 1) {
- SkPoint maxPt = SkEvalQuadAt(pts, t);
- SkVector tangent = SkEvalQuadTangentAt(pts, t);
- tangent.setLength(fWidthControl.fValLo * 2);
- canvas->drawLine(maxPt, {maxPt.fX + tangent.fY, maxPt.fY - tangent.fX},
- fSkeletonPaint);
- }
- } break;
- case SkPath::kConic_Verb:
- nextLast = pts[1] - pts[2];
- if (SkScalarNearlyZero(nextLast.length())) {
- nextLast = pts[0] - pts[2];
- }
- vector = pts[1] - pts[0];
- if (SkScalarNearlyZero(vector.length())) {
- vector = pts[2] - pts[0];
- }
- if (!fBisectButton.enabled()) {
- break;
- }
- // FIXME : need max curvature or equivalent here
- break;
- case SkPath::kCubic_Verb: {
- nextLast = pts[2] - pts[3];
- if (SkScalarNearlyZero(nextLast.length())) {
- nextLast = pts[1] - pts[3];
- if (SkScalarNearlyZero(nextLast.length())) {
- nextLast = pts[0] - pts[3];
- }
- }
- vector = pts[0] - pts[1];
- if (SkScalarNearlyZero(vector.length())) {
- vector = pts[0] - pts[2];
- if (SkScalarNearlyZero(vector.length())) {
- vector = pts[0] - pts[3];
- }
- }
- if (!fBisectButton.enabled()) {
- break;
- }
- SkScalar tMax[2];
- int tMaxCount = SkFindCubicMaxCurvature(pts, tMax);
- for (int tIndex = 0; tIndex < tMaxCount; ++tIndex) {
- if (0 >= tMax[tIndex] || tMax[tIndex] >= 1) {
- continue;
- }
- SkPoint maxPt;
- SkVector tangent;
- SkEvalCubicAt(pts, tMax[tIndex], &maxPt, &tangent, nullptr);
- tangent.setLength(fWidthControl.fValLo * 2);
- canvas->drawLine(maxPt, {maxPt.fX + tangent.fY, maxPt.fY - tangent.fX},
- fSkeletonPaint);
- }
- } break;
- case SkPath::kClose_Verb:
- if (foundFirst) {
- draw_bisect(canvas, lastVector, firstVector, firstPt);
- foundFirst = false;
- }
- break;
- default:
- break;
- }
- if (SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb) {
- if (!foundFirst) {
- firstPt = pts[0];
- firstVector = vector;
- foundFirst = true;
- } else {
- draw_bisect(canvas, lastVector, vector, pts[0]);
- }
- lastVector = nextLast;
- }
- }
- }
-
- void draw_legend(SkCanvas* canvas);
-
- void draw_segment(SkCanvas* canvas) {
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::Iter iter(fPath, true);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- if (++counter < fActiveVerb) {
- continue;
- }
- switch (verb) {
- case SkPath::kLine_Verb:
- canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, fActivePaint);
- draw_points(canvas, pts, 2);
- break;
- case SkPath::kQuad_Verb: {
- SkPath qPath;
- qPath.moveTo(pts[0]);
- qPath.quadTo(pts[1], pts[2]);
- canvas->drawPath(qPath, fActivePaint);
- draw_points(canvas, pts, 3);
- } break;
- case SkPath::kConic_Verb: {
- SkPath conicPath;
- conicPath.moveTo(pts[0]);
- conicPath.conicTo(pts[1], pts[2], iter.conicWeight());
- canvas->drawPath(conicPath, fActivePaint);
- draw_points(canvas, pts, 3);
- } break;
- case SkPath::kCubic_Verb: {
- SkScalar loopT[3];
- int complex = SkDCubic::ComplexBreak(pts, loopT);
- SkPath cPath;
- cPath.moveTo(pts[0]);
- cPath.cubicTo(pts[1], pts[2], pts[3]);
- canvas->drawPath(cPath, complex ? fComplexPaint : fActivePaint);
- draw_points(canvas, pts, 4);
- } break;
- default:
- break;
- }
- return;
- }
- }
-
- void draw_points(SkCanvas* canvas, SkPoint* points, int count) {
- for (int index = 0; index < count; ++index) {
- canvas->drawCircle(points[index].fX, points[index].fY, 10, fPointPaint);
- }
- }
-
- int hittest_verb(SkPoint pt, SkPath::Verb* verbPtr, SkScalar* weight) {
- SkIntersections i;
- SkDLine hHit = {{{pt.fX - kHitToleranace, pt.fY }, {pt.fX + kHitToleranace, pt.fY}}};
- SkDLine vHit = {{{pt.fX, pt.fY - kHitToleranace }, {pt.fX, pt.fY + kHitToleranace}}};
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::Iter iter(fPath, true);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- ++counter;
- switch (verb) {
- case SkPath::kLine_Verb: {
- SkDLine line;
- line.set(pts);
- if (i.intersect(line, hHit) || i.intersect(line, vHit)) {
- *verbPtr = verb;
- *weight = 1;
- return counter;
- }
- } break;
- case SkPath::kQuad_Verb: {
- SkDQuad quad;
- quad.set(pts);
- if (i.intersect(quad, hHit) || i.intersect(quad, vHit)) {
- *verbPtr = verb;
- *weight = 1;
- return counter;
- }
- } break;
- case SkPath::kConic_Verb: {
- SkDConic conic;
- SkScalar w = iter.conicWeight();
- conic.set(pts, w);
- if (i.intersect(conic, hHit) || i.intersect(conic, vHit)) {
- *verbPtr = verb;
- *weight = w;
- return counter;
- }
- } break;
- case SkPath::kCubic_Verb: {
- SkDCubic cubic;
- cubic.set(pts);
- if (i.intersect(cubic, hHit) || i.intersect(cubic, vHit)) {
- *verbPtr = verb;
- *weight = 1;
- return counter;
- }
- } break;
- default:
- break;
- }
- }
- return -1;
- }
-
- SkScalar pt_to_line(SkPoint s, SkPoint e, int x, int y) {
- SkScalar radius = fWidthControl.fValLo;
- SkVector adjOpp = e - s;
- SkScalar lenSq = SkPointPriv::LengthSqd(adjOpp);
- SkPoint rotated = {
- (y - s.fY) * adjOpp.fY + (x - s.fX) * adjOpp.fX,
- (y - s.fY) * adjOpp.fX - (x - s.fX) * adjOpp.fY,
- };
- if (rotated.fX < 0 || rotated.fX > lenSq) {
- return -radius;
- }
- rotated.fY /= SkScalarSqrt(lenSq);
- return SkTMax(-radius, SkTMin(radius, rotated.fY));
- }
-
- // given a line, compute the interior and exterior gradient coverage
- bool coverage(SkPoint s, SkPoint e, uint8_t* distanceMap, int w, int h) {
- SkScalar radius = fWidthControl.fValLo;
- int minX = SkTMax(0, (int) (SkTMin(s.fX, e.fX) - radius));
- int minY = SkTMax(0, (int) (SkTMin(s.fY, e.fY) - radius));
- int maxX = SkTMin(w, (int) (SkTMax(s.fX, e.fX) + radius) + 1);
- int maxY = SkTMin(h, (int) (SkTMax(s.fY, e.fY) + radius) + 1);
- for (int y = minY; y < maxY; ++y) {
- for (int x = minX; x < maxX; ++x) {
- SkScalar ptToLineDist = pt_to_line(s, e, x, y);
- if (ptToLineDist > -radius && ptToLineDist < radius) {
- SkScalar coverage = ptToLineDist / radius;
- add_to_map(1 - SkScalarAbs(coverage), x, y, distanceMap, w, h);
- }
- SkVector ptToS = { x - s.fX, y - s.fY };
- SkScalar dist = ptToS.length();
- if (dist < radius) {
- SkScalar coverage = dist / radius;
- add_to_map(1 - SkScalarAbs(coverage), x, y, distanceMap, w, h);
- }
- SkVector ptToE = { x - e.fX, y - e.fY };
- dist = ptToE.length();
- if (dist < radius) {
- SkScalar coverage = dist / radius;
- add_to_map(1 - SkScalarAbs(coverage), x, y, distanceMap, w, h);
- }
- }
- }
- return true;
- }
-
- void quad_coverage(SkPoint pts[3], uint8_t* distanceMap, int w, int h) {
- SkScalar dist = pts[0].Distance(pts[0], pts[2]);
- if (dist < gCurveDistance) {
- (void) coverage(pts[0], pts[2], distanceMap, w, h);
- return;
- }
- SkPoint split[5];
- SkChopQuadAt(pts, split, 0.5f);
- quad_coverage(&split[0], distanceMap, w, h);
- quad_coverage(&split[2], distanceMap, w, h);
- }
-
- void conic_coverage(SkPoint pts[3], SkScalar weight, uint8_t* distanceMap, int w, int h) {
- SkScalar dist = pts[0].Distance(pts[0], pts[2]);
- if (dist < gCurveDistance) {
- (void) coverage(pts[0], pts[2], distanceMap, w, h);
- return;
- }
- SkConic split[2];
- SkConic conic;
- conic.set(pts, weight);
- if (conic.chopAt(0.5f, split)) {
- conic_coverage(split[0].fPts, split[0].fW, distanceMap, w, h);
- conic_coverage(split[1].fPts, split[1].fW, distanceMap, w, h);
- }
- }
-
- void cubic_coverage(SkPoint pts[4], uint8_t* distanceMap, int w, int h) {
- SkScalar dist = pts[0].Distance(pts[0], pts[3]);
- if (dist < gCurveDistance) {
- (void) coverage(pts[0], pts[3], distanceMap, w, h);
- return;
- }
- SkPoint split[7];
- SkChopCubicAt(pts, split, 0.5f);
- cubic_coverage(&split[0], distanceMap, w, h);
- cubic_coverage(&split[3], distanceMap, w, h);
- }
-
- void path_coverage(const SkPath& path, uint8_t* distanceMap, int w, int h) {
- memset(distanceMap, 0, sizeof(distanceMap[0]) * w * h);
- SkPoint pts[4];
- SkPath::Verb verb;
- SkPath::Iter iter(path, true);
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- switch (verb) {
- case SkPath::kLine_Verb:
- (void) coverage(pts[0], pts[1], distanceMap, w, h);
- break;
- case SkPath::kQuad_Verb:
- quad_coverage(pts, distanceMap, w, h);
- break;
- case SkPath::kConic_Verb:
- conic_coverage(pts, iter.conicWeight(), distanceMap, w, h);
- break;
- case SkPath::kCubic_Verb:
- cubic_coverage(pts, distanceMap, w, h);
- break;
- default:
- break;
- }
- }
- }
-
- static uint8_t* set_up_dist_map(const SkImageInfo& imageInfo, SkBitmap* distMap) {
- distMap->setInfo(imageInfo);
- distMap->setIsVolatile(true);
- SkAssertResult(distMap->tryAllocPixels());
- SkASSERT((int) distMap->rowBytes() == imageInfo.width());
- return distMap->getAddr8(0, 0);
- }
-
- void path_stroke(int index, SkPath* inner, SkPath* outer) {
- #if 0
- SkPathStroker stroker(fPath, fWidthControl.fValLo, 0,
- SkPaint::kRound_Cap, SkPaint::kRound_Join, fResControl.fValLo);
- SkPoint pts[4], firstPt, lastPt;
- SkPath::Verb verb;
- SkPath::Iter iter(fPath, true);
- int counter = -1;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- ++counter;
- switch (verb) {
- case SkPath::kMove_Verb:
- firstPt = pts[0];
- break;
- case SkPath::kLine_Verb:
- if (counter == index) {
- stroker.moveTo(pts[0]);
- stroker.lineTo(pts[1]);
- goto done;
- }
- lastPt = pts[1];
- break;
- case SkPath::kQuad_Verb:
- if (counter == index) {
- stroker.moveTo(pts[0]);
- stroker.quadTo(pts[1], pts[2]);
- goto done;
- }
- lastPt = pts[2];
- break;
- case SkPath::kConic_Verb:
- if (counter == index) {
- stroker.moveTo(pts[0]);
- stroker.conicTo(pts[1], pts[2], iter.conicWeight());
- goto done;
- }
- lastPt = pts[2];
- break;
- case SkPath::kCubic_Verb:
- if (counter == index) {
- stroker.moveTo(pts[0]);
- stroker.cubicTo(pts[1], pts[2], pts[3]);
- goto done;
- }
- lastPt = pts[3];
- break;
- case SkPath::kClose_Verb:
- if (counter == index) {
- stroker.moveTo(lastPt);
- stroker.lineTo(firstPt);
- goto done;
- }
- break;
- case SkPath::kDone_Verb:
- break;
- default:
- SkASSERT(0);
- }
- }
- done:
- *inner = stroker.fInner;
- *outer = stroker.fOuter;
-#endif
- }
-
- void draw_stroke(SkCanvas* canvas, int active) {
- SkPath inner, outer;
- path_stroke(active, &inner, &outer);
- canvas->drawPath(inner, fSkeletonPaint);
- canvas->drawPath(outer, fSkeletonPaint);
- }
-
- void gather_strokes() {
- fStrokes.reset();
- for (int index = 0; index < fPath.countVerbs(); ++index) {
- Stroke& inner = fStrokes.push_back();
- inner.reset();
- inner.fInner = true;
- Stroke& outer = fStrokes.push_back();
- outer.reset();
- outer.fInner = false;
- path_stroke(index, &inner.fPath, &outer.fPath);
- }
- }
-
- void trim_strokes() {
- // eliminate self-itersecting loops
- // trim outside edges
- gather_strokes();
- for (int index = 0; index < fStrokes.count(); ++index) {
- SkPath& outPath = fStrokes[index].fPath;
- for (int inner = 0; inner < fStrokes.count(); ++inner) {
- if (index == inner) {
- continue;
- }
- SkPath& inPath = fStrokes[inner].fPath;
- if (!outPath.getBounds().intersects(inPath.getBounds())) {
- continue;
- }
-
- }
- }
- }
-
- void onDrawContent(SkCanvas* canvas) override {
-#if 0
- SkDEBUGCODE(SkDebugStrokeGlobals debugGlobals);
- SkOpAA aaResult(fPath, fWidthControl.fValLo, fResControl.fValLo
- SkDEBUGPARAMS(&debugGlobals));
-#endif
- SkPath strokePath;
-// aaResult.simplify(&strokePath);
- canvas->drawPath(strokePath, fSkeletonPaint);
- SkRect bounds = fPath.getBounds();
- SkScalar radius = fWidthControl.fValLo;
- int w = (int) (bounds.fRight + radius + 1);
- int h = (int) (bounds.fBottom + radius + 1);
- SkImageInfo imageInfo = SkImageInfo::MakeA8(w, h);
- SkBitmap distMap;
- uint8_t* distanceMap = set_up_dist_map(imageInfo, &distMap);
- path_coverage(fPath, distanceMap, w, h);
- if (fFillButton.enabled()) {
- canvas->drawPath(fPath, fCoveragePaint);
- }
- if (fFilterButton.fState == 2
- && (0 < fFilterControl.fValLo || fFilterControl.fValHi < 255)) {
- SkBitmap filteredMap;
- uint8_t* filtered = set_up_dist_map(imageInfo, &filteredMap);
- filter_coverage(distanceMap, sizeof(uint8_t) * w * h, (uint8_t) fFilterControl.fValLo,
- (uint8_t) fFilterControl.fValHi, filtered);
- canvas->drawBitmap(filteredMap, 0, 0, &fCoveragePaint);
- } else if (fFilterButton.enabled()) {
- canvas->drawBitmap(distMap, 0, 0, &fCoveragePaint);
- }
- if (fSkeletonButton.enabled()) {
- canvas->drawPath(fPath, fActiveVerb >= 0 ? fLightSkeletonPaint : fSkeletonPaint);
- }
- if (fActiveVerb >= 0) {
- draw_segment(canvas);
- }
- if (fBisectButton.enabled() || fJoinButton.enabled()) {
- draw_bisects(canvas, fActiveVerb >= 0);
- }
- if (fInOutButton.enabled()) {
- if (fActiveVerb >= 0) {
- draw_stroke(canvas, fActiveVerb);
- } else {
- for (int index = 0; index < fPath.countVerbs(); ++index) {
- draw_stroke(canvas, index);
- }
- }
- }
- if (fHideAll) {
- return;
- }
- for (int index = 0; index < kControlCount; ++index) {
- kControlList[index].fControl->draw(canvas, fControlPaints);
- }
- for (int index = 0; index < kButtonCount; ++index) {
- kButtonList[index].fButton->draw(canvas, fButtonPaints);
- }
- if (fShowLegend) {
- draw_legend(canvas);
- }
-
-#if 0
- SkPaint paint;
- paint.setARGB(255, 34, 31, 31);
- paint.setAntiAlias(true);
-
- SkPath path;
- path.moveTo(18,439);
- path.lineTo(414,439);
- path.lineTo(414,702);
- path.lineTo(18,702);
- path.lineTo(18,439);
-
- path.moveTo(19,701);
- path.lineTo(413,701);
- path.lineTo(413,440);
- path.lineTo(19,440);
- path.lineTo(19,701);
- path.close();
- canvas->drawPath(path, paint);
-
- canvas->scale(1.0f, -1.0f);
- canvas->translate(0.0f, -800.0f);
- canvas->drawPath(path, paint);
-#endif
-
- }
-
- int hittest_pt(SkPoint pt) {
- for (int index = 0; index < fPath.countPoints(); ++index) {
- if (SkPoint::Distance(fPath.getPoint(index), pt) <= kHitToleranace * 2) {
- return index;
- }
- }
- return -1;
- }
-
- virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
- SkPoint pt = {x, y};
- int ptHit = hittest_pt(pt);
- if (ptHit >= 0) {
- return new MyClick(MyClick::kPtType, ptHit);
- }
- SkPath::Verb verb;
- SkScalar weight;
- int verbHit = hittest_verb(pt, &verb, &weight);
- if (verbHit >= 0) {
- return new MyClick(MyClick::kVerbType, verbHit, verb, weight);
- }
- if (!fHideAll) {
- const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1);
- for (int index = 0; index < kControlCount; ++index) {
- if (kControlList[index].fControl->contains(rectPt)) {
- return new MyClick(MyClick::kControlType,
- kControlList[index].fControlType);
- }
- }
- for (int index = 0; index < kButtonCount; ++index) {
- if (kButtonList[index].fButton->contains(rectPt)) {
- return new MyClick(MyClick::kControlType, kButtonList[index].fButtonType);
- }
- }
- }
- fLineButton.fVisible = fQuadButton.fVisible = fConicButton.fVisible
- = fCubicButton.fVisible = fWeightControl.fVisible = fAddButton.fVisible
- = fDeleteButton.fVisible = false;
- fActiveVerb = -1;
- fActivePt = -1;
- if (fHandlePathMove) {
- return new MyClick(MyClick::kPathType, MyClick::kPathMove);
- }
- return nullptr;
- }
-
- static SkScalar MapScreenYtoValue(int y, const UniControl& control) {
- return SkTMin(1.f, SkTMax(0.f,
- SkIntToScalar(y) - control.fBounds.fTop) / control.fBounds.height())
- * (control.fMax - control.fMin) + control.fMin;
- }
-
- bool onClick(Click* click) override {
- MyClick* myClick = (MyClick*) click;
- switch (myClick->fType) {
- case MyClick::kPtType: {
- savePath(click->fState);
- fActivePt = myClick->ptHit();
- SkPoint pt = fPath.getPoint((int) myClick->fControl);
- pt.offset(SkIntToScalar(click->fCurr.fX - click->fPrev.fX),
- SkIntToScalar(click->fCurr.fY - click->fPrev.fY));
- set_path_pt(fActivePt, pt, &fPath);
- validatePath();
- return true;
- }
- case MyClick::kPathType:
- savePath(click->fState);
- fPath.offset(SkIntToScalar(click->fCurr.fX - click->fPrev.fX),
- SkIntToScalar(click->fCurr.fY - click->fPrev.fY));
- validatePath();
- return true;
- case MyClick::kVerbType: {
- fActiveVerb = myClick->verbHit();
- fLineButton.fVisible = fQuadButton.fVisible = fConicButton.fVisible
- = fCubicButton.fVisible = fAddButton.fVisible = fDeleteButton.fVisible
- = true;
- fLineButton.setEnabled(myClick->fVerb == SkPath::kLine_Verb);
- fQuadButton.setEnabled(myClick->fVerb == SkPath::kQuad_Verb);
- fConicButton.setEnabled(myClick->fVerb == SkPath::kConic_Verb);
- fCubicButton.setEnabled(myClick->fVerb == SkPath::kCubic_Verb);
- fWeightControl.fValLo = myClick->fWeight;
- fWeightControl.fVisible = myClick->fVerb == SkPath::kConic_Verb;
- } break;
- case MyClick::kControlType: {
- if (click->fState != skui::InputState::kDown && myClick->isButton()) {
- return true;
- }
- switch (myClick->fControl) {
- case MyClick::kFilterControl: {
- SkScalar val = MapScreenYtoValue(click->fCurr.fY, fFilterControl);
- if (val - fFilterControl.fValLo < fFilterControl.fValHi - val) {
- fFilterControl.fValLo = SkTMax(0.f, val);
- } else {
- fFilterControl.fValHi = SkTMin(255.f, val);
- }
- } break;
- case MyClick::kResControl:
- fResControl.fValLo = MapScreenYtoValue(click->fCurr.fY, fResControl);
- break;
- case MyClick::kWeightControl: {
- savePath(click->fState);
- SkScalar w = MapScreenYtoValue(click->fCurr.fY, fWeightControl);
- set_path_weight(fActiveVerb, w, &fPath);
- validatePath();
- fWeightControl.fValLo = w;
- } break;
- case MyClick::kWidthControl:
- fWidthControl.fValLo = MapScreenYtoValue(click->fCurr.fY, fWidthControl);
- break;
- case MyClick::kLineButton:
- savePath(click->fState);
- enable_verb_button(myClick->fControl);
- fWeightControl.fVisible = false;
- set_path_verb(fActiveVerb, SkPath::kLine_Verb, &fPath, 1);
- validatePath();
- break;
- case MyClick::kQuadButton:
- savePath(click->fState);
- enable_verb_button(myClick->fControl);
- fWeightControl.fVisible = false;
- set_path_verb(fActiveVerb, SkPath::kQuad_Verb, &fPath, 1);
- validatePath();
- break;
- case MyClick::kConicButton: {
- savePath(click->fState);
- enable_verb_button(myClick->fControl);
- fWeightControl.fVisible = true;
- const SkScalar defaultConicWeight = 1.f / SkScalarSqrt(2);
- set_path_verb(fActiveVerb, SkPath::kConic_Verb, &fPath, defaultConicWeight);
- validatePath();
- fWeightControl.fValLo = get_path_weight(fActiveVerb, fPath);
- } break;
- case MyClick::kCubicButton:
- savePath(click->fState);
- enable_verb_button(myClick->fControl);
- fWeightControl.fVisible = false;
- set_path_verb(fActiveVerb, SkPath::kCubic_Verb, &fPath, 1);
- validatePath();
- break;
- case MyClick::kAddButton:
- savePath(click->fState);
- add_path_segment(fActiveVerb, &fPath);
- validatePath();
- if (fWeightControl.fVisible) {
- fWeightControl.fValLo = get_path_weight(fActiveVerb, fPath);
- }
- break;
- case MyClick::kDeleteButton:
- savePath(click->fState);
- delete_path_segment(fActiveVerb, &fPath);
- validatePath();
- break;
- case MyClick::kFillButton:
- fFillButton.toggle();
- break;
- case MyClick::kSkeletonButton:
- fSkeletonButton.toggle();
- break;
- case MyClick::kFilterButton:
- fFilterButton.toggle();
- fFilterControl.fVisible = fFilterButton.fState == 2;
- break;
- case MyClick::kBisectButton:
- fBisectButton.toggle();
- break;
- case MyClick::kJoinButton:
- fJoinButton.toggle();
- break;
- case MyClick::kInOutButton:
- fInOutButton.toggle();
- break;
- default:
- SkASSERT(0);
- break;
- }
- } break;
- default:
- SkASSERT(0);
- break;
- }
- setControlButtonsPos();
- return true;
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-static struct KeyCommand {
- char fKey;
- char fAlternate;
- const char* fDescriptionL;
- const char* fDescriptionR;
- bool (AAGeometryView::*fFunction)();
-} kKeyCommandList[] = {
- { ' ', 0, "space", "center path", &AAGeometryView::scaleToFit },
- { '-', 0, "-", "zoom out", &AAGeometryView::scaleDown },
- { '+', '=', "+/=", "zoom in", &AAGeometryView::scaleUp },
- { 'D', 0, "D", "dump to console", &AAGeometryView::pathDump },
- { 'H', 0, "H", "hide controls", &AAGeometryView::hideAll },
- { 'R', 0, "R", "reset path", &AAGeometryView::constructPath },
- { 'Z', 0, "Z", "undo", &AAGeometryView::undo },
- { '?', 0, "?", "show legend", &AAGeometryView::showLegend },
-};
-
-const int kKeyCommandCount = (int) SK_ARRAY_COUNT(kKeyCommandList);
-
-void AAGeometryView::draw_legend(SkCanvas* canvas) {
- SkScalar bottomOffset = this->height() - 10;
- for (int index = kKeyCommandCount - 1; index >= 0; --index) {
- bottomOffset -= 15;
- SkTextUtils::DrawString(canvas, kKeyCommandList[index].fDescriptionL, this->width() - 160, bottomOffset,
- fLegendLeftFont, SkPaint());
- SkTextUtils::DrawString(canvas, kKeyCommandList[index].fDescriptionR,
- this->width() - 20, bottomOffset,
- fLegendRightFont, SkPaint(), SkTextUtils::kRight_Align);
- }
-}
-
-bool AAGeometryView::onChar(SkUnichar uni) {
- for (int index = 0; index < kButtonCount; ++index) {
- Button* button = kButtonList[index].fButton;
- if (button->fVisible && uni == button->fLabel) {
- MyClick click(MyClick::kControlType, kButtonList[index].fButtonType);
- click.fState = skui::InputState::kDown;
- (void) this->onClick(&click);
- return true;
- }
- }
- for (int index = 0; index < kKeyCommandCount; ++index) {
- KeyCommand& keyCommand = kKeyCommandList[index];
- if (uni == keyCommand.fKey || uni == keyCommand.fAlternate) {
- return (this->*keyCommand.fFunction)();
- }
- }
- if (('A' <= uni && uni <= 'Z') || ('a' <= uni && uni <= 'z')) {
- for (int index = 0; index < kButtonCount; ++index) {
- Button* button = kButtonList[index].fButton;
- if (button->fVisible && (uni & ~0x20) == (button->fLabel & ~0x20)) {
- MyClick click(MyClick::kControlType, kButtonList[index].fButtonType);
- click.fState = skui::InputState::kDown;
- (void) this->onClick(&click);
- return true;
- }
- }
- }
- return false;
-}
-
-DEF_SAMPLE( return new AAGeometryView; )
diff --git a/third_party/skia/samplecode/SampleAARectModes.cpp b/third_party/skia/samplecode/SampleAARectModes.cpp
index a3c5ea3..99d8f77 100644
--- a/third_party/skia/samplecode/SampleAARectModes.cpp
+++ b/third_party/skia/samplecode/SampleAARectModes.cpp
@@ -62,10 +62,8 @@
*bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC,
0xCC, 0xCC);
- SkMatrix m;
- m.setScale(SkIntToScalar(6), SkIntToScalar(6));
-
- return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, &m);
+ return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions(),
+ SkMatrix::Scale(6, 6));
}
class AARectsModesView : public Sample {
diff --git a/third_party/skia/samplecode/SampleAARects.cpp b/third_party/skia/samplecode/SampleAARects.cpp
index 834a1e5..b7cc5e8 100644
--- a/third_party/skia/samplecode/SampleAARects.cpp
+++ b/third_party/skia/samplecode/SampleAARects.cpp
@@ -49,7 +49,8 @@
SkPaint bluePaint;
bluePaint.setARGB(0xff, 0x0, 0x0, 0xff);
SkPaint bmpPaint;
- bmpPaint.setShader(fBitmap.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat));
+ bmpPaint.setShader(fBitmap.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
+ SkSamplingOptions()));
bluePaint.setStrokeWidth(3);
bmpPaint.setStrokeWidth(3);
@@ -170,7 +171,7 @@
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleAndroidShadows.cpp b/third_party/skia/samplecode/SampleAndroidShadows.cpp
index a4518f2..50c626e 100644
--- a/third_party/skia/samplecode/SampleAndroidShadows.cpp
+++ b/third_party/skia/samplecode/SampleAndroidShadows.cpp
@@ -9,7 +9,6 @@
#include "include/core/SkColorFilter.h"
#include "include/core/SkPath.h"
#include "include/core/SkPoint3.h"
-#include "include/effects/SkBlurMaskFilter.h"
#include "include/pathops/SkPathOps.h"
#include "include/utils/SkCamera.h"
#include "include/utils/SkShadowUtils.h"
@@ -192,55 +191,55 @@
paint.setColor(SK_ColorWHITE);
canvas->translate(200, 90);
- zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 2 + fZDelta);
this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorRED);
canvas->translate(250, 0);
- zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 8 + fZDelta);
this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorBLUE);
canvas->translate(-250, 110);
- zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 12 + fZDelta);
this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*0.5f);
paint.setColor(SK_ColorGREEN);
canvas->translate(250, 0);
- zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 64 + fZDelta);
this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorYELLOW);
canvas->translate(-250, 110);
- zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 8 + fZDelta);
this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorCYAN);
canvas->translate(250, 0);
- zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 16 + fZDelta);
this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorWHITE);
canvas->translate(250, -180);
- zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 8 + fZDelta);
this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint,
kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
paint.setColor(SK_ColorWHITE);
canvas->translate(150, 0);
- zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 2 + fZDelta);
this->drawShadowedPath(canvas, fNotchPath, zPlaneParams, paint,
kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
paint.setColor(SK_ColorWHITE);
canvas->translate(200, 0);
- zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 16 + fZDelta);
this->drawShadowedPath(canvas, fTabPath, zPlaneParams, paint,
kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
@@ -252,7 +251,7 @@
paint.setColor(SK_ColorMAGENTA);
canvas->translate(-725, 240);
- zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 32 + fZDelta);
this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f,
lightPos, kLightWidth, .5f);
@@ -262,7 +261,7 @@
Op(fSquareRRectPath, tmpClipPathBug, kIntersect_SkPathOp, &tmpPath);
canvas->translate(250, 0);
- zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta);
+ zPlaneParams.fZ = std::max(1.0f, 32 + fZDelta);
this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f,
lightPos, kLightWidth, .5f);
@@ -282,7 +281,7 @@
SkScalar radians = SkDegreesToRadians(fAnimAngle);
zPlaneParams = SkPoint3::Make(0,
SkScalarSin(radians),
- SkTMax(1.0f, 16 + fZDelta) - SkScalarSin(radians)*pivot.fY);
+ std::max(1.0f, 16 + fZDelta) - SkScalarSin(radians)*pivot.fY);
this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f,
lightPos, kLightWidth, .5f);
@@ -298,7 +297,7 @@
canvas->setMatrix(persp);
zPlaneParams = SkPoint3::Make(-SkScalarSin(radians),
0,
- SkTMax(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX);
+ std::max(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX);
this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f,
lightPos, kLightWidth, .5f);
@@ -313,7 +312,7 @@
canvas->setMatrix(persp);
zPlaneParams = SkPoint3::Make(-SkScalarSin(radians),
0,
- SkTMax(1.0f, 8 + fZDelta) + SkScalarSin(radians)*pivot.fX);
+ std::max(1.0f, 8 + fZDelta) + SkScalarSin(radians)*pivot.fX);
this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint, .1f,
lightPos, kLightWidth, .5f);
}
@@ -328,7 +327,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleAnimatedImage.cpp b/third_party/skia/samplecode/SampleAnimatedImage.cpp
index da6ac28..1ca7ac1 100644
--- a/third_party/skia/samplecode/SampleAnimatedImage.cpp
+++ b/third_party/skia/samplecode/SampleAnimatedImage.cpp
@@ -104,11 +104,10 @@
switch (uni) {
case kPauseKey:
fRunning = !fRunning;
- if (fImage->isFinished()) {
- // fall through
- } else {
+ if (!fImage->isFinished()) {
return true;
}
+ [[fallthrough]];
case kResetKey:
fImage->reset();
fCurrentTime = fLastWallTime;
diff --git a/third_party/skia/samplecode/SampleAnimatedText.cpp b/third_party/skia/samplecode/SampleAnimatedText.cpp
index 8e7ed0e..80aafdc 100644
--- a/third_party/skia/samplecode/SampleAnimatedText.cpp
+++ b/third_party/skia/samplecode/SampleAnimatedText.cpp
@@ -8,6 +8,7 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkColorPriv.h"
+#include "include/core/SkFont.h"
#include "include/core/SkImage.h"
#include "include/core/SkTime.h"
#include "include/core/SkTypeface.h"
@@ -16,8 +17,8 @@
#include "src/utils/SkUTF.h"
#if SK_SUPPORT_GPU
-#include "include/gpu/GrContext.h"
-#include "src/gpu/GrContextPriv.h"
+#include "include/gpu/GrDirectContext.h"
+#include "src/gpu/GrDirectContextPriv.h"
#endif
SkRandom gRand;
@@ -62,17 +63,18 @@
SkPaint paint;
paint.setAntiAlias(true);
- paint.setFilterQuality(kMedium_SkFilterQuality);
canvas->save();
#if SK_SUPPORT_GPU
- GrContext* grContext = canvas->getGrContext();
- if (grContext) {
- sk_sp<SkImage> image = grContext->priv().testingOnly_getFontAtlasImage(
+ auto direct = GrAsDirectContext(canvas->recordingContext());
+ if (direct) {
+ SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kNearest);
+ sk_sp<SkImage> image = direct->priv().testingOnly_getFontAtlasImage(
GrMaskFormat::kA8_GrMaskFormat);
- canvas->drawImageRect(image,
- SkRect::MakeXYWH(512.0f, 10.0f, 512.0f, 512.0f), &paint);
+ const SkRect rect = SkRect::MakeXYWH(512.0f, 10.0f, 512.0f, 512.0f);
+ canvas->drawImageRect(image.get(), rect, rect, sampling, &paint,
+ SkCanvas::kFast_SrcRectConstraint);
}
#endif
canvas->translate(180, 180);
diff --git a/third_party/skia/samplecode/SampleAtlas.cpp b/third_party/skia/samplecode/SampleAtlas.cpp
index 85d267c..8f7f116 100644
--- a/third_party/skia/samplecode/SampleAtlas.cpp
+++ b/third_party/skia/samplecode/SampleAtlas.cpp
@@ -13,27 +13,30 @@
#include "include/utils/SkRandom.h"
#include "include/utils/SkTextUtils.h"
#include "samplecode/Sample.h"
+#include "src/core/SkPaintPriv.h"
typedef void (*DrawAtlasProc)(SkCanvas*, SkImage*, const SkRSXform[], const SkRect[],
- const SkColor[], int, const SkRect*, const SkPaint*);
+ const SkColor[], int, const SkRect*, const SkSamplingOptions&,
+ const SkPaint*);
static void draw_atlas(SkCanvas* canvas, SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count, const SkRect* cull,
- const SkPaint* paint) {
- canvas->drawAtlas(atlas, xform, tex, colors, count, SkBlendMode::kModulate, cull, paint);
+ const SkSamplingOptions& sampling, const SkPaint* paint) {
+ canvas->drawAtlas(atlas, xform, tex, colors, count, SkBlendMode::kModulate,
+ sampling, cull, paint);
}
static void draw_atlas_sim(SkCanvas* canvas, SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count, const SkRect* cull,
- const SkPaint* paint) {
+ const SkSamplingOptions& sampling, const SkPaint* paint) {
for (int i = 0; i < count; ++i) {
SkMatrix matrix;
matrix.setRSXform(xform[i]);
canvas->save();
canvas->concat(matrix);
- canvas->drawImageRect(atlas, tex[i], tex[i].makeOffset(-tex[i].x(), -tex[i].y()), paint,
- SkCanvas::kFast_SrcRectConstraint);
+ canvas->drawImageRect(atlas, tex[i], tex[i].makeOffset(-tex[i].x(), -tex[i].y()),
+ sampling, paint, SkCanvas::kFast_SrcRectConstraint);
canvas->restore();
}
}
@@ -183,11 +186,11 @@
}
}
SkPaint paint;
- paint.setFilterQuality(kLow_SkFilterQuality);
+ SkSamplingOptions sampling(SkFilterMode::kLinear);
const SkRect cull = this->getBounds();
const SkColor* colorsPtr = fUseColors ? colors : nullptr;
- fProc(canvas, fAtlas.get(), xform, fTex, colorsPtr, N, &cull, &paint);
+ fProc(canvas, fAtlas.get(), xform, fTex, colorsPtr, N, &cull, sampling, &paint);
}
SkRect onGetBounds() override {
@@ -198,7 +201,7 @@
}
private:
- typedef SkDrawable INHERITED;
+ using INHERITED = SkDrawable;
};
class DrawAtlasView : public Sample {
@@ -239,7 +242,7 @@
#endif
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleAudio.cpp b/third_party/skia/samplecode/SampleAudio.cpp
new file mode 100644
index 0000000..a3347d7
--- /dev/null
+++ b/third_party/skia/samplecode/SampleAudio.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2020 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/SkData.h"
+#include "modules/audioplayer/SkAudioPlayer.h"
+#include "samplecode/Sample.h"
+#include "src/core/SkUtils.h"
+#include "tools/Resources.h"
+
+class AudioView : public Sample {
+ std::unique_ptr<SkAudioPlayer> fPlayer;
+ SkRect fBar;
+
+public:
+ AudioView() {}
+
+protected:
+ SkString name() override { return SkString("Audio"); }
+
+ void onOnceBeforeDraw() override {
+ auto data = SkData::MakeFromFileName("/Users/reed/skia/mp3/scott-joplin-peacherine-rag.mp3");
+ if (data) {
+ fPlayer = SkAudioPlayer::Make(data);
+
+ SkDebugf("make: dur:%g time%g state:%d",
+ fPlayer->duration(),
+ fPlayer->time(),
+ (int)fPlayer->state());
+ }
+
+ fBar = { 10, 10, 510, 30 };
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ if (!fPlayer) {
+ return;
+ }
+
+ SkPaint p;
+ p.setColor(0xFFCCCCCC);
+ canvas->drawRect(fBar, p);
+
+ p.setColor(fPlayer->isPlaying() ? SK_ColorBLUE : 0xFF8888FF);
+ SkRect r = fBar;
+ r.fRight = r.fLeft + (float)fPlayer->normalizedTime() * r.width();
+ canvas->drawRect(r, p);
+ }
+
+ bool onChar(SkUnichar c) override {
+ if (c == ' ') {
+ switch (fPlayer->state()) {
+ case SkAudioPlayer::State::kPlaying: fPlayer->pause(); break;
+ case SkAudioPlayer::State::kPaused: fPlayer->play(); break;
+ case SkAudioPlayer::State::kStopped: fPlayer->play(); break;
+ }
+ return true;
+ }
+ return this->INHERITED::onChar(c);
+ }
+
+ Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
+ if (fPlayer && fBar.contains(x, y)) {
+ bool wasPlaying = fPlayer->isPlaying();
+ if (wasPlaying) {
+ fPlayer->pause();
+ }
+ return new Click([this, wasPlaying](Click* click) {
+ if (fBar.contains(click->fCurr.fX, click->fCurr.fY)) {
+ fPlayer->setNormalizedTime((click->fCurr.fX - fBar.fLeft) / fBar.width());
+ }
+
+ if (click->fState == skui::InputState::kUp) {
+ if (wasPlaying) {
+ fPlayer->play();
+ }
+ }
+ return true;
+ });
+ }
+ return nullptr;
+ }
+
+ bool onAnimate(double /*nanos*/) override {
+ return true;
+ }
+
+private:
+ using INHERITED = Sample;
+};
+DEF_SAMPLE( return new AudioView; )
diff --git a/third_party/skia/samplecode/SampleBackdropBounds.cpp b/third_party/skia/samplecode/SampleBackdropBounds.cpp
deleted file mode 100644
index d16d0b9..0000000
--- a/third_party/skia/samplecode/SampleBackdropBounds.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2019 Google LLC
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "samplecode/Sample.h"
-
-#include "include/core/SkCanvas.h"
-#include "include/core/SkColor.h"
-#include "include/core/SkFont.h"
-#include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
-#include "include/core/SkPoint.h"
-#include "include/core/SkRect.h"
-
-#include "tools/ToolUtils.h"
-
-static constexpr float kLineHeight = 16.f;
-static constexpr float kLineInset = 8.f;
-
-static float print_size(SkCanvas* canvas, const char* prefix, const SkIRect& rect,
- float x, float y, const SkFont& font, const SkPaint& paint) {
- canvas->drawString(prefix, x, y, font, paint);
- y += kLineHeight;
- SkString sz;
- sz.appendf("%d x %d", rect.width(), rect.height());
- canvas->drawString(sz, x, y, font, paint);
- return y + kLineHeight;
-}
-
-static float print_info(SkCanvas* canvas, const SkIRect& origLayerBounds,
- const SkIRect& localLayerBounds, const SkIRect& filterInputBounds,
- const SkIRect& devLayerBounds) {
- SkFont font(nullptr, 12);
- SkPaint text;
- text.setAntiAlias(true);
-
- float y = kLineHeight;
-
- text.setColor(SK_ColorBLACK);
- y = print_size(canvas, "Orig layer", origLayerBounds, kLineInset, y, font, text);
- text.setColor(SK_ColorRED);
- y = print_size(canvas, "Filter layer", localLayerBounds, kLineInset, y, font, text);
- text.setColor(SK_ColorBLUE);
- y = print_size(canvas, "Filter input", filterInputBounds, kLineInset, y, font, text);
- text.setColor(SK_ColorMAGENTA);
- y = print_size(canvas, "Backdrop size", devLayerBounds, kLineInset, y, font, text);
-
- return y;
-}
-
-static SkPaint line_paint(SkScalar width, SkColor color) {
- SkPaint paint;
- paint.setColor(color);
- paint.setStrokeWidth(width);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setAntiAlias(true);
- return paint;
-}
-
-class BackdropBoundsSample : public Sample {
-public:
- BackdropBoundsSample() {}
-
- void onDrawContent(SkCanvas* canvas) override {
- SkMatrix ctm = canvas->getTotalMatrix();
-
- // This decomposition is for the backdrop filtering, and does not represent the CTM that
- // the layer actually uses (unless it also has a filter during restore).
- SkMatrix toGlobal, layerMatrix;
- SkSize scale;
- if (ctm.isScaleTranslate()) {
- // No decomposition needed
- toGlobal = SkMatrix::I();
- layerMatrix = ctm;
- } else if (ctm.decomposeScale(&scale, &toGlobal)) {
- layerMatrix = SkMatrix::MakeScale(scale.fWidth, scale.fHeight);
- } else {
- toGlobal = ctm;
- layerMatrix = SkMatrix::I();
- }
-
- SkMatrix fromGlobal;
- if (!toGlobal.invert(&fromGlobal)) {
- SkDebugf("Unable to invert CTM\n");
- return;
- }
-
- // The local content, e.g. what would be submitted to drawRect
- const SkRect localContentRect = SkRect::MakeLTRB(45.5f, 23.123f, 150.f, 140.45f);
- canvas->drawRect(localContentRect, line_paint(0.f, SK_ColorBLACK));
-
- canvas->save();
- // The layer bounds of the content, this is the size of the actual layer and does not
- // reflect the backdrop specific decomposition.
- canvas->setMatrix(SkMatrix::I());
- SkIRect origLayerBounds = ctm.mapRect(localContentRect).roundOut();
- canvas->drawRect(SkRect::Make(origLayerBounds), line_paint(1.f, SK_ColorBLACK));
-
- // Have to undo the full CTM transform on the layer bounds to get the layer bounds
- // for the specific backdrop filter decomposition
- canvas->setMatrix(toGlobal);
- SkIRect layerBounds = fromGlobal.mapRect(SkRect::Make(origLayerBounds)).roundOut();
- canvas->drawRect(SkRect::Make(layerBounds), line_paint(0.5f, SK_ColorRED));
-
- // Input bounds for the backdrop filter to cover the actual layer bounds (emulate some
- // blur that must outset by 5px for reading on the edge).
- SkIRect filterInputBounds = layerBounds;
- filterInputBounds.outset(5, 5);
- canvas->drawRect(SkRect::Make(filterInputBounds), line_paint(1.f, SK_ColorBLUE));
-
- // The destination bounds that must be snapped in order to transform and fill the
- // filterInputBounds
- canvas->setMatrix(SkMatrix::I());
- SkIRect devLayerBounds = toGlobal.mapRect(SkRect::Make(filterInputBounds)).roundOut();
- canvas->drawRect(SkRect::Make(devLayerBounds), line_paint(2.f, SK_ColorMAGENTA));
-
- // The destination bounds mapped back into the layer space, which should cover 'layerBounds'
- SkPath backdropCoveringBounds;
-
- // Add axis lines, to show perspective distortion
- SkIRect local = fromGlobal.mapRect(SkRect::Make(devLayerBounds)).roundOut();
- static int kAxisSpace = 10;
- for (int y = local.fTop + kAxisSpace; y <= local.fBottom - kAxisSpace; y += kAxisSpace) {
- backdropCoveringBounds.moveTo(local.fLeft, y);
- backdropCoveringBounds.lineTo(local.fRight, y);
- }
- for (int x = local.fLeft + kAxisSpace; x <= local.fRight - kAxisSpace; x += kAxisSpace) {
- backdropCoveringBounds.moveTo(x, local.fTop);
- backdropCoveringBounds.lineTo(x, local.fBottom);
- }
-
- canvas->setMatrix(toGlobal);
- canvas->drawPath(backdropCoveringBounds, line_paint(0.f, SK_ColorGREEN));
-
- canvas->resetMatrix();
- print_info(canvas, origLayerBounds, layerBounds, filterInputBounds, devLayerBounds);
-
- canvas->restore();
- }
-
- SkString name() override { return SkString("BackdropBounds"); }
-
-private:
-
- typedef Sample INHERITED;
-};
-
-DEF_SAMPLE(return new BackdropBoundsSample();)
diff --git a/third_party/skia/samplecode/SampleBitmapRect.cpp b/third_party/skia/samplecode/SampleBitmapRect.cpp
deleted file mode 100644
index 1f757f5..0000000
--- a/third_party/skia/samplecode/SampleBitmapRect.cpp
+++ /dev/null
@@ -1,160 +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/SkBitmap.h"
-#include "include/core/SkCanvas.h"
-#include "include/core/SkColorFilter.h"
-#include "include/core/SkColorPriv.h"
-#include "include/core/SkFont.h"
-#include "include/core/SkGraphics.h"
-#include "include/core/SkPath.h"
-#include "include/core/SkRegion.h"
-#include "include/core/SkShader.h"
-#include "include/core/SkTime.h"
-#include "include/core/SkTypeface.h"
-#include "include/effects/SkGradientShader.h"
-#include "samplecode/Sample.h"
-#include "src/utils/SkUTF.h"
-
-#include "include/core/SkStream.h"
-#include "src/core/SkOSFile.h"
-
-static constexpr int INT_SIZE = 64;
-static constexpr float SCALAR_SIZE = (float)INT_SIZE;
-
-static void make_bitmap(SkBitmap* bitmap) {
- bitmap->allocN32Pixels(INT_SIZE, INT_SIZE);
- SkCanvas canvas(*bitmap);
-
- canvas.drawColor(SK_ColorRED);
- SkPaint paint;
- paint.setAntiAlias(true);
- const SkPoint pts[] = { { 0, 0 }, { SCALAR_SIZE, SCALAR_SIZE } };
- const SkColor colors[] = { SK_ColorWHITE, SK_ColorBLUE };
- paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp));
- canvas.drawCircle(SCALAR_SIZE/2, SCALAR_SIZE/2, SCALAR_SIZE/2, paint);
-}
-
-static void bounce(SkScalar* value, SkScalar* delta, SkScalar min, SkScalar max) {
- *value += *delta;
- if (*value < min) {
- *value = min;
- *delta = - *delta;
- } else if (*value > max) {
- *value = max;
- *delta = - *delta;
- }
-}
-
-static void bounce_pt(SkPoint* pt, SkVector* vec, const SkRect& limit) {
- bounce(&pt->fX, &vec->fX, limit.fLeft, limit.fRight);
- bounce(&pt->fY, &vec->fY, limit.fTop, limit.fBottom);
-}
-
-class BitmapRectView : public Sample {
- SkPoint fSrcPt = {0, 0};
- SkPoint fSrcVec = {0.866025f, 0.5f};
-
- SkRect fSrcLimit = {-SCALAR_SIZE/4, -SCALAR_SIZE/4,
- SCALAR_SIZE*5/4, SCALAR_SIZE*5/4};
- SkRect fDstR[2] = {{10, 100, 260, 400}, {322.5, 100, 572.5, 400}};
- SkBitmap fBitmap;
-
- SkString name() override { return SkString("BitmapRect"); }
-
- void onOnceBeforeDraw() override {
- this->setBGColor(SK_ColorGRAY);
- make_bitmap(&fBitmap);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- SkRect srcR = {fSrcPt.fX - 16, fSrcPt.fY - 16,
- fSrcPt.fX + 16, fSrcPt.fY + 16};
-
- SkPaint paint(SkColors::kYellow);
- paint.setStyle(SkPaint::kStroke_Style);
-
- canvas->translate(20, 20);
-
- canvas->drawBitmap(fBitmap, 0, 0, &paint);
- canvas->drawRect(srcR, paint);
-
- for (int i = 0; i < 2; ++i) {
- paint.setFilterQuality(1 == i ? kLow_SkFilterQuality : kNone_SkFilterQuality);
- canvas->drawBitmapRect(fBitmap, srcR, fDstR[i], &paint,
- SkCanvas::kStrict_SrcRectConstraint);
- canvas->drawRect(fDstR[i], paint);
- }
- }
-
- bool onAnimate(double nanos) override {
- bounce_pt(&fSrcPt, &fSrcVec, fSrcLimit);
- return true;
- }
-};
-
-static constexpr int BIG_H = 120;
-
-static void make_big_bitmap(SkBitmap* bm) {
- static const char gText[] =
- "We the people, in order to form a more perfect union, establish justice,"
- " ensure domestic tranquility, provide for the common defense, promote the"
- " general welfare and ensure the blessings of liberty to ourselves and our"
- " posterity, do ordain and establish this constitution for the United"
- " States of America.";
-
- SkFont font;
- font.setSize(SkIntToScalar(BIG_H));
-
- const int BIG_W = SkScalarRoundToInt(font.measureText(gText, strlen(gText), SkTextEncoding::kUTF8));
-
- bm->allocN32Pixels(BIG_W, BIG_H);
- bm->eraseColor(SK_ColorWHITE);
-
- SkCanvas canvas(*bm);
-
- canvas.drawSimpleText(gText, strlen(gText), SkTextEncoding::kUTF8, 0, font.getSize()*4/5, font, SkPaint());
-}
-
-class BitmapRectView2 : public Sample {
- SkBitmap fBitmap;
- SkRect fSrcR = {0, 0, 3 * BIG_H, BIG_H};
- SkRect fLimitR;
- SkScalar fDX = 1;
- SkRect fDstR[2] = {{20, 20, 620, 220}, {20, 270, 620, 470}};
-
- SkString name() override { return SkString("BigBitmapRect"); }
-
- void onOnceBeforeDraw() override {
- this->setBGColor(SK_ColorGRAY);
- make_big_bitmap(&fBitmap);
- fLimitR = SkRect::Make(fBitmap.dimensions());
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- SkPaint paint;
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(SK_ColorYELLOW);
-
- for (int i = 0; i < 2; ++i) {
- paint.setFilterQuality(1 == i ? kLow_SkFilterQuality : kNone_SkFilterQuality);
- canvas->drawBitmapRect(fBitmap, fSrcR, fDstR[i], &paint,
- SkCanvas::kStrict_SrcRectConstraint);
- canvas->drawRect(fDstR[i], paint);
- }
- }
-
- bool onAnimate(double nanos) override {
- SkScalar width = fSrcR.width();
- bounce(&fSrcR.fLeft, &fDX, fLimitR.fLeft, fLimitR.fRight - width);
- fSrcR.fRight = fSrcR.fLeft + width;
- return true;
- }
-};
-
-DEF_SAMPLE( return new BitmapRectView(); )
-DEF_SAMPLE( return new BitmapRectView2(); )
diff --git a/third_party/skia/samplecode/SampleCCPRGeometry.cpp b/third_party/skia/samplecode/SampleCCPRGeometry.cpp
deleted file mode 100644
index dff8ed9..0000000
--- a/third_party/skia/samplecode/SampleCCPRGeometry.cpp
+++ /dev/null
@@ -1,495 +0,0 @@
-/*
- * Copyright 2017 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/SkTypes.h"
-
-#if SK_SUPPORT_GPU
-
-#include "include/core/SkCanvas.h"
-#include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkMakeUnique.h"
-#include "src/core/SkRectPriv.h"
-#include "src/gpu/GrClip.h"
-#include "src/gpu/GrContextPriv.h"
-#include "src/gpu/GrMemoryPool.h"
-#include "src/gpu/GrRenderTargetContext.h"
-#include "src/gpu/GrRenderTargetContextPriv.h"
-#include "src/gpu/GrResourceProvider.h"
-#include "src/gpu/ccpr/GrCCCoverageProcessor.h"
-#include "src/gpu/ccpr/GrCCFillGeometry.h"
-#include "src/gpu/ccpr/GrCCStroker.h"
-#include "src/gpu/ccpr/GrGSCoverageProcessor.h"
-#include "src/gpu/ccpr/GrVSCoverageProcessor.h"
-#include "src/gpu/geometry/GrPathUtils.h"
-#include "src/gpu/gl/GrGLGpu.h"
-#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/ops/GrDrawOp.h"
-
-using TriPointInstance = GrCCCoverageProcessor::TriPointInstance;
-using QuadPointInstance = GrCCCoverageProcessor::QuadPointInstance;
-using PrimitiveType = GrCCCoverageProcessor::PrimitiveType;
-
-static constexpr float kDebugBloat = 40;
-
-/**
- * This sample visualizes the AA bloat geometry generated by the ccpr geometry shaders. It
- * increases the AA bloat by 50x and outputs color instead of coverage (coverage=+1 -> green,
- * coverage=0 -> black, coverage=-1 -> red). Use the keys 1-7 to cycle through the different
- * geometry processors.
- */
-class CCPRGeometryView : public Sample {
- void onOnceBeforeDraw() override { this->updateGpuData(); }
- void onDrawContent(SkCanvas*) override;
-
- Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
- bool onClick(Sample::Click*) override;
- bool onChar(SkUnichar) override;
- SkString name() override { return SkString("CCPRGeometry"); }
-
- class Click;
- class DrawCoverageCountOp;
- class VisualizeCoverageCountFP;
-
- void updateAndInval() { this->updateGpuData(); }
-
- void updateGpuData();
-
- PrimitiveType fPrimitiveType = PrimitiveType::kTriangles;
- SkCubicType fCubicType;
- SkMatrix fCubicKLM;
-
- SkPoint fPoints[4] = {
- {100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}};
-
- float fConicWeight = .5;
- float fStrokeWidth = 40;
- bool fDoStroke = false;
-
- SkTArray<TriPointInstance> fTriPointInstances;
- SkTArray<QuadPointInstance> fQuadPointInstances;
- SkPath fPath;
-};
-
-class CCPRGeometryView::DrawCoverageCountOp : public GrDrawOp {
- DEFINE_OP_CLASS_ID
-
-public:
- DrawCoverageCountOp(CCPRGeometryView* view) : INHERITED(ClassID()), fView(view) {
- this->setBounds(SkRect::MakeIWH(fView->width(), fView->height()), GrOp::HasAABloat::kNo,
- GrOp::IsHairline::kNo);
- }
-
- const char* name() const override {
- return "[Testing/Sample code] CCPRGeometryView::DrawCoverageCountOp";
- }
-
-private:
- FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
- GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*,
- bool hasMixedSampledCoverage, GrClampType) override {
- return GrProcessorSet::EmptySetAnalysis();
- }
- void onPrepare(GrOpFlushState*) override {}
- void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
-
- CCPRGeometryView* fView;
-
- typedef GrDrawOp INHERITED;
-};
-
-class CCPRGeometryView::VisualizeCoverageCountFP : public GrFragmentProcessor {
-public:
- VisualizeCoverageCountFP() : GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags) {}
-
-private:
- const char* name() const override {
- return "[Testing/Sample code] CCPRGeometryView::VisualizeCoverageCountFP";
- }
- std::unique_ptr<GrFragmentProcessor> clone() const override {
- return skstd::make_unique<VisualizeCoverageCountFP>();
- }
- void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
- bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
-
- class Impl : public GrGLSLFragmentProcessor {
- void emitCode(EmitArgs& args) override {
- GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
- f->codeAppendf("half count = %s.a;", args.fInputColor);
- f->codeAppendf("%s = half4(clamp(-count, 0, 1), clamp(+count, 0, 1), 0, abs(count));",
- args.fOutputColor);
- }
- };
-
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new Impl; }
-};
-
-static void draw_klm_line(int w, int h, SkCanvas* canvas, const SkScalar line[3], SkColor color) {
- SkPoint p1, p2;
- if (SkScalarAbs(line[1]) > SkScalarAbs(line[0])) {
- // Draw from vertical edge to vertical edge.
- p1 = {0, -line[2] / line[1]};
- p2 = {(SkScalar)w, (-line[2] - w * line[0]) / line[1]};
- } else {
- // Draw from horizontal edge to horizontal edge.
- p1 = {-line[2] / line[0], 0};
- p2 = {(-line[2] - h * line[1]) / line[0], (SkScalar)h};
- }
-
- SkPaint linePaint;
- linePaint.setColor(color);
- linePaint.setAlpha(128);
- linePaint.setStyle(SkPaint::kStroke_Style);
- linePaint.setStrokeWidth(0);
- linePaint.setAntiAlias(true);
- canvas->drawLine(p1, p2, linePaint);
-}
-
-void CCPRGeometryView::onDrawContent(SkCanvas* canvas) {
- canvas->clear(SK_ColorBLACK);
-
- if (!fDoStroke) {
- SkPaint outlinePaint;
- outlinePaint.setColor(0x80ffffff);
- outlinePaint.setStyle(SkPaint::kStroke_Style);
- outlinePaint.setStrokeWidth(0);
- outlinePaint.setAntiAlias(true);
- canvas->drawPath(fPath, outlinePaint);
- }
-
-#if 0
- SkPaint gridPaint;
- gridPaint.setColor(0x10000000);
- gridPaint.setStyle(SkPaint::kStroke_Style);
- gridPaint.setStrokeWidth(0);
- gridPaint.setAntiAlias(true);
- for (int y = 0; y < this->height(); y += kDebugBloat) {
- canvas->drawLine(0, y, this->width(), y, gridPaint);
- }
- for (int x = 0; x < this->width(); x += kDebugBloat) {
- canvas->drawLine(x, 0, x, this->height(), outlinePaint);
- }
-#endif
-
- SkString caption;
- if (GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext()) {
- // Render coverage count.
- GrContext* ctx = canvas->getGrContext();
- SkASSERT(ctx);
-
- GrOpMemoryPool* pool = ctx->priv().opMemoryPool();
-
- auto ccbuff = ctx->priv().makeDeferredRenderTargetContext(SkBackingFit::kApprox,
- this->width(), this->height(),
- GrColorType::kAlpha_F16, nullptr);
- SkASSERT(ccbuff);
- ccbuff->clear(nullptr, SK_PMColor4fTRANSPARENT,
- GrRenderTargetContext::CanClearFullscreen::kYes);
- ccbuff->priv().testingOnly_addDrawOp(pool->allocate<DrawCoverageCountOp>(this));
-
- // Visualize coverage count in main canvas.
- GrPaint paint;
- paint.addColorFragmentProcessor(
- GrSimpleTextureEffect::Make(sk_ref_sp(ccbuff->asTextureProxy()),
- ccbuff->colorInfo().alphaType(), SkMatrix::I()));
- paint.addColorFragmentProcessor(
- skstd::make_unique<VisualizeCoverageCountFP>());
- paint.setPorterDuffXPFactory(SkBlendMode::kSrcOver);
- rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
- SkRect::MakeIWH(this->width(), this->height()));
-
- // Add label.
- caption.appendf("PrimitiveType_%s",
- GrCCCoverageProcessor::PrimitiveTypeName(fPrimitiveType));
- if (PrimitiveType::kCubics == fPrimitiveType) {
- caption.appendf(" (%s)", SkCubicTypeName(fCubicType));
- } else if (PrimitiveType::kConics == fPrimitiveType) {
- caption.appendf(" (w=%f)", fConicWeight);
- }
- if (fDoStroke) {
- caption.appendf(" (stroke_width=%f)", fStrokeWidth);
- }
- } else {
- caption = "Use GPU backend to visualize geometry.";
- }
-
- SkPaint pointsPaint;
- pointsPaint.setColor(SK_ColorBLUE);
- pointsPaint.setStrokeWidth(8);
- pointsPaint.setAntiAlias(true);
-
- if (PrimitiveType::kCubics == fPrimitiveType) {
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPoints, pointsPaint);
- if (!fDoStroke) {
- int w = this->width(), h = this->height();
- draw_klm_line(w, h, canvas, &fCubicKLM[0], SK_ColorYELLOW);
- draw_klm_line(w, h, canvas, &fCubicKLM[3], SK_ColorBLUE);
- draw_klm_line(w, h, canvas, &fCubicKLM[6], SK_ColorRED);
- }
- } else {
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, fPoints, pointsPaint);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, fPoints + 3, pointsPaint);
- }
-
- SkFont font(nullptr, 20);
- SkPaint captionPaint;
- captionPaint.setColor(SK_ColorWHITE);
- canvas->drawString(caption, 10, 30, font, captionPaint);
-}
-
-void CCPRGeometryView::updateGpuData() {
- using Verb = GrCCFillGeometry::Verb;
- fTriPointInstances.reset();
- fQuadPointInstances.reset();
-
- fPath.reset();
- fPath.moveTo(fPoints[0]);
-
- if (PrimitiveType::kCubics == fPrimitiveType) {
- double t[2], s[2];
- fCubicType = GrPathUtils::getCubicKLM(fPoints, &fCubicKLM, t, s);
- GrCCFillGeometry geometry;
- geometry.beginContour(fPoints[0]);
- geometry.cubicTo(fPoints, kDebugBloat / 2, kDebugBloat / 2);
- geometry.endContour();
- int ptsIdx = 0;
- for (Verb verb : geometry.verbs()) {
- switch (verb) {
- case Verb::kLineTo:
- ++ptsIdx;
- continue;
- case Verb::kMonotonicQuadraticTo:
- ptsIdx += 2;
- continue;
- case Verb::kMonotonicCubicTo:
- fQuadPointInstances.push_back().set(&geometry.points()[ptsIdx], 0, 0);
- ptsIdx += 3;
- continue;
- default:
- continue;
- }
- }
- fPath.cubicTo(fPoints[1], fPoints[2], fPoints[3]);
- } else if (PrimitiveType::kTriangles != fPrimitiveType) {
- SkPoint P3[3] = {fPoints[0], fPoints[1], fPoints[3]};
- GrCCFillGeometry geometry;
- geometry.beginContour(P3[0]);
- if (PrimitiveType::kQuadratics == fPrimitiveType) {
- geometry.quadraticTo(P3);
- fPath.quadTo(fPoints[1], fPoints[3]);
- } else {
- SkASSERT(PrimitiveType::kConics == fPrimitiveType);
- geometry.conicTo(P3, fConicWeight);
- fPath.conicTo(fPoints[1], fPoints[3], fConicWeight);
- }
- geometry.endContour();
- int ptsIdx = 0, conicWeightIdx = 0;
- for (Verb verb : geometry.verbs()) {
- if (Verb::kBeginContour == verb ||
- Verb::kEndOpenContour == verb ||
- Verb::kEndClosedContour == verb) {
- continue;
- }
- if (Verb::kLineTo == verb) {
- ++ptsIdx;
- continue;
- }
- SkASSERT(Verb::kMonotonicQuadraticTo == verb || Verb::kMonotonicConicTo == verb);
- if (PrimitiveType::kQuadratics == fPrimitiveType &&
- Verb::kMonotonicQuadraticTo == verb) {
- fTriPointInstances.push_back().set(
- &geometry.points()[ptsIdx], Sk2f(0, 0),
- TriPointInstance::Ordering::kXYTransposed);
- } else if (PrimitiveType::kConics == fPrimitiveType &&
- Verb::kMonotonicConicTo == verb) {
- fQuadPointInstances.push_back().setW(&geometry.points()[ptsIdx], Sk2f(0, 0),
- geometry.getConicWeight(conicWeightIdx++));
- }
- ptsIdx += 2;
- }
- } else {
- fTriPointInstances.push_back().set(
- fPoints[0], fPoints[1], fPoints[3], Sk2f(0, 0),
- TriPointInstance::Ordering::kXYTransposed);
- fPath.lineTo(fPoints[1]);
- fPath.lineTo(fPoints[3]);
- fPath.close();
- }
-}
-
-void CCPRGeometryView::DrawCoverageCountOp::onExecute(GrOpFlushState* state,
- const SkRect& chainBounds) {
- GrResourceProvider* rp = state->resourceProvider();
- GrContext* context = state->gpu()->getContext();
- GrGLGpu* glGpu = GrBackendApi::kOpenGL == context->backend()
- ? static_cast<GrGLGpu*>(state->gpu())
- : nullptr;
- if (glGpu) {
- glGpu->handleDirtyContext();
- // GR_GL_CALL(glGpu->glInterface(), PolygonMode(GR_GL_FRONT_AND_BACK, GR_GL_LINE));
- GR_GL_CALL(glGpu->glInterface(), Enable(GR_GL_LINE_SMOOTH));
- }
-
- GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kPlus,
- state->drawOpArgs().outputSwizzle());
-
- std::unique_ptr<GrCCCoverageProcessor> proc;
- if (state->caps().shaderCaps()->geometryShaderSupport()) {
- proc = skstd::make_unique<GrGSCoverageProcessor>();
- } else {
- proc = skstd::make_unique<GrVSCoverageProcessor>();
- }
-
- if (!fView->fDoStroke) {
- proc->reset(fView->fPrimitiveType, rp);
- SkDEBUGCODE(proc->enableDebugBloat(kDebugBloat));
-
- SkSTArray<1, GrMesh> mesh;
- if (PrimitiveType::kCubics == fView->fPrimitiveType ||
- PrimitiveType::kConics == fView->fPrimitiveType) {
- sk_sp<GrGpuBuffer> instBuff(
- rp->createBuffer(fView->fQuadPointInstances.count() * sizeof(QuadPointInstance),
- GrGpuBufferType::kVertex, kDynamic_GrAccessPattern,
- fView->fQuadPointInstances.begin()));
- if (!fView->fQuadPointInstances.empty() && instBuff) {
- proc->appendMesh(std::move(instBuff), fView->fQuadPointInstances.count(), 0, &mesh);
- }
- } else {
- sk_sp<GrGpuBuffer> instBuff(
- rp->createBuffer(fView->fTriPointInstances.count() * sizeof(TriPointInstance),
- GrGpuBufferType::kVertex, kDynamic_GrAccessPattern,
- fView->fTriPointInstances.begin()));
- if (!fView->fTriPointInstances.empty() && instBuff) {
- proc->appendMesh(std::move(instBuff), fView->fTriPointInstances.count(), 0, &mesh);
- }
- }
-
- if (!mesh.empty()) {
- SkASSERT(1 == mesh.count());
- proc->draw(state, pipeline, nullptr, mesh.begin(), 1, this->bounds());
- }
- } else if (PrimitiveType::kConics != fView->fPrimitiveType) { // No conic stroke support yet.
- GrCCStroker stroker(0,0,0);
-
- SkPaint p;
- p.setStyle(SkPaint::kStroke_Style);
- p.setStrokeWidth(fView->fStrokeWidth);
- p.setStrokeJoin(SkPaint::kMiter_Join);
- p.setStrokeMiter(4);
- // p.setStrokeCap(SkPaint::kRound_Cap);
- stroker.parseDeviceSpaceStroke(fView->fPath, SkPathPriv::PointData(fView->fPath),
- SkStrokeRec(p), p.getStrokeWidth(), GrScissorTest::kDisabled,
- SkIRect::MakeWH(fView->width(), fView->height()), {0, 0});
- GrCCStroker::BatchID batchID = stroker.closeCurrentBatch();
-
- GrOnFlushResourceProvider onFlushRP(context->priv().drawingManager());
- stroker.prepareToDraw(&onFlushRP);
-
- SkIRect ibounds;
- this->bounds().roundOut(&ibounds);
- stroker.drawStrokes(state, proc.get(), batchID, ibounds);
- }
-
- if (glGpu) {
- context->resetContext(kMisc_GrGLBackendState);
- }
-}
-
-class CCPRGeometryView::Click : public Sample::Click {
-public:
- Click(int ptIdx) : fPtIdx(ptIdx) {}
-
- void doClick(SkPoint points[]) {
- if (fPtIdx >= 0) {
- points[fPtIdx] += fCurr - fPrev;
- } else {
- for (int i = 0; i < 4; ++i) {
- points[i] += fCurr - fPrev;
- }
- }
- }
-
-private:
- int fPtIdx;
-};
-
-Sample::Click* CCPRGeometryView::onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) {
- for (int i = 0; i < 4; ++i) {
- if (PrimitiveType::kCubics != fPrimitiveType && 2 == i) {
- continue;
- }
- if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) {
- return new Click(i);
- }
- }
- return new Click(-1);
-}
-
-bool CCPRGeometryView::onClick(Sample::Click* click) {
- Click* myClick = (Click*)click;
- myClick->doClick(fPoints);
- this->updateAndInval();
- return true;
-}
-
-bool CCPRGeometryView::onChar(SkUnichar unichar) {
- if (unichar >= '1' && unichar <= '4') {
- fPrimitiveType = PrimitiveType(unichar - '1');
- if (fPrimitiveType >= PrimitiveType::kWeightedTriangles) {
- fPrimitiveType = (PrimitiveType) ((int)fPrimitiveType + 1);
- }
- this->updateAndInval();
- return true;
- }
- float* valueToScale = nullptr;
- if (fDoStroke) {
- valueToScale = &fStrokeWidth;
- } else if (PrimitiveType::kConics == fPrimitiveType) {
- valueToScale = &fConicWeight;
- }
- if (valueToScale) {
- if (unichar == '+') {
- *valueToScale *= 2;
- this->updateAndInval();
- return true;
- }
- if (unichar == '+' || unichar == '=') {
- *valueToScale *= 5/4.f;
- this->updateAndInval();
- return true;
- }
- if (unichar == '-') {
- *valueToScale *= 4/5.f;
- this->updateAndInval();
- return true;
- }
- if (unichar == '_') {
- *valueToScale *= .5f;
- this->updateAndInval();
- return true;
- }
- }
- if (unichar == 'D') {
- SkDebugf(" SkPoint fPoints[4] = {\n");
- SkDebugf(" {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y());
- SkDebugf(" {%ff, %ff},\n", fPoints[1].x(), fPoints[1].y());
- SkDebugf(" {%ff, %ff},\n", fPoints[2].x(), fPoints[2].y());
- SkDebugf(" {%ff, %ff}\n", fPoints[3].x(), fPoints[3].y());
- SkDebugf(" };\n");
- return true;
- }
- if (unichar == 'S') {
- fDoStroke = !fDoStroke;
- this->updateAndInval();
- }
- return false;
-}
-
-DEF_SAMPLE(return new CCPRGeometryView;)
-
-#endif // SK_SUPPORT_GPU
diff --git a/third_party/skia/samplecode/SampleCamera.cpp b/third_party/skia/samplecode/SampleCamera.cpp
index 38201eb..41da126 100644
--- a/third_party/skia/samplecode/SampleCamera.cpp
+++ b/third_party/skia/samplecode/SampleCamera.cpp
@@ -6,6 +6,7 @@
*/
#include "include/core/SkCanvas.h"
+#include "include/core/SkImage.h"
#include "include/core/SkShader.h"
#include "include/core/SkString.h"
#include "include/utils/SkCamera.h"
@@ -35,9 +36,8 @@
if (GetResourceAsBitmap(resource, &bm)) {
SkRect src = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
SkRect dst = { -150, -150, 150, 150 };
- SkMatrix matrix;
- matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
- fShaders.push_back(bm.makeShader(&matrix));
+ fShaders.push_back(bm.makeShader(SkSamplingOptions(SkFilterMode::kLinear),
+ SkMatrix::RectToRect(src, dst)));
}
}
this->setBGColor(0xFFDDDDDD);
@@ -61,7 +61,6 @@
SkPaint paint;
paint.setAntiAlias(true);
paint.setShader(fShaders[fShaderIndex]);
- paint.setFilterQuality(kLow_SkFilterQuality);
SkRect r = { -150, -150, 150, 150 };
canvas->drawRoundRect(r, 30, 30, paint);
}
diff --git a/third_party/skia/samplecode/SampleChart.cpp b/third_party/skia/samplecode/SampleChart.cpp
index 448e1d7..37b9d06 100644
--- a/third_party/skia/samplecode/SampleChart.cpp
+++ b/third_party/skia/samplecode/SampleChart.cpp
@@ -7,7 +7,7 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
#include "include/utils/SkRandom.h"
#include "samplecode/Sample.h"
@@ -30,9 +30,7 @@
SkScalar yBase,
SkScalar xLeft, SkScalar xDelta,
int leftShift,
- SkPath* plot, SkPath* fill) {
- plot->rewind();
- fill->rewind();
+ SkPathBuilder* plot, SkPathBuilder* fill) {
plot->incReserve(topData.count());
if (nullptr == bottomData) {
fill->incReserve(topData.count() + 2);
@@ -81,9 +79,9 @@
// A set of scrolling line plots with the area between each plot filled. Stresses out GPU path
// filling
class ChartView : public Sample {
- static constexpr int kNumGraphs = 5;
- static constexpr int kPixelsPerTick = 3;
- static constexpr int kShiftPerFrame = 1;
+ inline static constexpr int kNumGraphs = 5;
+ inline static constexpr int kPixelsPerTick = 3;
+ inline static constexpr int kShiftPerFrame = 1;
int fShift = 0;
SkISize fSize = {-1, -1};
SkTDArray<SkScalar> fData[kNumGraphs];
@@ -102,7 +100,7 @@
SkScalar height = SkIntToScalar(fSize.fHeight);
if (sizeChanged) {
- int dataPointCount = SkMax32(fSize.fWidth / kPixelsPerTick + 1, 2);
+ int dataPointCount = std::max(fSize.fWidth / kPixelsPerTick + 1, 2);
for (int i = 0; i < kNumGraphs; ++i) {
SkScalar y = (kNumGraphs - i) * (height - ySpread) / (kNumGraphs + 1);
@@ -121,9 +119,6 @@
}
}
- SkPath plotPath;
- SkPath fillPath;
-
static const SkScalar kStrokeWidth = SkIntToScalar(2);
SkPaint plotPaint;
SkPaint fillPaint;
@@ -135,7 +130,9 @@
fillPaint.setAntiAlias(true);
fillPaint.setStyle(SkPaint::kFill_Style);
+ SkPathBuilder plotPath, fillPath;
SkTDArray<SkScalar>* prevData = nullptr;
+
for (int i = 0; i < kNumGraphs; ++i) {
gen_paths(fData[i],
prevData,
@@ -148,10 +145,10 @@
// Make the fills partially transparent
fillPaint.setColor((gColors[i] & 0x00ffffff) | 0x80000000);
- canvas->drawPath(fillPath, fillPaint);
+ canvas->drawPath(fillPath.detach(), fillPaint);
plotPaint.setColor(gColors[i]);
- canvas->drawPath(plotPath, plotPaint);
+ canvas->drawPath(plotPath.detach(), plotPaint);
prevData = fData + i;
}
diff --git a/third_party/skia/samplecode/SampleChineseFling.cpp b/third_party/skia/samplecode/SampleChineseFling.cpp
index 1cdf784..0e62725 100644
--- a/third_party/skia/samplecode/SampleChineseFling.cpp
+++ b/third_party/skia/samplecode/SampleChineseFling.cpp
@@ -17,8 +17,8 @@
#include "include/utils/SkRandom.h"
#if SK_SUPPORT_GPU
-#include "include/gpu/GrContext.h"
-#include "src/gpu/GrContextPriv.h"
+#include "include/gpu/GrDirectContext.h"
+#include "src/gpu/GrDirectContextPriv.h"
#endif
static sk_sp<SkTypeface> chinese_typeface() {
@@ -38,8 +38,8 @@
}
class ChineseFlingView : public Sample {
- static constexpr int kNumBlobs = 200;
- static constexpr int kWordLength = 16;
+ inline static constexpr int kNumBlobs = 200;
+ inline static constexpr int kWordLength = 16;
sk_sp<SkTypeface> fTypeface;
SkFontMetrics fMetrics;
@@ -103,8 +103,8 @@
};
class ChineseZoomView : public Sample {
- static constexpr int kNumBlobs = 8;
- static constexpr int kParagraphLength = 175;
+ inline static constexpr int kNumBlobs = 8;
+ inline static constexpr int kParagraphLength = 175;
bool fAfterFirstFrame = false;
sk_sp<SkTypeface> fTypeface;
@@ -137,24 +137,28 @@
if (fAfterFirstFrame) {
#if SK_SUPPORT_GPU
- GrContext* grContext = canvas->getGrContext();
- if (grContext) {
- sk_sp<SkImage> image = grContext->priv().testingOnly_getFontAtlasImage(
+ auto direct = GrAsDirectContext(canvas->recordingContext());
+ if (direct) {
+ sk_sp<SkImage> image = direct->priv().testingOnly_getFontAtlasImage(
GrMaskFormat::kA8_GrMaskFormat, 0);
canvas->drawImageRect(image,
- SkRect::MakeXYWH(10.0f, 10.0f, 512.0f, 512.0), &paint);
- image = grContext->priv().testingOnly_getFontAtlasImage(
+ SkRect::MakeXYWH(10.0f, 10.0f, 512.0f, 512.0),
+ SkSamplingOptions(), &paint);
+ image = direct->priv().testingOnly_getFontAtlasImage(
GrMaskFormat::kA8_GrMaskFormat, 1);
canvas->drawImageRect(image,
- SkRect::MakeXYWH(522.0f, 10.0f, 512.f, 512.0f), &paint);
- image = grContext->priv().testingOnly_getFontAtlasImage(
+ SkRect::MakeXYWH(522.0f, 10.0f, 512.f, 512.0f),
+ SkSamplingOptions(), &paint);
+ image = direct->priv().testingOnly_getFontAtlasImage(
GrMaskFormat::kA8_GrMaskFormat, 2);
canvas->drawImageRect(image,
- SkRect::MakeXYWH(10.0f, 522.0f, 512.0f, 512.0f), &paint);
- image = grContext->priv().testingOnly_getFontAtlasImage(
+ SkRect::MakeXYWH(10.0f, 522.0f, 512.0f, 512.0f),
+ SkSamplingOptions(), &paint);
+ image = direct->priv().testingOnly_getFontAtlasImage(
GrMaskFormat::kA8_GrMaskFormat, 3);
canvas->drawImageRect(image,
- SkRect::MakeXYWH(522.0f, 522.0f, 512.0f, 512.0f), &paint);
+ SkRect::MakeXYWH(522.0f, 522.0f, 512.0f, 512.0f),
+ SkSamplingOptions(), &paint);
}
#endif
}
@@ -191,7 +195,7 @@
auto paragraphLength = kParagraphLength;
SkScalar y = 0;
while (paragraphLength - 45 > 0) {
- auto currentLineLength = SkTMin(45, paragraphLength - 45);
+ auto currentLineLength = std::min(45, paragraphLength - 45);
this->createRandomLine(glyphs, currentLineLength);
ToolUtils::add_to_text_blob_w_len(&builder,
diff --git a/third_party/skia/samplecode/SampleCircle.cpp b/third_party/skia/samplecode/SampleCircle.cpp
index c4126f9..3cd7c0b 100644
--- a/third_party/skia/samplecode/SampleCircle.cpp
+++ b/third_party/skia/samplecode/SampleCircle.cpp
@@ -35,7 +35,7 @@
paint.setStrokeWidth(SkIntToScalar(width));
}
canvas->drawCircle(0, 0, 9.0f, paint);
- if (false) { // avoid bit rot, suppress warning
+ if ((false)) { // avoid bit rot, suppress warning
test_circlebounds(canvas);
}
}
diff --git a/third_party/skia/samplecode/SampleClip.cpp b/third_party/skia/samplecode/SampleClip.cpp
index bff7704..358e3f8 100644
--- a/third_party/skia/samplecode/SampleClip.cpp
+++ b/third_party/skia/samplecode/SampleClip.cpp
@@ -9,10 +9,11 @@
#include "include/core/SkColorPriv.h"
#include "include/core/SkFont.h"
#include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
#include "include/utils/SkRandom.h"
#include "samplecode/Sample.h"
-#include "src/core/SkClipOpPriv.h"
+#include "src/core/SkPathPriv.h"
+#include "tools/Resources.h"
constexpr int W = 150;
constexpr int H = 200;
@@ -37,7 +38,6 @@
for (int i = 0; i < 50; ++i) {
SkRect r;
- SkPath p;
r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
rand.nextUScalar1() * W, rand.nextUScalar1() * H);
@@ -47,8 +47,7 @@
r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
rand.nextUScalar1() * W, rand.nextUScalar1() * H);
paint.setColor(rand.nextU());
- p.addOval(r);
- canvas->drawPath(p, paint);
+ canvas->drawOval(r, paint);
}
}
@@ -66,7 +65,6 @@
for (int i = 0; i < n; ++i) {
SkRect r;
- SkPath p;
r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
rand.nextUScalar1() * W, rand.nextUScalar1() * H);
@@ -76,8 +74,7 @@
r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
rand.nextUScalar1() * W, rand.nextUScalar1() * H);
paint.setColor(rand.nextU());
- p.addOval(r);
- canvas->drawPath(p, paint);
+ canvas->drawOval(r, paint);
const SkScalar minx = -SkIntToScalar(W)/4;
const SkScalar maxx = 5*SkIntToScalar(W)/4;
@@ -112,9 +109,8 @@
};
SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
- SkPath clipPath;
r.inset(SK_Scalar1 / 4, SK_Scalar1 / 4);
- clipPath.addRoundRect(r, SkIntToScalar(20), SkIntToScalar(20));
+ SkPath clipPath = SkPathBuilder().addRRect(SkRRect::MakeRectXY(r, 20, 20)).detach();
// clipPath.toggleInverseFillType();
@@ -122,7 +118,7 @@
canvas->save();
for (size_t i = 0; i < SK_ARRAY_COUNT(gProc); ++i) {
canvas->save();
- canvas->clipPath(clipPath, kIntersect_SkClipOp, SkToBool(aa));
+ canvas->clipPath(clipPath, SkClipOp::kIntersect, SkToBool(aa));
// canvas->drawColor(SK_ColorWHITE);
gProc[i](canvas, SkToBool(aa));
canvas->restore();
@@ -211,7 +207,7 @@
#include "src/core/SkEdgeClipper.h"
-static void clip(const SkPath& path, SkPoint p0, SkPoint p1, SkPath* clippedPath) {
+static SkPath clip(const SkPath& path, SkPoint p0, SkPoint p1) {
SkMatrix mx, inv;
SkVector v = p1 - p0;
mx.setAll(v.fX, -v.fY, p0.fX,
@@ -226,9 +222,9 @@
SkRect clip = {-big, 0, big, big };
struct Rec {
- SkPath* fResult;
- SkPoint fPrev;
- } rec = { clippedPath, {0, 0} };
+ SkPathBuilder fResult;
+ SkPoint fPrev = {0, 0};
+ } rec;
SkEdgeClipper::ClipPath(rotated, clip, false,
[](SkEdgeClipper* clipper, bool newCtr, void* ctx) {
@@ -239,26 +235,26 @@
SkPath::Verb verb;
while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
if (newCtr) {
- rec->fResult->moveTo(pts[0]);
+ rec->fResult.moveTo(pts[0]);
rec->fPrev = pts[0];
newCtr = false;
}
if (addLineTo || pts[0] != rec->fPrev) {
- rec->fResult->lineTo(pts[0]);
+ rec->fResult.lineTo(pts[0]);
}
switch (verb) {
case SkPath::kLine_Verb:
- rec->fResult->lineTo(pts[1]);
+ rec->fResult.lineTo(pts[1]);
rec->fPrev = pts[1];
break;
case SkPath::kQuad_Verb:
- rec->fResult->quadTo(pts[1], pts[2]);
+ rec->fResult.quadTo(pts[1], pts[2]);
rec->fPrev = pts[2];
break;
case SkPath::kCubic_Verb:
- rec->fResult->cubicTo(pts[1], pts[2], pts[3]);
+ rec->fResult.cubicTo(pts[1], pts[2], pts[3]);
rec->fPrev = pts[3];
break;
default: break;
@@ -267,27 +263,7 @@
}
}, &rec);
- rec.fResult->transform(mx);
-}
-
-// true means use clippedPath.
-// false means there was no clipping -- use the original path
-static bool clip(const SkPath& path, const SkHalfPlane& plane, SkPath* clippedPath) {
- switch (plane.test(path.getBounds())) {
- case SkHalfPlane::kAllPositive:
- return false;
- case SkHalfPlane::kMixed: {
- SkPoint pts[2];
- if (plane.twoPts(pts)) {
- clip(path, pts[0], pts[1], clippedPath);
- return true;
- }
- } break;
- default: break; // handled outside of the switch
- }
- // clipped out (or failed)
- clippedPath->reset();
- return true;
+ return rec.fResult.detach().makeTransform(mx);
}
static void draw_halfplane(SkCanvas* canvas, SkPoint p0, SkPoint p1, SkColor c) {
@@ -302,14 +278,21 @@
static SkPath make_path() {
SkRandom rand;
- auto rand_pt = [&rand]() { return SkPoint{rand.nextF() * 400, rand.nextF() * 400}; };
+ auto rand_pt = [&rand]() {
+ auto x = rand.nextF();
+ auto y = rand.nextF();
+ return SkPoint{x * 400, y * 400};
+ };
- SkPath path;
+ SkPathBuilder path;
for (int i = 0; i < 4; ++i) {
- path.moveTo(rand_pt()).quadTo(rand_pt(), rand_pt())
- .quadTo(rand_pt(), rand_pt()).lineTo(rand_pt());
+ SkPoint pts[6];
+ for (auto& p : pts) {
+ p = rand_pt();
+ }
+ path.moveTo(pts[0]).quadTo(pts[1], pts[2]).quadTo(pts[3], pts[4]).lineTo(pts[5]);
}
- return path;
+ return path.detach();
}
class HalfPlaneView : public Sample {
@@ -332,9 +315,7 @@
paint.setColor({0, 0, 0, 1}, nullptr);
- SkPath clippedPath;
- clip(fPath, fPts[0], fPts[1], &clippedPath);
- canvas->drawPath(clippedPath, paint);
+ canvas->drawPath(clip(fPath, fPts[0], fPts[1]), paint);
draw_halfplane(canvas, fPts[0], fPts[1], SK_ColorRED);
}
@@ -357,16 +338,16 @@
draw_halfplane(canvas, pts[0], pts[1], c);
}
-static void compute_half_planes(const SkMatrix& mx, SkScalar W, SkScalar H,
+static void compute_half_planes(const SkMatrix& mx, SkScalar width, SkScalar height,
SkHalfPlane planes[4]) {
SkScalar a = mx[0], b = mx[1], c = mx[2],
d = mx[3], e = mx[4], f = mx[5],
g = mx[6], h = mx[7], i = mx[8];
- planes[0] = { 2*g - 2*a/W, 2*h - 2*b/W, 2*i - 2*c/W };
- planes[1] = { 2*a/W, 2*b/W, 2*c/W };
- planes[2] = { 2*g - 2*d/H, 2*h - 2*e/H, 2*i - 2*f/H };
- planes[3] = { 2*d/H, 2*e/H, 2*f/H };
+ planes[0] = { 2*g - 2*a/width, 2*h - 2*b/width, 2*i - 2*c/width };
+ planes[1] = { 2*a/width, 2*b/width, 2*c/width };
+ planes[2] = { 2*g - 2*d/height, 2*h - 2*e/height, 2*i - 2*f/height };
+ planes[3] = { 2*d/height, 2*e/height, 2*f/height };
}
class HalfPlaneView2 : public Sample {
@@ -435,55 +416,78 @@
};
DEF_SAMPLE( return new HalfPlaneView2(); )
-#include "include/core/SkMatrix44.h"
-#include "include/utils/Sk3D.h"
-#include "tools/Resources.h"
-
-static SkMatrix44 inv(const SkMatrix44& m) {
- SkMatrix44 inverse;
+static SkM44 inv(const SkM44& m) {
+ SkM44 inverse;
SkAssertResult(m.invert(&inverse));
return inverse;
}
-#if 0 // Jim's general half-planes math
-static void half_planes(const SkMatrix44& m44, SkScalar W, SkScalar H, SkHalfPlane planes[6]) {
- float mx[16];
- m44.asColMajorf(mx);
-
- SkScalar a = mx[0], b = mx[4], /* c = mx[ 8], */ d = mx[12],
- e = mx[1], f = mx[5], /* g = mx[ 9], */ h = mx[13],
- i = mx[2], j = mx[6], /* k = mx[10], */ l = mx[14],
- m = mx[3], n = mx[7], /* o = mx[11], */ p = mx[15];
-
- a = 2*a/W - m; b = 2*b/W - n; d = 2*d/W - p;
- e = 2*e/H - m; f = 2*f/H - n; h = 2*h/H - p;
-// i = 2*i - m; j = 2*j - n; l = 2*l - p;
-
- planes[0] = { m - a, n - b, p - d }; // w - x
- planes[1] = { m + a, n + b, p + d }; // w + x
- planes[2] = { m - e, n - f, p - h }; // w - y
- planes[3] = { m + e, n + f, p + h }; // w + y
- planes[4] = { m - i, n - j, p - l }; // w - z
- planes[5] = { m + i, n + j, p + l }; // w + z
-}
-#endif
-
static SkHalfPlane half_plane_w0(const SkMatrix& m) {
return { m[SkMatrix::kMPersp0], m[SkMatrix::kMPersp1], m[SkMatrix::kMPersp2] - 0.05f };
}
-class HalfPlaneView3 : public Sample {
+class SampleCameraView : public Sample {
float fNear = 0.05f;
float fFar = 4;
float fAngle = SK_ScalarPI / 4;
- SkPoint3 fEye { 0, 0, 1.0f/tan(fAngle/2) - 1 };
- SkPoint3 fCOA { 0, 0, 0 };
- SkPoint3 fUp { 0, 1, 0 };
+ SkV3 fEye { 0, 0, 1.0f/tan(fAngle/2) - 1 };
+ SkV3 fCOA { 0, 0, 0 };
+ SkV3 fUp { 0, 1, 0 };
- SkMatrix44 fRot;
- SkPoint3 fTrans;
+ SkM44 fRot;
+ SkV3 fTrans;
+ void rotate(float x, float y, float z) {
+ SkM44 r;
+ if (x) {
+ r.setRotateUnit({1, 0, 0}, x);
+ } else if (y) {
+ r.setRotateUnit({0, 1, 0}, y);
+ } else {
+ r.setRotateUnit({0, 0, 1}, z);
+ }
+ fRot = r * fRot;
+ }
+
+public:
+ SkM44 get44(const SkRect& r) const {
+ SkScalar w = r.width();
+ SkScalar h = r.height();
+
+ SkM44 camera = SkM44::LookAt(fEye, fCOA, fUp),
+ perspective = SkM44::Perspective(fNear, fFar, fAngle),
+ translate = SkM44::Translate(fTrans.x, fTrans.y, fTrans.z),
+ viewport = SkM44::Translate(r.centerX(), r.centerY(), 0) *
+ SkM44::Scale(w*0.5f, h*0.5f, 1);
+
+ return viewport * perspective * camera * translate * fRot * inv(viewport);
+ }
+
+ bool onChar(SkUnichar uni) override {
+ float delta = SK_ScalarPI / 30;
+ switch (uni) {
+ case '8': this->rotate( delta, 0, 0); return true;
+ case '2': this->rotate(-delta, 0, 0); return true;
+ case '4': this->rotate(0, delta, 0); return true;
+ case '6': this->rotate(0, -delta, 0); return true;
+ case '-': this->rotate(0, 0, delta); return true;
+ case '+': this->rotate(0, 0, -delta); return true;
+
+ case 'i': fTrans.z += 0.1f; SkDebugf("z %g\n", fTrans.z); return true;
+ case 'k': fTrans.z -= 0.1f; SkDebugf("z %g\n", fTrans.z); return true;
+
+ case 'n': fNear += 0.1f; SkDebugf("near %g\n", fNear); return true;
+ case 'N': fNear -= 0.1f; SkDebugf("near %g\n", fNear); return true;
+ case 'f': fFar += 0.1f; SkDebugf("far %g\n", fFar); return true;
+ case 'F': fFar -= 0.1f; SkDebugf("far %g\n", fFar); return true;
+ default: break;
+ }
+ return false;
+ }
+};
+
+class HalfPlaneView3 : public SampleCameraView {
SkPath fPath;
sk_sp<SkShader> fShader;
bool fShowUnclipped = false;
@@ -493,37 +497,19 @@
void onOnceBeforeDraw() override {
fPath = make_path();
fShader = GetResourceAsImage("images/mandrill_128.png")
- ->makeShader(SkMatrix::MakeScale(3, 3));
+ ->makeShader(SkSamplingOptions(), SkMatrix::Scale(3, 3));
}
- void rotate(float x, float y, float z) {
- SkMatrix44 r;
- if (x) {
- r.setRotateAboutUnit(1, 0, 0, x);
- } else if (y) {
- r.setRotateAboutUnit(0, 1, 0, y);
- } else {
- r.setRotateAboutUnit(0, 0, 1, z);
+ bool onChar(SkUnichar uni) override {
+ switch (uni) {
+ case 'u': fShowUnclipped = !fShowUnclipped; return true;
+ default: break;
}
- fRot.postConcat(r);
- }
-
- SkMatrix44 get44() const {
- SkMatrix44 camera,
- perspective,
- translate,
- viewport;
-
- Sk3Perspective(&perspective, fNear, fFar, fAngle);
- Sk3LookAt(&camera, fEye, fCOA, fUp);
- translate.setTranslate(fTrans.fX, fTrans.fY, fTrans.fZ);
- viewport.setScale(200, 200, 1).postTranslate( 200, 200, 0);
-
- return viewport * perspective * camera * translate * fRot * inv(viewport);
+ return this->SampleCameraView::onChar(uni);
}
void onDrawContent(SkCanvas* canvas) override {
- SkMatrix mx = this->get44();
+ SkM44 mx = this->get44({0, 0, 400, 400});
SkPaint paint;
paint.setColor({0.75, 0.75, 0.75, 1});
@@ -540,11 +526,10 @@
canvas->restore();
}
- SkHalfPlane hpw = half_plane_w0(mx);
SkColor planeColor = SK_ColorBLUE;
SkPath clippedPath, *path = &fPath;
- if (clip(fPath, hpw, &clippedPath)) {
+ if (SkPathPriv::PerspectiveClip(fPath, mx.asM33(), &clippedPath)) {
path = &clippedPath;
planeColor = SK_ColorRED;
}
@@ -553,38 +538,97 @@
canvas->drawPath(*path, paint);
canvas->restore();
+ SkHalfPlane hpw = half_plane_w0(mx.asM33());
draw_halfplane(canvas, hpw, planeColor);
}
-
- bool onChar(SkUnichar uni) override {
- float delta = SK_ScalarPI / 30;
- switch (uni) {
- case '8': this->rotate( delta, 0, 0); return true;
- case '2': this->rotate(-delta, 0, 0); return true;
- case '4': this->rotate(0, delta, 0); return true;
- case '6': this->rotate(0, -delta, 0); return true;
- case '-': this->rotate(0, 0, delta); return true;
- case '+': this->rotate(0, 0, -delta); return true;
-
- case 'i': fTrans.fZ += 0.1f; SkDebugf("z %g\n", fTrans.fZ); return true;
- case 'k': fTrans.fZ -= 0.1f; SkDebugf("z %g\n", fTrans.fZ); return true;
-
- case 'n': fNear += 0.1f; SkDebugf("near %g\n", fNear); return true;
- case 'N': fNear -= 0.1f; SkDebugf("near %g\n", fNear); return true;
- case 'f': fFar += 0.1f; SkDebugf("far %g\n", fFar); return true;
- case 'F': fFar -= 0.1f; SkDebugf("far %g\n", fFar); return true;
-
- case 'u': fShowUnclipped = !fShowUnclipped; return true;
- default: break;
- }
- return false;
- }
- Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
- return nullptr;
- }
-
- bool onClick(Click* click) override {
- return false;
- }
};
DEF_SAMPLE( return new HalfPlaneView3(); )
+
+class HalfPlaneCoons : public SampleCameraView {
+ SkPoint fPatch[12];
+ SkColor fColors[4] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK };
+ SkPoint fTex[4] = {{0, 0}, {256, 0}, {256, 256}, {0, 256}};
+ sk_sp<SkShader> fShader;
+
+ bool fShowHandles = false;
+ bool fShowSkeleton = false;
+ bool fShowTex = false;
+
+ SkString name() override { return SkString("halfplane-coons"); }
+
+ void onOnceBeforeDraw() override {
+ fPatch[0] = { 0, 0 };
+ fPatch[1] = { 100, 0 };
+ fPatch[2] = { 200, 0 };
+ fPatch[3] = { 300, 0 };
+ fPatch[4] = { 300, 100 };
+ fPatch[5] = { 300, 200 };
+ fPatch[6] = { 300, 300 };
+ fPatch[7] = { 200, 300 };
+ fPatch[8] = { 100, 300 };
+ fPatch[9] = { 0, 300 };
+ fPatch[10] = { 0, 200 };
+ fPatch[11] = { 0, 100 };
+
+ fShader = GetResourceAsImage("images/mandrill_256.png")->makeShader(SkSamplingOptions());
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ SkPaint paint;
+
+ canvas->save();
+ canvas->concat(this->get44({0, 0, 300, 300}));
+
+ const SkPoint* tex = nullptr;
+ const SkColor* col = nullptr;
+ if (!fShowSkeleton) {
+ if (fShowTex) {
+ paint.setShader(fShader);
+ tex = fTex;
+ } else {
+ col = fColors;
+ }
+ }
+ canvas->drawPatch(fPatch, col, tex, SkBlendMode::kSrc, paint);
+ paint.setShader(nullptr);
+
+ if (fShowHandles) {
+ paint.setAntiAlias(true);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+ paint.setStrokeWidth(8);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 12, fPatch, paint);
+ paint.setColor(SK_ColorWHITE);
+ paint.setStrokeWidth(6);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 12, fPatch, paint);
+ }
+
+ canvas->restore();
+ }
+
+ Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
+ auto dist = [](SkPoint a, SkPoint b) { return (b - a).length(); };
+
+ const float tol = 15;
+ for (int i = 0; i < 12; ++i) {
+ if (dist({x,y}, fPatch[i]) <= tol) {
+ return new Click([this, i](Click* c) {
+ fPatch[i] = c->fCurr;
+ return true;
+ });
+ }
+ }
+ return nullptr;
+ }
+
+ bool onChar(SkUnichar uni) override {
+ switch (uni) {
+ case 'h': fShowHandles = !fShowHandles; return true;
+ case 'k': fShowSkeleton = !fShowSkeleton; return true;
+ case 't': fShowTex = !fShowTex; return true;
+ default: break;
+ }
+ return this->SampleCameraView::onChar(uni);
+ }
+
+};
+DEF_SAMPLE( return new HalfPlaneCoons(); )
diff --git a/third_party/skia/samplecode/SampleClipDrawMatch.cpp b/third_party/skia/samplecode/SampleClipDrawMatch.cpp
deleted file mode 100644
index bdbb54b..0000000
--- a/third_party/skia/samplecode/SampleClipDrawMatch.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 2015 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/SkPath.h"
-#include "include/core/SkRRect.h"
-#include "include/core/SkTime.h"
-#include "include/utils/SkInterpolator.h"
-#include "samplecode/Sample.h"
-
-// This slide tests out the match up between BW clipping and rendering. It can
-// draw a large rect through some clip geometry and draw the same geometry
-// normally. Which one is drawn first can be toggled. The pair of objects is translated
-// fractionally (via an animator) to expose snapping bugs. The key bindings are:
-// 1-9: the different geometries
-// t: toggle which is drawn first the clip or the normal geometry
-// f: flip-flops which corner the bottom AA clip rect occupies in the complex clip cases
-
-// The possible geometric combinations to test
-enum Geometry {
- kRect_Geometry,
- kRRect_Geometry,
- kCircle_Geometry,
- kConvexPath_Geometry,
- kConcavePath_Geometry,
- kRectAndRect_Geometry,
- kRectAndRRect_Geometry,
- kRectAndConvex_Geometry,
- kRectAndConcave_Geometry
-};
-
-// The basic rect used is [kMin,kMin]..[kMax,kMax]
-static const float kMin = 100.5f;
-static const float kMid = 200.0f;
-static const float kMax = 299.5f;
-
-// The translation applied to the base AA rect in the combination cases
-// (i.e., kRectAndRect through kRectAndConcave)
-static const float kXlate = 100.0f;
-
-SkRect create_rect(const SkPoint& offset) {
- SkRect r = SkRect::MakeLTRB(kMin, kMin, kMax, kMax);
- r.offset(offset);
- return r;
-}
-
-SkRRect create_rrect(const SkPoint& offset) {
- SkRRect rrect;
- rrect.setRectXY(create_rect(offset), 10, 10);
- return rrect;
-}
-
-SkRRect create_circle(const SkPoint& offset) {
- SkRRect circle;
- circle.setOval(create_rect(offset));
- return circle;
-}
-
-SkPath create_convex_path(const SkPoint& offset) {
- SkPath convexPath;
- convexPath.moveTo(kMin, kMin);
- convexPath.lineTo(kMax, kMax);
- convexPath.lineTo(kMin, kMax);
- convexPath.close();
- convexPath.offset(offset.fX, offset.fY);
- return convexPath;
-}
-
-SkPath create_concave_path(const SkPoint& offset) {
- SkPath concavePath;
- concavePath.moveTo(kMin, kMin);
- concavePath.lineTo(kMid, 105.0f);
- concavePath.lineTo(kMax, kMin);
- concavePath.lineTo(295.0f, kMid);
- concavePath.lineTo(kMax, kMax);
- concavePath.lineTo(kMid, 295.0f);
- concavePath.lineTo(kMin, kMax);
- concavePath.lineTo(105.0f, kMid);
- concavePath.close();
-
- concavePath.offset(offset.fX, offset.fY);
- return concavePath;
-}
-
-static void draw_normal_geom(SkCanvas* canvas, const SkPoint& offset, int geom, bool useAA) {
- SkPaint p;
- p.setAntiAlias(useAA);
- p.setColor(SK_ColorBLACK);
-
- switch (geom) {
- case kRect_Geometry: // fall thru
- case kRectAndRect_Geometry:
- canvas->drawRect(create_rect(offset), p);
- break;
- case kRRect_Geometry: // fall thru
- case kRectAndRRect_Geometry:
- canvas->drawRRect(create_rrect(offset), p);
- break;
- case kCircle_Geometry:
- canvas->drawRRect(create_circle(offset), p);
- break;
- case kConvexPath_Geometry: // fall thru
- case kRectAndConvex_Geometry:
- canvas->drawPath(create_convex_path(offset), p);
- break;
- case kConcavePath_Geometry: // fall thru
- case kRectAndConcave_Geometry:
- canvas->drawPath(create_concave_path(offset), p);
- break;
- }
-}
-
-class ClipDrawMatchView : public Sample {
- SkInterpolator fTrans;
- Geometry fGeom;
- bool fClipFirst = true;
- int fSign = 1;
- const double fStart = SkTime::GetMSecs();
-
-public:
- ClipDrawMatchView() : fTrans(2, 5), fGeom(kRect_Geometry) {}
-
-private:
- void onOnceBeforeDraw() override {
- SkScalar values[2];
-
- fTrans.setRepeatCount(999);
- values[0] = values[1] = 0;
- fTrans.setKeyFrame(0, GetMSecs() + 1000, values);
- values[1] = 1;
- fTrans.setKeyFrame(1, GetMSecs() + 2000, values);
- values[0] = values[1] = 1;
- fTrans.setKeyFrame(2, GetMSecs() + 3000, values);
- values[1] = 0;
- fTrans.setKeyFrame(3, GetMSecs() + 4000, values);
- values[0] = 0;
- fTrans.setKeyFrame(4, GetMSecs() + 5000, values);
- }
-
- SkString name() override { return SkString("ClipDrawMatch"); }
-
- bool onChar(SkUnichar uni) override {
- switch (uni) {
- case '1': fGeom = kRect_Geometry; return true;
- case '2': fGeom = kRRect_Geometry; return true;
- case '3': fGeom = kCircle_Geometry; return true;
- case '4': fGeom = kConvexPath_Geometry; return true;
- case '5': fGeom = kConcavePath_Geometry; return true;
- case '6': fGeom = kRectAndRect_Geometry; return true;
- case '7': fGeom = kRectAndRRect_Geometry; return true;
- case '8': fGeom = kRectAndConvex_Geometry; return true;
- case '9': fGeom = kRectAndConcave_Geometry; return true;
- case 'f': fSign = -fSign; return true;
- case 't': fClipFirst = !fClipFirst; return true;
- default: break;
- }
- return false;
- }
-
- void drawClippedGeom(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
-
- int count = canvas->save();
-
- switch (fGeom) {
- case kRect_Geometry:
- canvas->clipRect(create_rect(offset), useAA);
- break;
- case kRRect_Geometry:
- canvas->clipRRect(create_rrect(offset), useAA);
- break;
- case kCircle_Geometry:
- canvas->clipRRect(create_circle(offset), useAA);
- break;
- case kConvexPath_Geometry:
- canvas->clipPath(create_convex_path(offset), useAA);
- break;
- case kConcavePath_Geometry:
- canvas->clipPath(create_concave_path(offset), useAA);
- break;
- case kRectAndRect_Geometry: {
- SkRect r = create_rect(offset);
- r.offset(fSign * kXlate, fSign * kXlate);
- canvas->clipRect(r, true); // AA here forces shader clips
- canvas->clipRect(create_rect(offset), useAA);
- } break;
- case kRectAndRRect_Geometry: {
- SkRect r = create_rect(offset);
- r.offset(fSign * kXlate, fSign * kXlate);
- canvas->clipRect(r, true); // AA here forces shader clips
- canvas->clipRRect(create_rrect(offset), useAA);
- } break;
- case kRectAndConvex_Geometry: {
- SkRect r = create_rect(offset);
- r.offset(fSign * kXlate, fSign * kXlate);
- canvas->clipRect(r, true); // AA here forces shader clips
- canvas->clipPath(create_convex_path(offset), useAA);
- } break;
- case kRectAndConcave_Geometry: {
- SkRect r = create_rect(offset);
- r.offset(fSign * kXlate, fSign * kXlate);
- canvas->clipRect(r, true); // AA here forces shader clips
- canvas->clipPath(create_concave_path(offset), useAA);
- } break;
- }
-
- SkISize size = canvas->getBaseLayerSize();
- SkRect bigR = SkRect::MakeWH(SkIntToScalar(size.width()), SkIntToScalar(size.height()));
-
- SkPaint p;
- p.setColor(SK_ColorRED);
-
- canvas->drawRect(bigR, p);
- canvas->restoreToCount(count);
- }
-
- // Draw a big red rect through some clip geometry and also draw that same
- // geometry in black. The order in which they are drawn can be swapped.
- // This tests whether the clip and normally drawn geometry match up.
- void drawGeometry(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
- if (fClipFirst) {
- this->drawClippedGeom(canvas, offset, useAA);
- }
-
- draw_normal_geom(canvas, offset, fGeom, useAA);
-
- if (!fClipFirst) {
- this->drawClippedGeom(canvas, offset, useAA);
- }
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- SkScalar trans[2];
- fTrans.timeToValues(GetMSecs(), trans);
-
- SkPoint offset;
- offset.set(trans[0], trans[1]);
-
- int saveCount = canvas->save();
- this->drawGeometry(canvas, offset, false);
- canvas->restoreToCount(saveCount);
- }
-
- SkMSec GetMSecs() const {
- return static_cast<SkMSec>(SkTime::GetMSecs() - fStart);
- }
-};
-
-DEF_SAMPLE( return new ClipDrawMatchView(); )
diff --git a/third_party/skia/samplecode/SampleColorFilter.cpp b/third_party/skia/samplecode/SampleColorFilter.cpp
deleted file mode 100644
index 7f57a32..0000000
--- a/third_party/skia/samplecode/SampleColorFilter.cpp
+++ /dev/null
@@ -1,183 +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/SkPaint.h"
-#include "include/core/SkShader.h"
-#include "samplecode/Sample.h"
-#include "tools/ToolUtils.h"
-
-static int inflate5To8(int x) {
- return (x << 3) | (x >> 2);
-}
-
-static int trunc5(int x) {
- return x >> 3;
-}
-
-#define SK_R16_BITS 5
-
-#ifdef SK_DEBUG
-static int round5_slow(int x) {
- int orig = x & 7;
- int fake = x >> 5;
- int trunc = x >> 3;
-
- int diff = fake - orig;
-
- int bias = 0;
- if (diff > 4) {
- bias = -1;
- } else if (diff < -4) {
- bias = 1;
- }
- return trunc + bias;
-}
-#endif
-
-static int round5_fast(int x) {
- int result = x + 3 - (x >> 5) + (x >> 7);
- result >>= 3;
-#ifdef SK_DEBUG
- {
- int r2 = round5_slow(x);
- SkASSERT(r2 == result);
- }
-#endif
- return result;
-}
-
-static void test_5bits() {
- int e0 = 0;
- int e1 = 0;
- int e2 = 0;
- int ae0 = 0;
- int ae1 = 0;
- int ae2 = 0;
- for (int i = 0; i < 256; i++) {
- int t0 = trunc5(i);
- int t1 = round5_fast(i);
- int t2 = trunc5(i);
- int v0 = inflate5To8(t0);
- int v1 = inflate5To8(t1);
- int v2 = inflate5To8(t2);
- int err0 = i - v0;
- int err1 = i - v1;
- int err2 = i - v2;
- SkDebugf("--- %3d : trunc=%3d (%2d) round:%3d (%2d) \n"/*new:%d (%2d)\n"*/, i,
- v0, err0, v1, err1, v2, err2);
-
-
- e0 += err0;
- e1 += err1;
- e2 += err2;
- ae0 += SkAbs32(err0);
- ae1 += SkAbs32(err1);
- ae2 += SkAbs32(err2);
- }
- SkDebugf("--- trunc: %d %d round: %d %d new: %d %d\n", e0, ae0, e1, ae1, e2, ae2);
-}
-
-static SkBitmap createBitmap(int n) {
- SkBitmap bitmap;
- bitmap.allocN32Pixels(n, n);
- bitmap.eraseColor(SK_ColorTRANSPARENT);
-
- SkCanvas canvas(bitmap);
- SkRect r;
- r.setWH(SkIntToScalar(n), SkIntToScalar(n));
- r.inset(SK_Scalar1, SK_Scalar1);
-
- SkPaint paint;
- paint.setAntiAlias(true);
-
- paint.setColor(SK_ColorRED);
- canvas.drawOval(r, paint);
-
- r.inset(SK_Scalar1*n/4, SK_Scalar1*n/4);
- paint.setBlendMode(SkBlendMode::kSrc);
- paint.setColor(0x800000FF);
- canvas.drawOval(r, paint);
-
- return bitmap;
-}
-
-class ColorFilterView : public Sample {
- SkBitmap fBitmap;
- sk_sp<SkShader> fShader;
- enum {
- N = 64
- };
-
- void onOnceBeforeDraw() override {
- fBitmap = createBitmap(N);
- fShader = ToolUtils::create_checkerboard_shader(0xFFCCCCCC, 0xFFFFFFFF, 12);
-
- if (false) { // avoid bit rot, suppress warning
- test_5bits();
- }
- }
-
- SkString name() override { return SkString("ColorFilter"); }
-
- void onDrawBackground(SkCanvas* canvas) override {
- SkPaint paint;
- paint.setShader(fShader);
- canvas->drawPaint(paint);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- if (false) {
- SkPaint p;
- p.setAntiAlias(true);
- SkRect r = { 20.4f, 10, 20.6f, 20 };
- canvas->drawRect(r, p);
- r.setLTRB(30.9f, 10, 31.1f, 20);
- canvas->drawRect(r, p);
- return;
- }
-
- static const SkBlendMode gModes[] = {
- SkBlendMode::kClear,
- SkBlendMode::kSrc,
- SkBlendMode::kDst,
- SkBlendMode::kSrcOver,
- SkBlendMode::kDstOver,
- SkBlendMode::kSrcIn,
- SkBlendMode::kDstIn,
- SkBlendMode::kSrcOut,
- SkBlendMode::kDstOut,
- SkBlendMode::kSrcATop,
- SkBlendMode::kDstATop,
- SkBlendMode::kXor,
- SkBlendMode::kPlus,
- SkBlendMode::kModulate,
- };
-
- static const SkColor gColors[] = {
- 0xFF000000,
- 0x80000000,
- 0xFF00FF00,
- 0x8000FF00,
- 0x00000000,
- };
-
- float scale = 1.5f;
- SkPaint paint;
- canvas->translate(N / 8, N / 8);
-
- for (size_t y = 0; y < SK_ARRAY_COUNT(gColors); y++) {
- for (size_t x = 0; x < SK_ARRAY_COUNT(gModes); x++) {
- paint.setColorFilter(SkColorFilters::Blend(gColors[y], gModes[x]));
- canvas->drawBitmap(fBitmap, x * N * 1.25f, y * N * scale, &paint);
- }
- }
-
- }
-};
-
-DEF_SAMPLE( return new ColorFilterView(); )
diff --git a/third_party/skia/samplecode/SampleComplexClip.cpp b/third_party/skia/samplecode/SampleComplexClip.cpp
index d903148..64e7af5 100644
--- a/third_party/skia/samplecode/SampleComplexClip.cpp
+++ b/third_party/skia/samplecode/SampleComplexClip.cpp
@@ -9,7 +9,6 @@
#include "include/core/SkFont.h"
#include "include/core/SkPath.h"
#include "samplecode/Sample.h"
-#include "src/core/SkClipOpPriv.h"
class ComplexClipView : public Sample {
void onOnceBeforeDraw() override {
@@ -78,11 +77,8 @@
SkClipOp fOp;
const char* fName;
} gOps[] = { //extra spaces in names for measureText
- {kIntersect_SkClipOp, "Isect "},
- {kDifference_SkClipOp, "Diff " },
- {kUnion_SkClipOp, "Union "},
- {kXOR_SkClipOp, "Xor " },
- {kReverseDifference_SkClipOp, "RDiff "}
+ {SkClipOp::kIntersect, "Isect "},
+ {SkClipOp::kDifference, "Diff " },
};
canvas->translate(0, SkIntToScalar(40));
diff --git a/third_party/skia/samplecode/SampleCowboy.cpp b/third_party/skia/samplecode/SampleCowboy.cpp
index 6ba3177..2ed47cb 100644
--- a/third_party/skia/samplecode/SampleCowboy.cpp
+++ b/third_party/skia/samplecode/SampleCowboy.cpp
@@ -7,12 +7,13 @@
#include "include/core/SkTypes.h"
-#ifdef SK_XML
+#if defined(SK_ENABLE_SVG)
-#include "experimental/svg/model/SkSVGDOM.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkRect.h"
#include "include/core/SkStream.h"
+#include "modules/svg/include/SkSVGDOM.h"
+#include "modules/svg/include/SkSVGNode.h"
#include "samplecode/Sample.h"
#include "src/core/SkOSFile.h"
#include "src/utils/SkOSPath.h"
@@ -21,7 +22,7 @@
namespace {
class AnimatedSVGSample : public Sample {
- static constexpr auto kAnimationIterations = 5;
+ inline static constexpr auto kAnimationIterations = 5;
enum State {
kZoomIn,
kScroll,
@@ -47,13 +48,7 @@
}
SkMemoryStream svgStream(std::move(data));
- SkDOM xmlDom;
- if (!xmlDom.build(svgStream)) {
- SkDebugf("XML parsing failed: \"%s\"\n", fResource);
- return;
- }
-
- fDom = SkSVGDOM::MakeFromDOM(xmlDom);
+ fDom = SkSVGDOM::MakeFromStream(svgStream);
if (fDom) {
fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
}
@@ -61,12 +56,12 @@
void onDrawContent(SkCanvas* canvas) override {
if (fDom) {
- canvas->setMatrix(SkMatrix::MakeScale(3));
+ canvas->setMatrix(SkMatrix::Scale(3, 3));
canvas->clipRect(SkRect::MakeLTRB(0, 0, 400, 400));
switch (fState) {
case kZoomIn:
fDelta += 0.2f;
- canvas->concat(SkMatrix::MakeScale(fDelta));
+ canvas->scale(fDelta, fDelta);
break;
case kScroll:
if (fAnimationLoop > kAnimationIterations/2) {
@@ -74,12 +69,12 @@
} else {
fDelta -= 80.f;
}
- canvas->concat(SkMatrix::MakeScale(fDelta));
+ canvas->scale(fDelta, fDelta);
canvas->translate(fDelta, 0);
break;
case kZoomOut:
fDelta += 0.2f;
- canvas->concat(SkMatrix::MakeScale(fDelta));
+ canvas->scale(fDelta, fDelta);
break;
}
@@ -125,4 +120,4 @@
DEF_SAMPLE( return new AnimatedSVGSample("Cowboy.svg", "SampleCowboy"); )
-#endif // SK_XML
+#endif // defined(SK_ENABLE_SVG)
diff --git a/third_party/skia/samplecode/SampleCusp.cpp b/third_party/skia/samplecode/SampleCusp.cpp
index 28b1233..543a3a3 100644
--- a/third_party/skia/samplecode/SampleCusp.cpp
+++ b/third_party/skia/samplecode/SampleCusp.cpp
@@ -144,12 +144,14 @@
bool split;
path = cusp(pts, pp, split, 8000, .125);
auto debugOutCubic = [](const SkPoint* pts) {
- return false; // comment out to capture stream of cusp'd cubics in stdout
- SkDebugf("{{");
- for (int i = 0; i < 4; ++i) {
- SkDebugf("{0x%08x,0x%08x},", SkFloat2Bits(pts[i].fX), SkFloat2Bits(pts[i].fY));
+ if ((false)) { // enable to capture stream of cusp'd cubics in stdout
+ SkDebugf("{{");
+ for (int i = 0; i < 4; ++i) {
+ SkDebugf("{0x%08x,0x%08x},", SkFloat2Bits(pts[i].fX), SkFloat2Bits(pts[i].fY));
+ }
+ SkDebugf("}},\n");
}
- SkDebugf("}},\n");
+ return false;
};
if (split) {
debugOutCubic(&pp[0]);
@@ -162,7 +164,6 @@
// draw time to make it easier to guess when the bad cubic was drawn
std::string timeStr = std::to_string((float) (curTime - start) / 1000.f);
canvas->drawSimpleText(timeStr.c_str(), timeStr.size(), SkTextEncoding::kUTF8, 20, 20, SkFont(), SkPaint());
- SkDebugf("");
}
bool onAnimate(double nanos) override {
@@ -175,7 +176,7 @@
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new CuspView(); )
diff --git a/third_party/skia/samplecode/SampleDegenerateQuads.cpp b/third_party/skia/samplecode/SampleDegenerateQuads.cpp
index 3d48cec..e3ab138 100644
--- a/third_party/skia/samplecode/SampleDegenerateQuads.cpp
+++ b/third_party/skia/samplecode/SampleDegenerateQuads.cpp
@@ -8,12 +8,18 @@
#include "samplecode/Sample.h"
#include "src/gpu/geometry/GrQuad.h"
-#include "src/gpu/ops/GrQuadPerEdgeAA.h"
+#include "src/gpu/ops/QuadPerEdgeAA.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/effects/SkDashPathEffect.h"
#include "include/pathops/SkPathOps.h"
+#include "include/private/SkTPin.h"
+
+using VertexSpec = skgpu::v1::QuadPerEdgeAA::VertexSpec;
+using ColorType = skgpu::v1::QuadPerEdgeAA::ColorType;
+using Subset = skgpu::v1::QuadPerEdgeAA::Subset;
+using IndexBufferOption = skgpu::v1::QuadPerEdgeAA::IndexBufferOption;
// Draw a line through the two points, outset by a fixed length in screen space
static void draw_extended_line(SkCanvas* canvas, const SkPaint paint,
@@ -216,11 +222,11 @@
SkScalar coverage = bary[0] * c0 + bary[1] * c1 + bary[2] * c2;
if (coverage < 0.5f) {
// Check distances to domain
- SkScalar l = SkScalarPin(point.fX - geomDomain.fLeft, 0.f, 1.f);
- SkScalar t = SkScalarPin(point.fY - geomDomain.fTop, 0.f, 1.f);
- SkScalar r = SkScalarPin(geomDomain.fRight - point.fX, 0.f, 1.f);
- SkScalar b = SkScalarPin(geomDomain.fBottom - point.fY, 0.f, 1.f);
- coverage = SkMinScalar(coverage, l * t * r * b);
+ SkScalar l = SkTPin(point.fX - geomDomain.fLeft, 0.f, 1.f);
+ SkScalar t = SkTPin(point.fY - geomDomain.fTop, 0.f, 1.f);
+ SkScalar r = SkTPin(geomDomain.fRight - point.fX, 0.f, 1.f);
+ SkScalar b = SkTPin(geomDomain.fBottom - point.fY, 0.f, 1.f);
+ coverage = std::min(coverage, l * t * r * b);
}
return coverage;
}
@@ -406,10 +412,10 @@
void getTessellatedPoints(SkPoint inset[4], SkScalar insetCoverage[4], SkPoint outset[4],
SkScalar outsetCoverage[4], SkRect* domain) const {
// Fixed vertex spec for extracting the picture frame geometry
- static const GrQuadPerEdgeAA::VertexSpec kSpec =
- {GrQuad::Type::kGeneral, GrQuadPerEdgeAA::ColorType::kNone,
- GrQuad::Type::kAxisAligned, false, GrQuadPerEdgeAA::Domain::kNo,
- GrAAType::kCoverage, false, GrQuadPerEdgeAA::IndexBufferOption::kPictureFramed};
+ static const VertexSpec kSpec =
+ {GrQuad::Type::kGeneral, ColorType::kNone,
+ GrQuad::Type::kAxisAligned, false, Subset::kNo,
+ GrAAType::kCoverage, false, IndexBufferOption::kPictureFramed};
static const GrQuad kIgnored(SkRect::MakeEmpty());
GrQuadAAFlags flags = GrQuadAAFlags::kNone;
@@ -421,7 +427,7 @@
GrQuad quad = GrQuad::MakeFromSkQuad(fCorners, SkMatrix::I());
float vertices[56]; // 2 quads, with x, y, coverage, and geometry domain (7 floats x 8 vert)
- GrQuadPerEdgeAA::Tessellator tessellator(kSpec, (char*) vertices);
+ skgpu::v1::QuadPerEdgeAA::Tessellator tessellator(kSpec, (char*) vertices);
tessellator.append(&quad, nullptr, {1.f, 1.f, 1.f, 1.f},
SkRect::MakeEmpty(), flags);
@@ -448,7 +454,7 @@
*domain = {vertices[52], vertices[53], vertices[54], vertices[55]};
}
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
class DegenerateQuadSample::Click : public Sample::Click {
@@ -474,8 +480,8 @@
void drag(SkPoint* point) {
SkPoint delta = fCurr - fPrev;
*point += SkPoint::Make(delta.x() / kViewScale, delta.y() / kViewScale);
- point->fX = SkMinScalar(fOuterRect.fRight, SkMaxScalar(point->fX, fOuterRect.fLeft));
- point->fY = SkMinScalar(fOuterRect.fBottom, SkMaxScalar(point->fY, fOuterRect.fTop));
+ point->fX = std::min(fOuterRect.fRight, std::max(point->fX, fOuterRect.fLeft));
+ point->fY = std::min(fOuterRect.fBottom, std::max(point->fY, fOuterRect.fTop));
}
};
diff --git a/third_party/skia/samplecode/SampleDegenerateTwoPtRadials.cpp b/third_party/skia/samplecode/SampleDegenerateTwoPtRadials.cpp
index f26403e..f0c74be 100644
--- a/third_party/skia/samplecode/SampleDegenerateTwoPtRadials.cpp
+++ b/third_party/skia/samplecode/SampleDegenerateTwoPtRadials.cpp
@@ -73,7 +73,7 @@
private:
SkScalar fTime;
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleEffects.cpp b/third_party/skia/samplecode/SampleEffects.cpp
index f22aea1..5a49ded 100644
--- a/third_party/skia/samplecode/SampleEffects.cpp
+++ b/third_party/skia/samplecode/SampleEffects.cpp
@@ -86,9 +86,9 @@
}
protected:
- virtual SkString name() { return SkString("Effects"); }
+ SkString name() override { return SkString("Effects"); }
- virtual void onDrawContent(SkCanvas* canvas) {
+ void onDrawContent(SkCanvas* canvas) override {
canvas->scale(3, 3);
canvas->translate(10, 30);
for (size_t i = 0; i < SK_ARRAY_COUNT(fPaint); i++) {
@@ -98,7 +98,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleEmboss.cpp b/third_party/skia/samplecode/SampleEmboss.cpp
index beacecb..0c49a85 100644
--- a/third_party/skia/samplecode/SampleEmboss.cpp
+++ b/third_party/skia/samplecode/SampleEmboss.cpp
@@ -33,9 +33,9 @@
}
protected:
- virtual SkString name() { return SkString("Emboss"); }
+ SkString name() override { return SkString("Emboss"); }
- virtual void onDrawContent(SkCanvas* canvas) {
+ void onDrawContent(SkCanvas* canvas) override {
SkPaint paint;
paint.setAntiAlias(true);
@@ -51,7 +51,7 @@
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleFatBits.cpp b/third_party/skia/samplecode/SampleFatBits.cpp
index f1dcd29..f80fb25 100644
--- a/third_party/skia/samplecode/SampleFatBits.cpp
+++ b/third_party/skia/samplecode/SampleFatBits.cpp
@@ -21,7 +21,6 @@
#include "include/core/SkSurface.h"
#include "include/core/SkTypes.h"
#include "samplecode/Sample.h"
-#include "src/core/SkClipOpPriv.h"
#include "src/core/SkPointPriv.h"
#include "tools/ToolUtils.h"
@@ -172,7 +171,7 @@
SkCanvas* canvas = fMaxSurface->getCanvas();
canvas->save();
canvas->concat(fMatrix);
- fMinSurface->draw(canvas, 0, 0, nullptr);
+ fMinSurface->draw(canvas, 0, 0);
canvas->restore();
SkPaint paint;
@@ -271,7 +270,7 @@
fMinSurface->getCanvas()->save();
SkRect r = fClipRect;
r.inset(SK_Scalar1/3, SK_Scalar1/3);
- fMinSurface->getCanvas()->clipRect(r, kIntersect_SkClipOp, true);
+ fMinSurface->getCanvas()->clipRect(r, SkClipOp::kIntersect, true);
}
fMinSurface->getCanvas()->drawLine(pts[0], pts[1], paint);
if (fUseClip) {
@@ -284,7 +283,7 @@
fMatrix.mapPoints(pts, 2);
this->drawLineSkeleton(max, pts);
- fMaxSurface->draw(canvas, 0, 0, nullptr);
+ fMaxSurface->draw(canvas, 0, 0);
}
void FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
@@ -314,7 +313,7 @@
r.setBounds(pts, 2);
this->drawRectSkeleton(max, r);
- fMaxSurface->draw(canvas, 0, 0, nullptr);
+ fMaxSurface->draw(canvas, 0, 0);
}
void FatBits::drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]) {
@@ -356,7 +355,7 @@
fMatrix.mapPoints(pts, 3);
this->drawTriangleSkeleton(max, pts);
- fMaxSurface->draw(canvas, 0, 0, nullptr);
+ fMaxSurface->draw(canvas, 0, 0);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -382,7 +381,7 @@
fPts[0].set(1, 1);
fPts[1].set(5, 4);
fPts[2].set(2, 6);
- SkMatrix::MakeScale(SkIntToScalar(fZoom)).mapPoints(fPts, 3);
+ SkMatrix::Scale(fZoom, fZoom).mapPoints(fPts, 3);
fIsRect = false;
}
@@ -499,7 +498,7 @@
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleFillType.cpp b/third_party/skia/samplecode/SampleFillType.cpp
index 230f41b..7330549 100644
--- a/third_party/skia/samplecode/SampleFillType.cpp
+++ b/third_party/skia/samplecode/SampleFillType.cpp
@@ -25,7 +25,7 @@
}
protected:
- virtual SkString name() { return SkString("FillType"); }
+ SkString name() override{ return SkString("FillType"); }
void showPath(SkCanvas* canvas, int x, int y, SkPathFillType ft,
SkScalar scale, const SkPaint& paint) {
@@ -55,7 +55,7 @@
scale, paint);
}
- virtual void onDrawContent(SkCanvas* canvas) {
+ void onDrawContent(SkCanvas* canvas) override {
canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
SkPaint paint;
@@ -77,7 +77,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleFilter2.cpp b/third_party/skia/samplecode/SampleFilter2.cpp
deleted file mode 100644
index 453bfa7..0000000
--- a/third_party/skia/samplecode/SampleFilter2.cpp
+++ /dev/null
@@ -1,85 +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/SkFont.h"
-#include "include/core/SkString.h"
-#include "include/utils/SkTextUtils.h"
-#include "samplecode/DecodeFile.h"
-#include "samplecode/Sample.h"
-#include "tools/Resources.h"
-
-#include <vector>
-
-static const char* gNames[] = {
- "images/mandrill_512_q075.jpg",
- "images/dog.jpg",
-};
-
-struct Filter2View : public Sample {
- std::vector<SkBitmap> fBitmaps;
-
- void onOnceBeforeDraw() override {
- SkASSERT(fBitmaps.empty());
- fBitmaps.reserve(SK_ARRAY_COUNT(gNames) * 2);
- for (const char* name : gNames) {
- SkBitmap bitmap;
- (void)decode_file(GetResourceAsData(name), &bitmap);
- fBitmaps.push_back(std::move(bitmap));
- }
- for (const char* name : gNames) {
- SkBitmap bitmap;
- (void)decode_file(GetResourceAsData(name), &bitmap, kRGB_565_SkColorType);
- fBitmaps.push_back(std::move(bitmap));
- }
- this->setBGColor(SK_ColorGRAY);
- }
-
- SkString name() override { return SkString("Filter/Dither"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->translate(SkIntToScalar(10), SkIntToScalar(50));
-
- const SkScalar W = SkIntToScalar(fBitmaps[0].width() + 1);
- const SkScalar H = SkIntToScalar(fBitmaps[0].height() + 1);
- SkPaint paint;
-
- const SkScalar scale = 0.897917f;
- canvas->scale(SK_Scalar1, scale);
-
- for (int k = 0; k < 2; k++) {
- paint.setFilterQuality(k == 1 ? kLow_SkFilterQuality : kNone_SkFilterQuality);
- for (int j = 0; j < 2; j++) {
- paint.setDither(j == 1);
- for (int i = 0; i < (int)fBitmaps.size(); i++) {
- SkScalar x = (k * (int)fBitmaps.size() + j) * W;
- SkScalar y = i * H;
- x = SkScalarRoundToScalar(x);
- y = SkScalarRoundToScalar(y);
- canvas->drawBitmap(fBitmaps[i], x, y, &paint);
- SkFont font;
- font.setSize(SkIntToScalar(18));
- if (i == 0) {
- SkString s("dither=");
- s.appendS32(paint.isDither());
- s.append(" filter=");
- s.appendS32(paint.getFilterQuality() != kNone_SkFilterQuality);
- SkTextUtils::DrawString(canvas, s.c_str(), x + W/2, y - font.getSize(), font, SkPaint(),
- SkTextUtils::kCenter_Align);
- }
- if (k+j == 2) {
- SkString s;
- s.append(" depth=");
- s.appendS32(fBitmaps[i].colorType() == kRGB_565_SkColorType ? 16 : 32);
- SkTextUtils::DrawString(canvas, s.c_str(), x + W + SkIntToScalar(4), y + H/2, font, SkPaint());
- }
- }
- }
- }
- }
-};
-DEF_SAMPLE( return new Filter2View(); )
diff --git a/third_party/skia/samplecode/SampleFilterBounds.cpp b/third_party/skia/samplecode/SampleFilterBounds.cpp
new file mode 100644
index 0000000..682891c
--- /dev/null
+++ b/third_party/skia/samplecode/SampleFilterBounds.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "samplecode/Sample.h"
+
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkColor.h"
+#include "include/core/SkFont.h"
+#include "include/core/SkPaint.h"
+#include "include/core/SkPath.h"
+#include "include/core/SkPoint.h"
+#include "include/core/SkRect.h"
+#include "include/effects/SkDashPathEffect.h"
+#include "include/effects/SkGradientShader.h"
+#include "include/effects/SkImageFilters.h"
+
+#include "src/core/SkImageFilterTypes.h"
+#include "src/core/SkImageFilter_Base.h"
+#include "src/core/SkMatrixPriv.h"
+
+#include "tools/ToolUtils.h"
+
+static constexpr float kLineHeight = 16.f;
+static constexpr float kLineInset = 8.f;
+
+static float print_size(SkCanvas* canvas, const char* prefix, const SkIRect& rect,
+ float x, float y, const SkFont& font, const SkPaint& paint) {
+ canvas->drawString(prefix, x, y, font, paint);
+ y += kLineHeight;
+ SkString sz;
+ sz.appendf("%d x %d", rect.width(), rect.height());
+ canvas->drawString(sz, x, y, font, paint);
+ return y + kLineHeight;
+}
+
+static float print_info(SkCanvas* canvas,
+ const SkIRect& layerContentBounds,
+ const SkIRect& outputBounds,
+ const SkIRect& hintedOutputBounds,
+ const SkIRect& unhintedLayerBounds) {
+ SkFont font(nullptr, 12);
+ SkPaint text;
+ text.setAntiAlias(true);
+
+ float y = kLineHeight;
+
+ text.setColor(SK_ColorRED);
+ y = print_size(canvas, "Content (in layer)", layerContentBounds, kLineInset, y, font, text);
+ text.setColor(SK_ColorDKGRAY);
+ y = print_size(canvas, "Target (in device)", outputBounds, kLineInset, y, font, text);
+ text.setColor(SK_ColorBLUE);
+ y = print_size(canvas, "Output (w/ hint)", hintedOutputBounds, kLineInset, y, font, text);
+ text.setColor(SK_ColorGREEN);
+ y = print_size(canvas, "Input (w/ no hint)", unhintedLayerBounds, kLineInset, y, font, text);
+
+ return y;
+}
+
+static void print_label(SkCanvas* canvas, float x, float y, float value) {
+ SkFont font(nullptr, 12);
+ SkPaint text;
+ text.setAntiAlias(true);
+
+ SkString label;
+ label.printf("%.3f", value);
+
+ canvas->drawString(label, x, y + kLineHeight / 2.f, font, text);
+}
+
+static SkPaint line_paint(SkColor color, bool dashed = false) {
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setStrokeWidth(0.f);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setAntiAlias(true);
+ if (dashed) {
+ SkScalar dash[2] = {10.f, 10.f};
+ paint.setPathEffect(SkDashPathEffect::Make(dash, 2, 0.f));
+ }
+ return paint;
+}
+
+static SkPath create_axis_path(const SkRect& rect, float axisSpace) {
+ SkPath localSpace;
+ for (float y = rect.fTop + axisSpace; y <= rect.fBottom; y += axisSpace) {
+ localSpace.moveTo(rect.fLeft, y);
+ localSpace.lineTo(rect.fRight, y);
+ }
+ for (float x = rect.fLeft + axisSpace; x <= rect.fRight; x += axisSpace) {
+ localSpace.moveTo(x, rect.fTop);
+ localSpace.lineTo(x, rect.fBottom);
+ }
+ return localSpace;
+}
+
+static const SkColor4f kScaleGradientColors[] =
+ { { 0.05f, 0.0f, 6.f, 1.f }, // Severe downscaling, s < 1/8, log(s) < -3
+ { 0.6f, 0.6f, 0.8f, 0.6f }, // Okay downscaling, s < 1/2, log(s) < -1
+ { 1.f, 1.f, 1.f, 0.2f }, // No scaling, s = 1, log(s) = 0
+ { 0.95f, 0.6f, 0.5f, 0.6f }, // Okay upscaling, s > 2, log(s) > 1
+ { 0.8f, 0.1f, 0.f, 1.f } }; // Severe upscaling, s > 8, log(s) > 3
+static const SkScalar kLogScaleFactors[] = { -3.f, -1.f, 0.f, 1.f, 3.f };
+static const SkScalar kGradientStops[] = { 0.f, 0.33333f, 0.5f, 0.66667f, 1.f };
+static const int kStopCount = (int) SK_ARRAY_COUNT(kScaleGradientColors);
+
+static void draw_scale_key(SkCanvas* canvas, float y) {
+ SkRect key = SkRect::MakeXYWH(15.f, y + 30.f, 15.f, 100.f);
+ SkPoint pts[] = {{key.centerX(), key.fTop}, {key.centerX(), key.fBottom}};
+ sk_sp<SkShader> gradient = SkGradientShader::MakeLinear(
+ pts, kScaleGradientColors, nullptr, kGradientStops, kStopCount, SkTileMode::kClamp,
+ SkGradientShader::kInterpolateColorsInPremul_Flag, nullptr);
+ SkPaint keyPaint;
+ keyPaint.setShader(gradient);
+ canvas->drawRect(key, keyPaint);
+ for (int i = 0; i < kStopCount; ++i) {
+ print_label(canvas, key.fRight + 5.f, key.fTop + kGradientStops[i] * key.height(),
+ SkScalarPow(2.f, kLogScaleFactors[i]));
+ }
+}
+
+static void draw_scale_factors(SkCanvas* canvas, const skif::Mapping& mapping, const SkRect& rect) {
+ SkPoint testPoints[5];
+ testPoints[0] = {rect.centerX(), rect.centerY()};
+ rect.toQuad(testPoints + 1);
+ for (int i = 0; i < 5; ++i) {
+ float scale = SkMatrixPriv::DifferentialAreaScale(
+ mapping.deviceMatrix(),
+ SkPoint(mapping.paramToLayer(skif::ParameterSpace<SkPoint>(testPoints[i]))));
+ SkColor4f color = {0.f, 0.f, 0.f, 1.f};
+
+ if (SkScalarIsFinite(scale)) {
+ float logScale = SkScalarLog2(scale);
+ for (int j = 0; j <= kStopCount; ++j) {
+ if (j == kStopCount) {
+ color = kScaleGradientColors[j - 1];
+ break;
+ } else if (kLogScaleFactors[j] >= logScale) {
+ if (j == 0) {
+ color = kScaleGradientColors[0];
+ } else {
+ SkScalar t = (logScale - kLogScaleFactors[j - 1]) /
+ (kLogScaleFactors[j] - kLogScaleFactors[j - 1]);
+
+ SkColor4f a = kScaleGradientColors[j - 1] * (1.f - t);
+ SkColor4f b = kScaleGradientColors[j] * t;
+ color = {a.fR + b.fR, a.fG + b.fG, a.fB + b.fB, a.fA + b.fA};
+ }
+ break;
+ }
+ }
+ }
+
+ SkPaint p;
+ p.setAntiAlias(true);
+ p.setColor4f(color, nullptr);
+ canvas->drawRect(SkRect::MakeLTRB(testPoints[i].fX - 4.f, testPoints[i].fY - 4.f,
+ testPoints[i].fX + 4.f, testPoints[i].fY + 4.f), p);
+ }
+}
+
+class FilterBoundsSample : public Sample {
+public:
+ FilterBoundsSample() {}
+
+ void onOnceBeforeDraw() override {
+ fBlur = SkImageFilters::Blur(8.f, 8.f, nullptr);
+ fImage = ToolUtils::create_checkerboard_image(
+ 300, 300, SK_ColorMAGENTA, SK_ColorLTGRAY, 50);
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ // The local content, e.g. what would be submitted to drawRect or the bounds to saveLayer
+ const SkRect localContentRect = SkRect::MakeLTRB(100.f, 20.f, 180.f, 140.f);
+ SkMatrix ctm = canvas->getLocalToDeviceAs3x3();
+
+ // Base rendering of a filter
+ SkPaint blurPaint;
+ blurPaint.setImageFilter(fBlur);
+ canvas->saveLayer(&localContentRect, &blurPaint);
+ canvas->drawImageRect(fImage.get(), localContentRect, localContentRect,
+ SkSamplingOptions(SkFilterMode::kLinear),
+ nullptr, SkCanvas::kFast_SrcRectConstraint);
+ canvas->restore();
+
+ // Now visualize the underlying bounds calculations used to determine the layer for the blur
+ SkIRect target = ctm.mapRect(localContentRect).roundOut();
+ if (!target.intersect(SkIRect::MakeWH(canvas->imageInfo().width(),
+ canvas->imageInfo().height()))) {
+ return;
+ }
+ skif::DeviceSpace<SkIRect> targetOutput(target);
+ skif::ParameterSpace<SkRect> contentBounds(localContentRect);
+ skif::ParameterSpace<SkPoint> contentCenter({localContentRect.centerX(),
+ localContentRect.centerY()});
+ skif::Mapping mapping;
+ SkAssertResult(mapping.decomposeCTM(ctm, fBlur.get(), contentCenter));
+
+ // Add axis lines, to show perspective distortion
+ canvas->save();
+ canvas->setMatrix(mapping.deviceMatrix());
+ canvas->drawPath(create_axis_path(SkRect(mapping.paramToLayer(contentBounds)), 20.f),
+ line_paint(SK_ColorGRAY));
+ canvas->restore();
+
+ // Visualize scale factors at the four corners and center of the local rect
+ draw_scale_factors(canvas, mapping, localContentRect);
+
+ // The device content rect, e.g. the clip bounds if 'localContentRect' were used as a clip
+ // before the draw or saveLayer, representing what the filter must cover if it affects
+ // transparent black or doesn't have a local content hint.
+ canvas->setMatrix(SkMatrix::I());
+ canvas->drawRect(ctm.mapRect(localContentRect), line_paint(SK_ColorDKGRAY));
+
+ // Layer bounds for the filter, in the layer space compatible with the filter's matrix
+ // type requirements.
+ skif::LayerSpace<SkIRect> targetOutputInLayer = mapping.deviceToLayer(targetOutput);
+ skif::LayerSpace<SkIRect> hintedLayerBounds = as_IFB(fBlur)->getInputBounds(
+ mapping, targetOutput, &contentBounds);
+ skif::LayerSpace<SkIRect> unhintedLayerBounds = as_IFB(fBlur)->getInputBounds(
+ mapping, targetOutput, nullptr);
+
+ canvas->setMatrix(mapping.deviceMatrix());
+ canvas->drawRect(SkRect::Make(SkIRect(targetOutputInLayer)),
+ line_paint(SK_ColorDKGRAY, true));
+ canvas->drawRect(SkRect::Make(SkIRect(hintedLayerBounds)), line_paint(SK_ColorRED));
+ canvas->drawRect(SkRect::Make(SkIRect(unhintedLayerBounds)), line_paint(SK_ColorGREEN));
+
+ // For visualization purposes, we want to show the layer-space output, this is what we get
+ // when contentBounds is provided as a hint in local/parameter space.
+ skif::Mapping layerOnly{mapping.layerMatrix()};
+ skif::DeviceSpace<SkIRect> hintedOutputBounds = as_IFB(fBlur)->getOutputBounds(
+ layerOnly, contentBounds);
+ canvas->drawRect(SkRect::Make(SkIRect(hintedOutputBounds)), line_paint(SK_ColorBLUE));
+
+ canvas->resetMatrix();
+ float y = print_info(canvas, SkIRect(mapping.paramToLayer(contentBounds).roundOut()),
+ SkIRect(targetOutput),
+ SkIRect(hintedOutputBounds),
+ SkIRect(unhintedLayerBounds));
+
+ // Draw color key for layer visualization
+ draw_scale_key(canvas, y);
+ }
+
+ SkString name() override { return SkString("FilterBounds"); }
+
+private:
+ sk_sp<SkImageFilter> fBlur;
+ sk_sp<SkImage> fImage;
+
+ using INHERITED = Sample;
+};
+
+DEF_SAMPLE(return new FilterBoundsSample();)
diff --git a/third_party/skia/samplecode/SampleFilterQuality.cpp b/third_party/skia/samplecode/SampleFilterQuality.cpp
deleted file mode 100644
index f18a1a6..0000000
--- a/third_party/skia/samplecode/SampleFilterQuality.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright 2015 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/SkData.h"
-#include "include/core/SkFont.h"
-#include "include/core/SkPath.h"
-#include "include/core/SkSurface.h"
-#include "include/core/SkTime.h"
-#include "include/effects/SkGradientShader.h"
-#include "include/utils/SkInterpolator.h"
-#include "include/utils/SkRandom.h"
-#include "samplecode/Sample.h"
-#include "tools/Resources.h"
-#include "tools/timer/TimeUtils.h"
-
-static sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
- auto surface = canvas->makeSurface(info);
- if (!surface) {
- surface = SkSurface::MakeRaster(info);
- }
- return surface;
-}
-
-static sk_sp<SkShader> make_shader(const SkRect& bounds) {
- sk_sp<SkImage> image(GetResourceAsImage("images/mandrill_128.png"));
- return image ? image->makeShader() : nullptr;
-}
-
-#define N 128
-#define ANGLE_DELTA 3
-#define SCALE_DELTA (SK_Scalar1 / 32)
-
-static sk_sp<SkImage> make_image() {
- SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
- auto surface(SkSurface::MakeRaster(info));
- SkCanvas* canvas = surface->getCanvas();
- canvas->drawColor(SK_ColorWHITE);
-
- SkPath path;
- path.setFillType(SkPathFillType::kEvenOdd);
-
- path.addRect(SkRect::MakeWH(N/2, N));
- path.addRect(SkRect::MakeWH(N, N/2));
- path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
-
- SkPaint paint;
- paint.setShader(make_shader(SkRect::MakeWH(N, N)));
-
- canvas->drawPath(path, paint);
- return surface->makeImageSnapshot();
-}
-
-static sk_sp<SkImage> zoom_up(SkSurface* origSurf, SkImage* orig) {
- const SkScalar S = 16; // amount to scale up
- const int D = 2; // dimension scaling for the offscreen
- // since we only view the center, don't need to produce the entire thing
-
- SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
- kOpaque_SkAlphaType);
- auto surface(origSurf->makeSurface(info));
- SkCanvas* canvas = surface->getCanvas();
- canvas->drawColor(SK_ColorWHITE);
- canvas->scale(S, S);
- canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
- -SkScalarHalf(orig->height()) * (S - D) / S);
- canvas->drawImage(orig, 0, 0, nullptr);
-
- if (S > 3) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- for (int i = 1; i < orig->height(); ++i) {
- SkScalar y = SkIntToScalar(i);
- canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
- }
- for (int i = 1; i < orig->width(); ++i) {
- SkScalar x = SkIntToScalar(i);
- canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
- }
- }
- return surface->makeImageSnapshot();
-}
-
-struct AnimValue {
- SkScalar fValue;
- SkScalar fMin;
- SkScalar fMax;
- SkScalar fMod;
-
- operator SkScalar() const { return fValue; }
-
- void set(SkScalar value, SkScalar min, SkScalar max) {
- fValue = value;
- fMin = min;
- fMax = max;
- fMod = 0;
- }
-
- void setMod(SkScalar value, SkScalar mod) {
- fValue = value;
- fMin = 0;
- fMax = 0;
- fMod = mod;
- }
-
- SkScalar inc(SkScalar delta) {
- fValue += delta;
- return this->fixUp();
- }
-
- SkScalar fixUp() {
- if (fMod) {
- fValue = SkScalarMod(fValue, fMod);
- } else {
- if (fValue > fMax) {
- fValue = fMax;
- } else if (fValue < fMin) {
- fValue = fMin;
- }
- }
- return fValue;
- }
-};
-
-static void draw_box_frame(SkCanvas* canvas, int width, int height) {
- SkPaint p;
- p.setStyle(SkPaint::kStroke_Style);
- p.setColor(SK_ColorRED);
- SkRect r = SkRect::MakeIWH(width, height);
- r.inset(0.5f, 0.5f);
- canvas->drawRect(r, p);
- canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
- canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
-}
-
-class FilterQualityView : public Sample {
- sk_sp<SkImage> fImage;
- AnimValue fScale, fAngle;
- SkSize fCell;
- SkInterpolator fTrans;
- SkMSec fCurrTime;
- bool fShowFatBits;
-
-public:
- FilterQualityView() : fTrans(2, 2), fShowFatBits(true) {
- fCell.set(256, 256);
-
- fScale.set(1, SK_Scalar1 / 8, 1);
- fAngle.setMod(0, 360);
-
- SkScalar values[2];
- fTrans.setMirror(true);
- fTrans.setReset(true);
-
- fCurrTime = 0;
-
- fTrans.setRepeatCount(999);
- values[0] = values[1] = 0;
- fTrans.setKeyFrame(0, fCurrTime, values);
- values[0] = values[1] = 1;
- fTrans.setKeyFrame(1, fCurrTime + 2000, values);
- }
-
-protected:
- SkString name() override { return SkString("FilterQuality"); }
-
- bool onChar(SkUnichar uni) override {
- switch (uni) {
- case '1': fAngle.inc(-ANGLE_DELTA); return true;
- case '2': fAngle.inc( ANGLE_DELTA); return true;
- case '3': fScale.inc(-SCALE_DELTA); return true;
- case '4': fScale.inc( SCALE_DELTA); return true;
- case '5': fShowFatBits = !fShowFatBits; return true;
- default: break;
- }
- return false;
- }
-
- void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
- SkScalar dx, SkScalar dy) {
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setFilterQuality(filter);
-
- SkAutoCanvasRestore acr(canvas, true);
-
- canvas->translate(dx, dy);
-
- canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
- canvas->scale(fScale, fScale);
- canvas->rotate(fAngle);
- canvas->drawImage(fImage.get(), -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
- &paint);
-
- if (false) {
- acr.restore();
- draw_box_frame(canvas, size.width(), size.height());
- }
- }
-
- void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
- SkCanvas* origCanvas = canvas;
- SkAutoCanvasRestore acr(canvas, true);
-
- SkISize size = SkISize::Make(fImage->width(), fImage->height());
-
- sk_sp<SkSurface> surface;
- if (fShowFatBits) {
- // scale up so we don't clip rotations
- SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
- kOpaque_SkAlphaType);
- surface = make_surface(canvas, info);
- canvas = surface->getCanvas();
- canvas->drawColor(SK_ColorWHITE);
- size.set(info.width(), info.height());
- } else {
- canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
- SkScalarHalf(fCell.height() - fImage->height()));
- }
- this->drawTheImage(canvas, size, filter, dx, dy);
-
- if (surface) {
- sk_sp<SkImage> orig(surface->makeImageSnapshot());
- sk_sp<SkImage> zoomed(zoom_up(surface.get(), orig.get()));
- origCanvas->drawImage(zoomed.get(),
- SkScalarHalf(fCell.width() - zoomed->width()),
- SkScalarHalf(fCell.height() - zoomed->height()));
- }
- }
-
- void drawBorders(SkCanvas* canvas) {
- SkPaint p;
- p.setStyle(SkPaint::kStroke_Style);
- p.setColor(SK_ColorBLUE);
-
- SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
- r.inset(SK_ScalarHalf, SK_ScalarHalf);
- canvas->drawRect(r, p);
- canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
- canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
- }
-
- void onOnceBeforeDraw() override {
- fImage = make_image();
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- fCell.set(this->height() / 2, this->height() / 2);
-
- SkScalar trans[2];
- fTrans.timeToValues(fCurrTime, trans);
-
- for (int y = 0; y < 2; ++y) {
- for (int x = 0; x < 2; ++x) {
- int index = y * 2 + x;
- SkAutoCanvasRestore acr(canvas, true);
- canvas->translate(fCell.width() * x, fCell.height() * y);
- SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
- r.inset(4, 4);
- canvas->clipRect(r);
- this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
- }
- }
-
- this->drawBorders(canvas);
-
- const SkScalar textX = fCell.width() * 2 + 30;
-
- SkFont font(nullptr, 36);
- SkPaint paint;
- canvas->drawString(SkStringPrintf("%.8g", (float)fScale), textX, 100, font, paint);
- canvas->drawString(SkStringPrintf("%.8g", (float)fAngle), textX, 150, font, paint);
- canvas->drawString(SkStringPrintf("%.8g", trans[0] ), textX, 200, font, paint);
- canvas->drawString(SkStringPrintf("%.8g", trans[1] ), textX, 250, font, paint);
- }
-
- bool onAnimate(double nanos) override {
- fCurrTime = TimeUtils::NanosToMSec(nanos);
- return true;
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new FilterQualityView(); )
diff --git a/third_party/skia/samplecode/SampleFitCubicToCircle.cpp b/third_party/skia/samplecode/SampleFitCubicToCircle.cpp
new file mode 100644
index 0000000..84042e5
--- /dev/null
+++ b/third_party/skia/samplecode/SampleFitCubicToCircle.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "samplecode/Sample.h"
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkFont.h"
+#include "include/core/SkPaint.h"
+#include "include/core/SkPath.h"
+#include <tuple>
+
+// Math constants are not always defined.
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338327950288
+#endif
+
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880168872420969808
+#endif
+
+constexpr static int kCenterX = 300;
+constexpr static int kCenterY = 325;
+constexpr static int kRadius = 250;
+
+// This sample fits a cubic to the arc between two interactive points on a circle. It also finds the
+// T-coordinate of max error, and outputs it and its value in pixels. (It turns out that max error
+// always occurs at T=0.21132486540519.)
+//
+// Press 'E' to iteratively cut the arc in half and report the improvement in max error after each
+// halving. (It turns out that max error improves by exactly 64x on every halving.)
+class SampleFitCubicToCircle : public Sample {
+ SkString name() override { return SkString("FitCubicToCircle"); }
+ void onOnceBeforeDraw() override { this->fitCubic(); }
+ void fitCubic();
+ void onDrawContent(SkCanvas*) override;
+ Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
+ bool onClick(Sample::Click*) override;
+ bool onChar(SkUnichar) override;
+
+ // Coordinates of two points on the unit circle. These are the two endpoints of the arc we fit.
+ double fEndptsX[2] = {0, 1};
+ double fEndptsY[2] = {-1, 0};
+
+ // Fitted cubic and info, set by fitCubic().
+ double fControlLength; // Length of (p1 - p0) and/or (p3 - p2) in unit circle space.
+ double fMaxErrorT; // T value where the cubic diverges most from the true arc.
+ std::array<double, 4> fCubicX; // Screen space cubic control points.
+ std::array<double, 4> fCubicY;
+ double fMaxError; // Max error (in pixels) between the cubic and the screen-space arc.
+ double fTheta; // Angle of the arc. This is only used for informational purposes.
+ SkTArray<SkString> fInfoStrings;
+
+ class Click;
+};
+
+// Fits a cubic to an arc on the unit circle with endpoints (x0, y0) and (x1, y1). Using the
+// following 3 constraints, we arrive at the formula used in the method:
+//
+// 1) The endpoints and tangent directions at the endpoints must match the arc.
+// 2) The cubic must be symmetric (i.e., length(p1 - p0) == length(p3 - p2)).
+// 3) The height of the cubic must match the height of the arc.
+//
+// Returns the "control length", or length of (p1 - p0) and/or (p3 - p2).
+static float fit_cubic_to_unit_circle(double x0, double y0, double x1, double y1,
+ std::array<double, 4>* X, std::array<double, 4>* Y) {
+ constexpr static double kM = -4.0/3;
+ constexpr static double kA = 4*M_SQRT2/3;
+ double d = x0*x1 + y0*y1;
+ double c = (std::sqrt(1 + d) * kM + kA) / std::sqrt(1 - d);
+ *X = {x0, x0 - y0*c, x1 + y1*c, x1};
+ *Y = {y0, y0 + x0*c, y1 - x1*c, y1};
+ return c;
+}
+
+static double lerp(double x, double y, double T) {
+ return x + T*(y - x);
+}
+
+// Evaluates the cubic and 1st and 2nd derivatives at T.
+static std::tuple<double, double, double> eval_cubic(double x[], double T) {
+ // Use De Casteljau's algorithm for better accuracy and stability.
+ double ab = lerp(x[0], x[1], T);
+ double bc = lerp(x[1], x[2], T);
+ double cd = lerp(x[2], x[3], T);
+ double abc = lerp(ab, bc, T);
+ double bcd = lerp(bc, cd, T);
+ double abcd = lerp(abc, bcd, T);
+ return {abcd, 3 * (bcd - abc) /*1st derivative.*/, 6 * (cd - 2*bc + ab) /*2nd derivative.*/};
+}
+
+// Uses newton-raphson convergence to find the point where the provided cubic diverges most from the
+// unit circle. i.e., the point where the derivative of error == 0. For error we use:
+//
+// error = x^2 + y^2 - 1
+// error' = 2xx' + 2yy'
+// error'' = 2xx'' + 2yy'' + 2x'^2 + 2y'^2
+//
+double find_max_error_T(double cubicX[4], double cubicY[4]) {
+ constexpr static double kInitialT = .25;
+ double T = kInitialT;
+ for (int i = 0; i < 64; ++i) {
+ auto [x, dx, ddx] = eval_cubic(cubicX, T);
+ auto [y, dy, ddy] = eval_cubic(cubicY, T);
+ double dError = 2*(x*dx + y*dy);
+ double ddError = 2*(x*ddx + y*ddy + dx*dx + dy*dy);
+ T -= dError / ddError;
+ }
+ return T;
+}
+
+void SampleFitCubicToCircle::fitCubic() {
+ fInfoStrings.reset();
+
+ std::array<double, 4> X, Y;
+ // "Control length" is the length of (p1 - p0) and/or (p3 - p2) in unit circle space.
+ fControlLength = fit_cubic_to_unit_circle(fEndptsX[0], fEndptsY[0], fEndptsX[1], fEndptsY[1],
+ &X, &Y);
+ fInfoStrings.push_back().printf("control length=%0.14f", fControlLength);
+
+ fMaxErrorT = find_max_error_T(X.data(), Y.data());
+ fInfoStrings.push_back().printf("max error T=%0.14f", fMaxErrorT);
+
+ for (int i = 0; i < 4; ++i) {
+ fCubicX[i] = X[i] * kRadius + kCenterX;
+ fCubicY[i] = Y[i] * kRadius + kCenterY;
+ }
+ double errX = std::get<0>(eval_cubic(fCubicX.data(), fMaxErrorT)) - kCenterX;
+ double errY = std::get<0>(eval_cubic(fCubicY.data(), fMaxErrorT)) - kCenterY;
+ fMaxError = std::sqrt(errX*errX + errY*errY) - kRadius;
+ fInfoStrings.push_back().printf("max error=%.5gpx", fMaxError);
+
+ fTheta = std::atan2(fEndptsY[1], fEndptsX[1]) - std::atan2(fEndptsY[0], fEndptsX[0]);
+ fTheta = std::abs(fTheta * 180/M_PI);
+ if (fTheta > 180) {
+ fTheta = 360 - fTheta;
+ }
+ fInfoStrings.push_back().printf("(theta=%.2f)", fTheta);
+
+ SkDebugf("\n");
+ for (const SkString& infoString : fInfoStrings) {
+ SkDebugf("%s\n", infoString.c_str());
+ }
+}
+
+void SampleFitCubicToCircle::onDrawContent(SkCanvas* canvas) {
+ canvas->clear(SK_ColorBLACK);
+
+ SkPaint circlePaint;
+ circlePaint.setColor(0x80ffffff);
+ circlePaint.setStyle(SkPaint::kStroke_Style);
+ circlePaint.setStrokeWidth(0);
+ circlePaint.setAntiAlias(true);
+ canvas->drawArc(SkRect::MakeXYWH(kCenterX - kRadius, kCenterY - kRadius, kRadius * 2,
+ kRadius * 2), 0, 360, false, circlePaint);
+
+ SkPaint cubicPaint;
+ cubicPaint.setColor(SK_ColorGREEN);
+ cubicPaint.setStyle(SkPaint::kStroke_Style);
+ cubicPaint.setStrokeWidth(10);
+ cubicPaint.setAntiAlias(true);
+ SkPath cubicPath;
+ cubicPath.moveTo(fCubicX[0], fCubicY[0]);
+ cubicPath.cubicTo(fCubicX[1], fCubicY[1], fCubicX[2], fCubicY[2], fCubicX[3], fCubicY[3]);
+ canvas->drawPath(cubicPath, cubicPaint);
+
+ SkPaint endpointsPaint;
+ endpointsPaint.setColor(SK_ColorBLUE);
+ endpointsPaint.setStrokeWidth(8);
+ endpointsPaint.setAntiAlias(true);
+ SkPoint points[2] = {{(float)fCubicX[0], (float)fCubicY[0]},
+ {(float)fCubicX[3], (float)fCubicY[3]}};
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, points, endpointsPaint);
+
+ SkPaint textPaint;
+ textPaint.setColor(SK_ColorWHITE);
+ constexpr static float kInfoTextSize = 16;
+ SkFont font(nullptr, kInfoTextSize);
+ int infoY = 10 + kInfoTextSize;
+ for (const SkString& infoString : fInfoStrings) {
+ canvas->drawString(infoString.c_str(), 10, infoY, font, textPaint);
+ infoY += kInfoTextSize * 3/2;
+ }
+}
+
+class SampleFitCubicToCircle::Click : public Sample::Click {
+public:
+ Click(int ptIdx) : fPtIdx(ptIdx) {}
+
+ void doClick(SampleFitCubicToCircle* that) {
+ double dx = fCurr.fX - kCenterX;
+ double dy = fCurr.fY - kCenterY;
+ double l = std::sqrt(dx*dx + dy*dy);
+ that->fEndptsX[fPtIdx] = dx/l;
+ that->fEndptsY[fPtIdx] = dy/l;
+ if (that->fEndptsX[0] * that->fEndptsY[1] - that->fEndptsY[0] * that->fEndptsX[1] < 0) {
+ std::swap(that->fEndptsX[0], that->fEndptsX[1]);
+ std::swap(that->fEndptsY[0], that->fEndptsY[1]);
+ fPtIdx = 1 - fPtIdx;
+ }
+ that->fitCubic();
+ }
+
+private:
+ int fPtIdx;
+};
+
+Sample::Click* SampleFitCubicToCircle::onFindClickHandler(SkScalar x, SkScalar y,
+ skui::ModifierKey) {
+ double dx0 = x - fCubicX[0];
+ double dy0 = y - fCubicY[0];
+ double dx3 = x - fCubicX[3];
+ double dy3 = y - fCubicY[3];
+ if (dx0*dx0 + dy0*dy0 < dx3*dx3 + dy3*dy3) {
+ return new Click(0);
+ } else {
+ return new Click(1);
+ }
+}
+
+bool SampleFitCubicToCircle::onClick(Sample::Click* click) {
+ Click* myClick = (Click*)click;
+ myClick->doClick(this);
+ return true;
+}
+
+bool SampleFitCubicToCircle::onChar(SkUnichar unichar) {
+ if (unichar == 'E') {
+ constexpr static double kMaxErrorT = 0.21132486540519; // Always the same.
+ // Split the arc in half until error =~0, and report the improvement after each halving.
+ double lastError = -1;
+ for (double theta = fTheta; lastError != 0; theta /= 2) {
+ double rads = theta * M_PI/180;
+ std::array<double, 4> X, Y;
+ fit_cubic_to_unit_circle(1, 0, std::cos(rads), std::sin(rads), &X, &Y);
+ auto [x, dx, ddx] = eval_cubic(X.data(), kMaxErrorT);
+ auto [y, dy, ddy] = eval_cubic(Y.data(), kMaxErrorT);
+ double error = std::sqrt(x*x + y*y) * kRadius - kRadius;
+ if ((float)error <= 0) {
+ error = 0;
+ }
+ SkDebugf("%6.2f degrees: error= %10.5gpx", theta, error);
+ if (lastError > 0) {
+ SkDebugf(" (%17.14fx improvement)", lastError / error);
+ }
+ SkDebugf("\n");
+ lastError = error;
+ }
+ return true;
+ }
+ return false;
+}
+
+DEF_SAMPLE(return new SampleFitCubicToCircle;)
diff --git a/third_party/skia/samplecode/SampleFlutterAnimate.cpp b/third_party/skia/samplecode/SampleFlutterAnimate.cpp
index e3e53e0..48198bf 100644
--- a/third_party/skia/samplecode/SampleFlutterAnimate.cpp
+++ b/third_party/skia/samplecode/SampleFlutterAnimate.cpp
@@ -16,10 +16,6 @@
#include "samplecode/Sample.h"
#include "tools/timer/Timer.h"
-#if SK_SUPPORT_GPU
-#include "include/gpu/GrContext.h"
-#endif
-
// Create an animation of a bunch of letters that rotate in place. This is intended to stress
// the glyph atlas and test that we don't see corruption or bad slowdowns.
class FlutterAnimateView : public Sample {
@@ -37,7 +33,6 @@
void onDrawContent(SkCanvas* canvas) override {
SkFont font(fTypeface, 50);
SkPaint paint;
- paint.setFilterQuality(kMedium_SkFilterQuality);
// rough center of each glyph
static constexpr auto kMidX = 35;
@@ -79,7 +74,7 @@
}
}
- static constexpr double kDuration = 5.0;
+ inline static constexpr double kDuration = 5.0;
double fCurrTime;
double fResetTime;
SkRandom fRand;
@@ -91,10 +86,10 @@
SkScalar fEndRotation;
};
sk_sp<SkTypeface> fTypeface;
- static constexpr int kNumChars = 40;
+ inline static constexpr int kNumChars = 40;
AnimatedChar fChars[kNumChars];
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleFontCache.cpp b/third_party/skia/samplecode/SampleFontCache.cpp
deleted file mode 100644
index 9f39e9c..0000000
--- a/third_party/skia/samplecode/SampleFontCache.cpp
+++ /dev/null
@@ -1,133 +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/SkGraphics.h"
-#include "include/utils/SkRandom.h"
-#include "samplecode/Sample.h"
-
-#include <pthread.h>
-
-static void call_measure() {
- SkPaint paint;
- uint16_t text[32];
- SkRandom rand;
-
- paint.setAntiAlias(true);
- paint.setTextEncoding(SkTextEncoding::kUTF16);
- for (int j = 0; j < SK_ARRAY_COUNT(text); j++)
- text[j] = (uint16_t)((rand.nextU() & 0xFF) + 32);
-
- for (int i = 9; i < 36; i++) {
- SkFontMetrics m;
-
- paint.setTextSize(SkIntToScalar(i));
- paint.getFontMetrics(&m);
- paint.measureText(text, sizeof(text));
- }
-}
-
-static void call_draw(SkCanvas* canvas) {
- SkPaint paint;
- uint16_t text[32];
- SkRandom rand;
-
- paint.setAntiAlias(true);
- paint.setTextEncoding(SkTextEncoding::kUTF16);
- for (int j = 0; j < SK_ARRAY_COUNT(text); j++)
- text[j] = (uint16_t)((rand.nextU() & 0xFF) + 32);
-
- SkScalar x = SkIntToScalar(10);
- SkScalar y = SkIntToScalar(20);
-
- canvas->drawColor(SK_ColorWHITE);
- for (int i = 9; i < 36; i++)
- {
- SkFontMetrics m;
-
- paint.setTextSize(SkIntToScalar(i));
- paint.getFontMetrics(&m);
- canvas->drawText(text, sizeof(text), x, y, paint);
- y += m.fDescent - m.fAscent;
- }
-}
-
-static bool gDone;
-
-static void* measure_proc(void* context) {
- while (!gDone) {
- call_measure();
- }
- return nullptr;
-}
-
-static void* draw_proc(void* context) {
- SkBitmap* bm = (SkBitmap*)context;
- SkCanvas canvas(*bm);
-
- while (!gDone) {
- call_draw(&canvas);
- }
- return nullptr;
-}
-
-class FontCacheView : public Sample {
-public:
- enum { N = 4 };
-
- pthread_t fMThreads[N];
- pthread_t fDThreads[N];
- SkBitmap fBitmaps[N];
-
- FontCacheView() {
- gDone = false;
- for (int i = 0; i < N; i++) {
- int status;
-
- status = pthread_create(&fMThreads[i], nullptr, measure_proc, nullptr);
- SkASSERT(0 == status);
-
- fBitmaps[i].allocPixels(SkImageInfo::Make(320, 240,
- kRGB_565_SkColorType,
- kOpaque_SkAlphaType));
- status = pthread_create(&fDThreads[i], nullptr, draw_proc, &fBitmaps[i]);
- SkASSERT(0 == status);
- }
- this->setBGColor(0xFFDDDDDD);
- }
-
- virtual ~FontCacheView() {
- gDone = true;
- for (int i = 0; i < N; i++) {
- void* ret;
- int status = pthread_join(fMThreads[i], &ret);
- SkASSERT(0 == status);
- status = pthread_join(fDThreads[i], &ret);
- SkASSERT(0 == status);
- }
- }
-
-protected:
- SkString name() override { return SkString("FontCache"); }
-
- virtual void onDrawContent(SkCanvas* canvas) {
- SkScalar x = 0;
- SkScalar y = 0;
- for (int i = 0; i < N; i++) {
- canvas->drawBitmap(fBitmaps[i], x, y);
- x += SkIntToScalar(fBitmaps[i].width());
- }
- this->inval(nullptr);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-static Sample* MyFactory() { return new FontCacheView; }
-static SampleRegister reg(MyFactory);
diff --git a/third_party/skia/samplecode/SampleGlyphTransform.cpp b/third_party/skia/samplecode/SampleGlyphTransform.cpp
index 2260a1a..cd7191b 100644
--- a/third_party/skia/samplecode/SampleGlyphTransform.cpp
+++ b/third_party/skia/samplecode/SampleGlyphTransform.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
@@ -75,7 +75,7 @@
SkScalar fScale;
SkScalar fRotate;
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleGradients.cpp b/third_party/skia/samplecode/SampleGradients.cpp
index 9eb4e71..a101ec3 100644
--- a/third_party/skia/samplecode/SampleGradients.cpp
+++ b/third_party/skia/samplecode/SampleGradients.cpp
@@ -149,13 +149,13 @@
canvas->restore();
canvas->translate(0, SkIntToScalar(370));
- if (false) { // avoid bit rot, suppress warning
+ if ((false)) { // avoid bit rot, suppress warning
test_alphagradients(canvas);
}
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleHT.cpp b/third_party/skia/samplecode/SampleHT.cpp
deleted file mode 100644
index bec4a7d..0000000
--- a/third_party/skia/samplecode/SampleHT.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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 "include/core/SkCanvas.h"
-#include "include/core/SkDrawable.h"
-#include "include/core/SkPictureRecorder.h"
-#include "include/utils/SkInterpolator.h"
-#include "include/utils/SkRandom.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkPointPriv.h"
-#include "tools/timer/TimeUtils.h"
-
-const SkRect gUnitSquare = { -1, -1, 1, 1 };
-
-static void color_to_floats(SkColor c, SkScalar f[4]) {
- f[0] = SkIntToScalar(SkColorGetA(c));
- f[1] = SkIntToScalar(SkColorGetR(c));
- f[2] = SkIntToScalar(SkColorGetG(c));
- f[3] = SkIntToScalar(SkColorGetB(c));
-}
-
-static SkColor floats_to_color(const SkScalar f[4]) {
- return SkColorSetARGB(SkScalarRoundToInt(f[0]),
- SkScalarRoundToInt(f[1]),
- SkScalarRoundToInt(f[2]),
- SkScalarRoundToInt(f[3]));
-}
-
-static bool oval_contains(const SkRect& r, SkScalar x, SkScalar y) {
- SkMatrix m;
- m.setRectToRect(r, gUnitSquare, SkMatrix::kFill_ScaleToFit);
- SkPoint pt;
- m.mapXY(x, y, &pt);
- return SkPointPriv::LengthSqd(pt) <= 1;
-}
-
-static SkColor rand_opaque_color(uint32_t seed) {
- SkRandom rand(seed);
- return rand.nextU() | (0xFF << 24);
-}
-
-class HTDrawable : public SkDrawable {
- SkRect fR;
- SkColor fColor;
- SkInterpolator* fInterp;
- SkMSec fTime;
-
-public:
- HTDrawable(SkRandom& rand) {
- fR = SkRect::MakeXYWH(rand.nextRangeF(0, 640), rand.nextRangeF(0, 480),
- rand.nextRangeF(20, 200), rand.nextRangeF(20, 200));
- fColor = rand_opaque_color(rand.nextU());
- fInterp = nullptr;
- fTime = 0;
- }
-
- void spawnAnimation(SkMSec now) {
- this->setTime(now);
-
- delete fInterp;
- fInterp = new SkInterpolator(5, 3);
- SkScalar values[5];
- color_to_floats(fColor, values); values[4] = 0;
- fInterp->setKeyFrame(0, now, values);
- values[0] = 0; values[4] = 180;
- fInterp->setKeyFrame(1, now + 1000, values);
- color_to_floats(rand_opaque_color(fColor), values); values[4] = 360;
- fInterp->setKeyFrame(2, now + 2000, values);
-
- fInterp->setMirror(true);
- fInterp->setRepeatCount(3);
-
- this->notifyDrawingChanged();
- }
-
- bool hitTest(SkScalar x, SkScalar y) {
- return oval_contains(fR, x, y);
- }
-
- void setTime(SkMSec time) { fTime = time; }
-
- void onDraw(SkCanvas* canvas) override {
- SkAutoCanvasRestore acr(canvas, false);
-
- SkPaint paint;
- paint.setAntiAlias(true);
-
- if (fInterp) {
- SkScalar values[5];
- SkInterpolator::Result res = fInterp->timeToValues(fTime, values);
- fColor = floats_to_color(values);
-
- canvas->save();
- canvas->rotate(values[4], fR.centerX(), fR.centerY());
-
- switch (res) {
- case SkInterpolator::kFreezeEnd_Result:
- delete fInterp;
- fInterp = nullptr;
- break;
- default:
- break;
- }
- }
- paint.setColor(fColor);
- canvas->drawRect(fR, paint);
- }
-
- SkRect onGetBounds() override { return fR; }
-};
-
-class HTView : public Sample {
-public:
- enum {
- N = 50,
- W = 640,
- H = 480,
- };
-
- struct Rec {
- HTDrawable* fDrawable;
- };
- Rec fArray[N];
- sk_sp<SkDrawable> fRoot;
- SkMSec fTime;
-
- HTView() {
- SkRandom rand;
-
- SkPictureRecorder recorder;
- SkCanvas* canvas = recorder.beginRecording(SkRect::MakeWH(W, H));
- for (int i = 0; i < N; ++i) {
- fArray[i].fDrawable = new HTDrawable(rand);
- canvas->drawDrawable(fArray[i].fDrawable);
- fArray[i].fDrawable->unref();
- }
- fRoot = recorder.finishRecordingAsDrawable();
- }
-
-protected:
- SkString name() override { return SkString("HT"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawDrawable(fRoot.get());
- }
-
- bool onAnimate(double nanos) override {
- fTime = TimeUtils::NanosToMSec(nanos);
- for (int i = 0; i < N; ++i) {
- fArray[i].fDrawable->setTime(fTime);
- }
- return true;
- }
-
- Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
- // search backwards to find the top-most
- for (int i = N - 1; i >= 0; --i) {
- if (fArray[i].fDrawable->hitTest(x, y)) {
- fArray[i].fDrawable->spawnAnimation(fTime);
- break;
- }
- }
- return nullptr;
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new HTView(); )
diff --git a/third_party/skia/samplecode/SampleHairCurves.cpp b/third_party/skia/samplecode/SampleHairCurves.cpp
index 73a6aee..cdb8ed8 100644
--- a/third_party/skia/samplecode/SampleHairCurves.cpp
+++ b/third_party/skia/samplecode/SampleHairCurves.cpp
@@ -114,7 +114,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleHairModes.cpp b/third_party/skia/samplecode/SampleHairModes.cpp
index 5df28f5..6e05fbc 100644
--- a/third_party/skia/samplecode/SampleHairModes.cpp
+++ b/third_party/skia/samplecode/SampleHairModes.cpp
@@ -61,10 +61,8 @@
*bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF;
*bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC, 0xCC, 0xCC);
- SkMatrix m;
- m.setScale(SkIntToScalar(6), SkIntToScalar(6));
-
- return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, &m);
+ return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions(),
+ SkMatrix::Scale(6, 6));
}
class HairModesView : public Sample {
@@ -108,7 +106,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleHairline.cpp b/third_party/skia/samplecode/SampleHairline.cpp
deleted file mode 100644
index a43ac44..0000000
--- a/third_party/skia/samplecode/SampleHairline.cpp
+++ /dev/null
@@ -1,231 +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/SkBitmap.h"
-#include "include/core/SkCanvas.h"
-#include "include/core/SkColorFilter.h"
-#include "include/core/SkColorPriv.h"
-#include "include/core/SkGraphics.h"
-#include "include/core/SkPath.h"
-#include "include/core/SkRegion.h"
-#include "include/core/SkShader.h"
-#include "include/core/SkStream.h"
-#include "include/core/SkTime.h"
-#include "include/core/SkTypeface.h"
-#include "include/effects/SkCornerPathEffect.h"
-#include "include/effects/SkGradientShader.h"
-#include "include/private/SkTo.h"
-#include "include/utils/SkRandom.h"
-#include "samplecode/Sample.h"
-#include "src/utils/SkUTF.h"
-
-static SkRandom gRand;
-
-static void generate_pts(SkPoint pts[], int count, int w, int h) {
- for (int i = 0; i < count; i++) {
- pts[i].set(gRand.nextUScalar1() * 3 * w - SkIntToScalar(w),
- gRand.nextUScalar1() * 3 * h - SkIntToScalar(h));
- }
-}
-
-static bool check_zeros(const SkPMColor pixels[], int count, int skip) {
- for (int i = 0; i < count; i++) {
- if (*pixels) {
- return false;
- }
- pixels += skip;
- }
- return true;
-}
-
-static bool check_bitmap_margin(const SkBitmap& bm, int margin) {
- size_t rb = bm.rowBytes();
- for (int i = 0; i < margin; i++) {
- if (!check_zeros(bm.getAddr32(0, i), bm.width(), 1)) {
- return false;
- }
- int bottom = bm.height() - i - 1;
- if (!check_zeros(bm.getAddr32(0, bottom), bm.width(), 1)) {
- return false;
- }
- // left column
- if (!check_zeros(bm.getAddr32(i, 0), bm.height(), SkToInt(rb >> 2))) {
- return false;
- }
- int right = bm.width() - margin + i;
- if (!check_zeros(bm.getAddr32(right, 0), bm.height(),
- SkToInt(rb >> 2))) {
- return false;
- }
- }
- return true;
-}
-
-#define WIDTH 620
-#define HEIGHT 460
-#define MARGIN 10
-
-static void line_proc(SkCanvas* canvas, const SkPaint& paint,
- const SkBitmap& bm) {
- const int N = 2;
- SkPoint pts[N];
- for (int i = 0; i < 400; i++) {
- generate_pts(pts, N, WIDTH, HEIGHT);
-
- canvas->drawLine(pts[0], pts[1], paint);
- if (!check_bitmap_margin(bm, MARGIN)) {
- SkDebugf("---- hairline failure (%g %g) (%g %g)\n",
- pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
- break;
- }
- }
-}
-
-static void poly_proc(SkCanvas* canvas, const SkPaint& paint,
- const SkBitmap& bm) {
- const int N = 8;
- SkPoint pts[N];
- for (int i = 0; i < 50; i++) {
- generate_pts(pts, N, WIDTH, HEIGHT);
-
- SkPath path;
- path.moveTo(pts[0]);
- for (int j = 1; j < N; j++) {
- path.lineTo(pts[j]);
- }
- canvas->drawPath(path, paint);
- }
-}
-
-static SkPoint ave(const SkPoint& a, const SkPoint& b) {
- SkPoint c = a + b;
- c.fX = SkScalarHalf(c.fX);
- c.fY = SkScalarHalf(c.fY);
- return c;
-}
-
-static void quad_proc(SkCanvas* canvas, const SkPaint& paint,
- const SkBitmap& bm) {
- const int N = 30;
- SkPoint pts[N];
- for (int i = 0; i < 10; i++) {
- generate_pts(pts, N, WIDTH, HEIGHT);
-
- SkPath path;
- path.moveTo(pts[0]);
- for (int j = 1; j < N - 2; j++) {
- path.quadTo(pts[j], ave(pts[j], pts[j+1]));
- }
- path.quadTo(pts[N - 2], pts[N - 1]);
-
- canvas->drawPath(path, paint);
- }
-}
-
-static void add_cubic(SkPath* path, const SkPoint& mid, const SkPoint& end) {
- SkPoint start;
- path->getLastPt(&start);
- path->cubicTo(ave(start, mid), ave(mid, end), end);
-}
-
-static void cube_proc(SkCanvas* canvas, const SkPaint& paint,
- const SkBitmap& bm) {
- const int N = 30;
- SkPoint pts[N];
- for (int i = 0; i < 10; i++) {
- generate_pts(pts, N, WIDTH, HEIGHT);
-
- SkPath path;
- path.moveTo(pts[0]);
- for (int j = 1; j < N - 2; j++) {
- add_cubic(&path, pts[j], ave(pts[j], pts[j+1]));
- }
- add_cubic(&path, pts[N - 2], pts[N - 1]);
-
- canvas->drawPath(path, paint);
- }
-}
-
-typedef void (*HairProc)(SkCanvas*, const SkPaint&, const SkBitmap&);
-
-static const struct {
- const char* fName;
- HairProc fProc;
-} gProcs[] = {
- { "line", line_proc },
- { "poly", poly_proc },
- { "quad", quad_proc },
- { "cube", cube_proc },
-};
-
-static int cycle_hairproc_index(int index) {
- return (index + 1) % SK_ARRAY_COUNT(gProcs);
-}
-
-class HairlineView : public Sample {
- SkMSec fNow;
- int fProcIndex;
- bool fDoAA;
-public:
- HairlineView() {
- fProcIndex = 0;
- fDoAA = true;
- fNow = 0;
- }
-
-protected:
- SkString name() override { return SkStringPrintf("Hair-%s", gProcs[fProcIndex].fName); }
-
- void show_bitmaps(SkCanvas* canvas, const SkBitmap& b0, const SkBitmap& b1,
- const SkIRect& inset) {
- canvas->drawBitmap(b0, 0, 0, nullptr);
- canvas->drawBitmap(b1, SkIntToScalar(b0.width()), 0, nullptr);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- gRand.setSeed(fNow);
-
- SkBitmap bm, bm2;
- bm.allocN32Pixels(WIDTH + MARGIN*2, HEIGHT + MARGIN*2);
- // this will erase our margin, which we want to always stay 0
- bm.eraseColor(SK_ColorTRANSPARENT);
-
- bm2.installPixels(SkImageInfo::MakeN32Premul(WIDTH, HEIGHT),
- bm.getAddr32(MARGIN, MARGIN), bm.rowBytes());
-
- SkCanvas c2(bm2);
- SkPaint paint;
- paint.setAntiAlias(fDoAA);
- paint.setStyle(SkPaint::kStroke_Style);
-
- bm2.eraseColor(SK_ColorTRANSPARENT);
- gProcs[fProcIndex].fProc(&c2, paint, bm);
- canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), nullptr);
- }
-
- bool onAnimate(double /*nanos*/) override {
- if (fDoAA) {
- fProcIndex = cycle_hairproc_index(fProcIndex);
- // todo: signal that we want to rebuild our TITLE
- }
- fDoAA = !fDoAA;
- return true;
- }
-
- Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
- fDoAA = !fDoAA;
- return this->INHERITED::onFindClickHandler(x, y, modi);
- }
-
-
-private:
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new HairlineView(); )
diff --git a/third_party/skia/samplecode/SampleIdentityScale.cpp b/third_party/skia/samplecode/SampleIdentityScale.cpp
deleted file mode 100644
index 4e7b1dd..0000000
--- a/third_party/skia/samplecode/SampleIdentityScale.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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 "include/core/SkCanvas.h"
-#include "include/core/SkColorPriv.h"
-#include "include/core/SkFont.h"
-#include "include/core/SkPath.h"
-#include "include/core/SkStream.h"
-#include "include/core/SkTime.h"
-#include "include/effects/SkBlurMaskFilter.h"
-#include "include/utils/SkRandom.h"
-#include "samplecode/DecodeFile.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkClipOpPriv.h"
-#include "tools/Resources.h"
-
-// Intended to exercise pixel snapping observed with scaled images (and
-// with non-scaled images, but for a different reason): Bug 1145
-
-class IdentityScaleView : public Sample {
-public:
- IdentityScaleView(const char imageFilename[]) {
- if (!DecodeDataToBitmap(GetResourceAsData(imageFilename), &fBM)) {
- fBM.allocN32Pixels(1, 1);
- *(fBM.getAddr32(0,0)) = 0xFF0000FF; // red == bad
- }
- }
-
-protected:
- SkBitmap fBM;
-
- SkString name() override { return SkString("IdentityScale"); }
-
- void onDrawContent(SkCanvas* canvas) override {
-
- SkFont font(nullptr, 48);
- SkPaint paint;
-
- paint.setAntiAlias(true);
- paint.setFilterQuality(kHigh_SkFilterQuality);
-
- SkTime::DateTime time;
- SkTime::GetDateTime(&time);
-
- bool use_scale = (time.fSecond % 2 == 1);
- const char *text;
-
- canvas->save();
- if (use_scale) {
- text = "Scaled = 1";
- } else {
-
- SkRect r = { 100, 100, 356, 356 };
- SkPath clipPath;
- clipPath.addRoundRect(r, SkIntToScalar(5), SkIntToScalar(5));
- canvas->clipPath(clipPath, kIntersect_SkClipOp, true);
- text = "Scaled = 0";
- }
- canvas->drawBitmap( fBM, 100, 100, &paint );
- canvas->restore();
- canvas->drawString(text, 100, 400, font, paint);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new IdentityScaleView("images/mandrill_256.png"); )
diff --git a/third_party/skia/samplecode/SampleImageFilterDAG.cpp b/third_party/skia/samplecode/SampleImageFilterDAG.cpp
index 41340b6..3c925d1 100644
--- a/third_party/skia/samplecode/SampleImageFilterDAG.cpp
+++ b/third_party/skia/samplecode/SampleImageFilterDAG.cpp
@@ -42,224 +42,89 @@
int fDepth;
// The source content rect (this is the same for all nodes, but is stored here for convenience)
- SkRect fContent;
- // The portion of the original CTM that is kept as the local matrix/ctm when filtering
- SkMatrix fLocalCTM;
- // The portion of the original CTM that the results should be drawn with (or given current
- // canvas impl., the portion of the CTM that is baked into a new DAG)
- SkMatrix fRemainingCTM;
+ skif::ParameterSpace<SkRect> fContent;
+ // The mapping for the filter dag (same for all nodes, but stored here for convenience)
+ skif::Mapping fMapping;
- // Cached reverse bounds using device-space clip bounds (e.g. SkCanvas::clipRectBounds with
- // null first argument). This represents the layer calculated in SkCanvas for the filtering.
- // FIXME: SkCanvas (and this sample), this is seeded with the device-space clip bounds so that
- // the implicit matrix node's reverse bounds are updated appropriately when it recurses to the
- // original root node.
- SkIRect fLayerBounds;
+ // Cached reverse bounds using device-space clip bounds (e.g. no local bounds hint passed to
+ // saveLayer). This represents the layer calculated in SkCanvas for the filtering.
+ skif::LayerSpace<SkIRect> fUnhintedLayerBounds;
- // Cached reverse bounds using the local draw bounds (e.g. SkCanvas::clipRectBounds with the
- // draw bounds provided as first argument). For intermediate nodes in a DAG, this is calculated
- // to match what the filter would compute when being evaluated as part of the original DAG
- // (i.e. if the implicit matrix filter node were not inserted at the beginning).
- // fReverseLocalIsolatedBounds is the same, except it represents what would be calculated if
- // only this node were being applied as the image filter.
- SkIRect fReverseLocalBounds;
- SkIRect fReverseLocalIsolatedBounds;
+ // Cached input bounds using the local draw bounds (e.g. saveLayer with a bounds rect, or
+ // an auto-layer for a draw with image filter). This represents the layer bounds up to this
+ // point of the DAG.
+ skif::LayerSpace<SkIRect> fHintedLayerBounds;
- // Cached forward bounds based on local draw bounds. For intermediate nodes in a DAG, this is
- // calculated to match what the filter computes as part of the whole DAG. fForwardIsolatedBounds
- // is the same but represents what would be calculated if only this node were applied.
- SkIRect fForwardBounds;
- SkIRect fForwardIsolatedBounds;
+ // Cached output bounds based on local draw bounds. This represents the output up to this
+ // point of the DAG.
+ skif::LayerSpace<SkIRect> fOutputBounds;
- // Should be called after the input nodes have been created since this will complete the
- // entire tree.
- void computeBounds() {
- // In normal usage, forward bounds are filter-space bounds of the geometry content, so
- // fContent mapped by the local matrix, since we assume the layer content is made by
- // concat(localCTM) -> clipRect(content) -> drawRect(content).
- // Similarly, in normal usage, reverse bounds are the filter-space bounds of the space to
- // be filled by image filter results. Since the clip rect is set to the same as the content,
- // it's the same bounds forward or reverse in this contrived case.
- SkIRect inputRect;
- fLocalCTM.mapRect(fContent).roundOut(&inputRect);
-
- this->computeForwardBounds(inputRect);
-
- // The layer bounds (matching what SkCanvas computes), use the content rect mapped by the
- // entire CTM as its input rect. If this is an implicit matrix node, the computeReverseX
- // functions will switch to using the local-mapped bounds for children in order to simulate
- // what would happen if the last step were done as a draw. When there's no implicit matrix
- // node, this calculated rectangle is the same as inputRect.
- SkIRect deviceRect;
- SkMatrix ctm = SkMatrix::Concat(fRemainingCTM, fLocalCTM);
- ctm.mapRect(fContent).roundOut(&deviceRect);
-
- SkASSERT(this->isImplicitMatrixNode() || inputRect == deviceRect);
- this->computeReverseLocalIsolatedBounds(deviceRect);
- this->computeReverseBounds(deviceRect, false);
- // Unlike the above two calls, calculating layer bounds will keep the device bounds for
- // intermediate nodes to show the current SkCanvas behavior vs. the ideal
- this->computeReverseBounds(deviceRect, true);
- }
-
- bool isImplicitMatrixNode() const {
- // In the future we wish to replace the implicit matrix node with direct draws to the final
- // destination (instead of using an SkMatrixImageFilter). Visualizing the DAG correctly
- // requires handling these nodes differently since it has part of the canvas CTM built in.
- return fDepth == 1 && !fRemainingCTM.isIdentity();
+ FilterNode(const SkImageFilter* filter,
+ const skif::Mapping& mapping,
+ const skif::ParameterSpace<SkRect>& content,
+ int depth)
+ : fFilter(sk_ref_sp(filter))
+ , fDepth(depth)
+ , fContent(content)
+ , fMapping(mapping) {
+ this->computeInputBounds();
+ this->computeOutputBounds();
+ if (fFilter) {
+ fInputNodes.reserve_back(fFilter->countInputs());
+ for (int i = 0; i < fFilter->countInputs(); ++i) {
+ fInputNodes.emplace_back(fFilter->getInput(i), mapping, content, depth + 1);
+ }
+ }
}
private:
- void computeForwardBounds(const SkIRect srcRect) {
+ void computeOutputBounds() {
if (fFilter) {
- // For forward filtering, the leaves of the DAG are evaluated first and are then
- // propagated to the root. This means that every filter's filterBounds() function sees
- // the original src rect. It is never dependent on the parent node (unlike reverse
- // filtering), so calling filterBounds() on an intermediate node gives us the correct
- // intermediate values.
- fForwardBounds = fFilter->filterBounds(
- srcRect, fLocalCTM, SkImageFilter::kForward_MapDirection, nullptr);
-
- // For isolated forward filtering, it uses the same input but should not be propagated
- // to the inputs, so get the filter node bounds directly.
- fForwardIsolatedBounds = as_IFB(fFilter)->filterNodeBounds(
- srcRect, fLocalCTM, SkImageFilter::kForward_MapDirection, nullptr);
+ // For visualization purposes, we want the output bounds in layer space, before it's
+ // been transformed to device space. To achieve that, we mock a new mapping with the
+ // identity matrix transform.
+ skif::Mapping layerOnly{fMapping.layerMatrix()};
+ skif::DeviceSpace<SkIRect> pseudoDeviceBounds =
+ as_IFB(fFilter)->getOutputBounds(layerOnly, fContent);
+ // Since layerOnly's device matrix is I, this is effectively a cast to layer space
+ fOutputBounds = layerOnly.deviceToLayer(pseudoDeviceBounds);
} else {
- fForwardBounds = srcRect;
- fForwardIsolatedBounds = srcRect;
+ fOutputBounds = fMapping.paramToLayer(fContent).roundOut();
}
// Fill in children
for (int i = 0; i < fInputNodes.count(); ++i) {
- fInputNodes[i].computeForwardBounds(srcRect);
+ fInputNodes[i].computeOutputBounds();
}
}
- void computeReverseLocalIsolatedBounds(const SkIRect& srcRect) {
- if (fFilter) {
- fReverseLocalIsolatedBounds = as_IFB(fFilter)->filterNodeBounds(
- srcRect, fLocalCTM, SkImageFilter::kReverse_MapDirection, &srcRect);
- } else {
- fReverseLocalIsolatedBounds = srcRect;
- }
-
- SkIRect childSrcRect = srcRect;
- if (this->isImplicitMatrixNode()) {
- // Switch srcRect from the device-space bounds to what would be used when the draw is
- // the final step of filtering, as if the implicit node weren't needed
- fLocalCTM.mapRect(fContent).roundOut(&childSrcRect);
- }
-
- // Fill in children. Unlike regular reverse bounds mapping, the input nodes see the original
- // bounds. Normally, the bounds that the child nodes see have already been mapped processed
- // by this node.
- for (int i = 0; i < fInputNodes.count(); ++i) {
- fInputNodes[i].computeReverseLocalIsolatedBounds(childSrcRect);
- }
- }
-
- // fReverseLocalBounds and fLayerBounds are computed the same, except they differ in what the
- // initial bounding rectangle was. It is assumed that the 'srcRect' has already been processed
- // by the parent node's onFilterNodeBounds() function, as in SkImageFilter::filterBounds().
- void computeReverseBounds(const SkIRect& srcRect, bool writeToLayerBounds) {
- SkIRect reverseBounds = srcRect;
+ void computeInputBounds() {
+ // As a proxy for what the base device had, use the content rect mapped to device space
+ // (e.g. clipRect() was called with the same coords prior to the draw).
+ skif::DeviceSpace<SkIRect> targetOutput(fMapping.totalMatrix()
+ .mapRect(SkRect(fContent))
+ .roundOut());
if (fFilter) {
- // Since srcRect has been through parent's onFilterNodeBounds(), calling filterBounds()
- // directly on this node will calculate the same rectangle that this filter would report
- // during the parent node's onFilterBounds() recursion.
- reverseBounds = fFilter->filterBounds(
- srcRect, fLocalCTM, SkImageFilter::kReverse_MapDirection, &srcRect);
-
- SkIRect nextSrcRect;
- if (this->isImplicitMatrixNode() && !writeToLayerBounds) {
- // When not writing to the layer bounds, and we're the implicit matrix node
- // we reset the src rect to be what it should be if no implicit node was necessary.
- fLocalCTM.mapRect(fContent).roundOut(&nextSrcRect);
- } else {
- // To calculate the appropriate intermediate reverse bounds for the children, we
- // need this node's onFilterNodeBounds() results based on its parents' bounds (the
- // current 'srcRect').
- nextSrcRect = as_IFB(fFilter)->filterNodeBounds(
- srcRect, fLocalCTM, SkImageFilter::kReverse_MapDirection, &srcRect);
- }
-
- // Fill in the children. The union of these bounds should equal the value calculated
- // for reverseBounds already.
- SkDEBUGCODE(SkIRect netReverseBounds = SkIRect::MakeEmpty();)
- for (int i = 0; i < fInputNodes.count(); ++i) {
- fInputNodes[i].computeReverseBounds(nextSrcRect, writeToLayerBounds);
- SkDEBUGCODE(netReverseBounds.join(
- writeToLayerBounds ? fInputNodes[i].fLayerBounds
- : fInputNodes[i].fReverseLocalBounds);)
- }
- // Because of the resetting done when not computing layer bounds for the implicit
- // matrix node, this assertion doesn't hold in that particular scenario.
- SkASSERT(netReverseBounds == reverseBounds ||
- (this->isImplicitMatrixNode() && !writeToLayerBounds));
- }
-
- if (writeToLayerBounds) {
- fLayerBounds = reverseBounds;
+ fHintedLayerBounds = as_IFB(fFilter)->getInputBounds(fMapping, targetOutput, &fContent);
+ fUnhintedLayerBounds = as_IFB(fFilter)->getInputBounds(fMapping, targetOutput, nullptr);
} else {
- fReverseLocalBounds = reverseBounds;
+ fHintedLayerBounds = fMapping.paramToLayer(fContent).roundOut();
+ fUnhintedLayerBounds = fMapping.deviceToLayer(targetOutput);
}
}
};
} // anonymous namespace
-static FilterNode build_dag(const SkMatrix& local, const SkMatrix& remainder, const SkRect& rect,
- const SkImageFilter* filter, int depth) {
- FilterNode node;
- node.fFilter = sk_ref_sp(filter);
- node.fDepth = depth;
- node.fContent = rect;
-
- node.fLocalCTM = local;
- node.fRemainingCTM = remainder;
-
- if (node.fFilter) {
- if (depth > 0) {
- // We don't visit children when at the root because the real child filters are replaced
- // with the internalSaveLayer decomposition emulation, which then cycles back to the
- // original filter but with an updated matrix (and then we process the children).
- node.fInputNodes.reserve(node.fFilter->countInputs());
- for (int i = 0; i < node.fFilter->countInputs(); ++i) {
- node.fInputNodes.push_back() =
- build_dag(local, remainder, rect, node.fFilter->getInput(i), depth + 1);
- }
- }
- }
-
- return node;
-}
-
static FilterNode build_dag(const SkMatrix& ctm, const SkRect& rect,
const SkImageFilter* rootFilter) {
// Emulate SkCanvas::internalSaveLayer's decomposition of the CTM.
- SkMatrix local;
- sk_sp<SkImageFilter> finalFilter = as_IFB(rootFilter)->applyCTM(ctm, &local);
-
- // In ApplyCTMToFilter, the CTM is decomposed such that CTM = remainder * local. The matrix
- // that is embedded in 'finalFilter' is actually local^-1*remainder*local to account for
- // how SkMatrixImageFilter is specified, but we want the true remainder since it is what should
- // transform the results to put in the correct place after filtering.
- SkMatrix invLocal, remaining;
- if (as_IFB(rootFilter)->uniqueID() != as_IFB(finalFilter)->uniqueID()) {
- remaining = SkMatrix::Concat(ctm, invLocal);
- } else {
- remaining = SkMatrix::I();
- }
-
- // Create a root node that represents the full result
- FilterNode rootNode = build_dag(ctm, SkMatrix::I(), rect, rootFilter, 0);
- // Set its only child as the modified DAG that handles the CTM decomposition
- rootNode.fInputNodes.push_back() =
- build_dag(local, remaining, rect, finalFilter.get(), 1);
- // Fill in bounds information that requires the entire node DAG to have been extracted first.
- rootNode.fInputNodes[0].computeBounds();
- return rootNode;
+ skif::ParameterSpace<SkRect> content(rect);
+ skif::ParameterSpace<SkPoint> center({rect.centerX(), rect.centerY()});
+ skif::Mapping mapping;
+ SkAssertResult(mapping.decomposeCTM(ctm, rootFilter, center));
+ return FilterNode(rootFilter, mapping, content, 0);
}
static void draw_node(SkCanvas* canvas, const FilterNode& node) {
@@ -268,10 +133,11 @@
SkPaint filterPaint;
filterPaint.setImageFilter(node.fFilter);
+ SkRect content = SkRect(node.fContent);
SkPaint paint;
static const SkColor kColors[2] = {SK_ColorGREEN, SK_ColorWHITE};
- SkPoint points[2] = { {node.fContent.fLeft + 15.f, node.fContent.fTop + 15.f},
- {node.fContent.fRight - 15.f, node.fContent.fBottom - 15.f} };
+ SkPoint points[2] = { {content.fLeft + 15.f, content.fTop + 15.f},
+ {content.fRight - 15.f, content.fBottom - 15.f} };
paint.setShader(SkGradientShader::MakeLinear(points, kColors, nullptr, SK_ARRAY_COUNT(kColors),
SkTileMode::kRepeat));
@@ -279,77 +145,40 @@
line.setStrokeWidth(0.f);
line.setStyle(SkPaint::kStroke_Style);
- if (node.fDepth == 0) {
- // The root node, so draw this one the canonical way through SkCanvas to show current
- // net behavior. Will not include bounds visualization.
- canvas->save();
- canvas->concat(node.fLocalCTM);
- SkASSERT(node.fRemainingCTM.isIdentity());
+ canvas->save();
+ canvas->concat(node.fMapping.deviceMatrix());
+ canvas->save();
+ canvas->concat(node.fMapping.layerMatrix());
- canvas->clipRect(node.fContent, /* aa */ true);
- canvas->saveLayer(nullptr, &filterPaint);
- canvas->drawRect(node.fContent, paint);
- canvas->restore(); // Completes the image filter
- canvas->restore(); // Undoes matrix and clip
+ canvas->saveLayer(&content, &filterPaint);
+ canvas->drawRect(content, paint);
+ canvas->restore(); // Completes the image filter
- // Draw content rect (no clipping)
- canvas->save();
- canvas->concat(node.fLocalCTM);
- line.setColor(SK_ColorBLACK);
- canvas->drawRect(node.fContent, line);
- canvas->restore();
- } else {
- canvas->save();
- if (!node.isImplicitMatrixNode()) {
- canvas->concat(node.fRemainingCTM);
- }
- canvas->concat(node.fLocalCTM);
+ // Draw content-rect bounds
+ line.setColor(SK_ColorBLACK);
+ canvas->drawRect(content, line);
- canvas->saveLayer(nullptr, &filterPaint);
- canvas->drawRect(node.fContent, paint);
- canvas->restore(); // Completes the image filter
+ // Bounding boxes have all been mapped by the layer matrix from local to layer space, so undo
+ // the layer matrix, leaving just the device matrix.
+ canvas->restore();
- // Draw content-rect bounds
- line.setColor(SK_ColorBLACK);
- if (node.isImplicitMatrixNode()) {
- canvas->setMatrix(SkMatrix::Concat(node.fRemainingCTM, node.fLocalCTM));
- }
- canvas->drawRect(node.fContent, line);
- canvas->restore(); // Undoes the matrix
+ // The hinted bounds of the layer saved for the filtering
+ line.setColor(SK_ColorRED);
+ canvas->drawRect(SkRect::Make(SkIRect(node.fHintedLayerBounds)).makeOutset(3.f, 3.f), line);
+ // The bounds of the layer if there was no local content hint
+ line.setColor(SK_ColorGREEN);
+ canvas->drawRect(SkRect::Make(SkIRect(node.fUnhintedLayerBounds)).makeOutset(2.f, 2.f), line);
- // Bounding boxes have all been mapped by the local matrix already, so drawing them with
- // the remaining CTM should align everything to the already drawn filter outputs. The
- // exception is forward bounds of the implicit matrix node, which also have been mapped
- // by the remainder matrix.
- canvas->save();
- canvas->concat(node.fRemainingCTM);
-
- // The bounds of the layer saved for the filtering as currently implemented
- line.setColor(SK_ColorRED);
- canvas->drawRect(SkRect::Make(node.fLayerBounds).makeOutset(5.f, 5.f), line);
- // The bounds of the layer that could be saved if the last step were a draw
- line.setColor(SK_ColorMAGENTA);
- canvas->drawRect(SkRect::Make(node.fReverseLocalBounds).makeOutset(4.f, 4.f), line);
-
- // Dashed lines for the isolated shapes
- static const SkScalar kDashParams[] = {6.f, 12.f};
- line.setPathEffect(SkDashPathEffect::Make(kDashParams, 2, 0.f));
- // The bounds of the layer if it were the only filter in the DAG
- canvas->drawRect(SkRect::Make(node.fReverseLocalIsolatedBounds).makeOutset(3.f, 3.f), line);
-
- if (node.isImplicitMatrixNode()) {
- canvas->resetMatrix();
- }
- // The output bounds calculated as if the node were the only filter in the DAG
- line.setColor(SK_ColorBLUE);
- canvas->drawRect(SkRect::Make(node.fForwardIsolatedBounds).makeOutset(1.f, 1.f), line);
-
- // The output bounds calculated for the node
- line.setPathEffect(nullptr);
- canvas->drawRect(SkRect::Make(node.fForwardBounds).makeOutset(2.f, 2.f), line);
-
- canvas->restore();
- }
+ // The output bounds in layer space
+ line.setColor(SK_ColorBLUE);
+ canvas->drawRect(SkRect::Make(SkIRect(node.fOutputBounds)).makeOutset(1.f, 1.f), line);
+ // Device-space bounding box of the output bounds (e.g. what legacy DAG manipulation via
+ // MatrixTransform would produce).
+ static const SkScalar kDashParams[] = {6.f, 12.f};
+ line.setPathEffect(SkDashPathEffect::Make(kDashParams, 2, 0.f));
+ SkRect devOutputBounds = SkRect::Make(SkIRect(node.fMapping.layerToDevice(node.fOutputBounds)));
+ canvas->restore(); // undoes device matrix
+ canvas->drawRect(devOutputBounds, line);
}
static constexpr float kLineHeight = 16.f;
@@ -385,21 +214,23 @@
text.setAntiAlias(true);
float y = kLineHeight;
- if (node.fDepth == 0) {
- canvas->drawString("Final Results", kLineInset, y, font, text);
- // The actual interesting matrices are in the root node's first child
- y = print_matrix(canvas, "Local", node.fInputNodes[0].fLocalCTM,
- kLineInset, y + kLineHeight, font, text);
- y = print_matrix(canvas, "Embedded", node.fInputNodes[0].fRemainingCTM,
- kLineInset, y, font, text);
- } else if (node.fFilter) {
+ if (node.fFilter) {
canvas->drawString(node.fFilter->getTypeName(), kLineInset, y, font, text);
- print_size(canvas, "Layer Size", node.fLayerBounds, kLineInset, y + kLineHeight,
- font, text);
- y = print_size(canvas, "Ideal Size", node.fReverseLocalBounds, 10 * kLineInset,
- y + kLineHeight, font, text);
+ y += kLineHeight;
+ if (node.fDepth == 0) {
+ // The mapping is the same for all nodes, so only print at the root
+ y = print_matrix(canvas, "Param->Layer", node.fMapping.layerMatrix(),
+ kLineInset, y, font, text);
+ y = print_matrix(canvas, "Layer->Device", node.fMapping.deviceMatrix(),
+ kLineInset, y, font, text);
+ }
+
+ y = print_size(canvas, "Layer Size", SkIRect(node.fUnhintedLayerBounds),
+ kLineInset, y, font, text);
+ y = print_size(canvas, "Layer Size (hinted)", SkIRect(node.fHintedLayerBounds),
+ kLineInset, y, font, text);
} else {
- canvas->drawString("Source Input", kLineInset, kLineHeight, font, text);
+ canvas->drawString("Source Input", kLineInset, y, font, text);
y += kLineHeight;
}
@@ -448,7 +279,7 @@
y = draw_dag(canvas, nodeSurface, node.fInputNodes[i]);
canvas->restore();
}
- return SkMaxScalar(y, nodeResults->height() + textHeight + kPad);
+ return std::max(y, nodeResults->height() + textHeight + kPad);
}
static void draw_dag(SkCanvas* canvas, sk_sp<SkImageFilter> filter,
@@ -509,7 +340,7 @@
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE(return new ImageFilterDAGSample();)
diff --git a/third_party/skia/samplecode/SampleLCD.cpp b/third_party/skia/samplecode/SampleLCD.cpp
index 3c71415..0fd46a1 100644
--- a/third_party/skia/samplecode/SampleLCD.cpp
+++ b/third_party/skia/samplecode/SampleLCD.cpp
@@ -49,7 +49,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleLayerMask.cpp b/third_party/skia/samplecode/SampleLayerMask.cpp
deleted file mode 100644
index 546c6c4..0000000
--- a/third_party/skia/samplecode/SampleLayerMask.cpp
+++ /dev/null
@@ -1,66 +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/SkBitmap.h"
-#include "include/core/SkCanvas.h"
-#include "include/core/SkPaint.h"
-#include "include/core/SkPath.h"
-#include "samplecode/Sample.h"
-
-///////////////////////////////////////////////////////////////////////////////
-
-class LayerMaskView : public Sample {
-public:
- LayerMaskView() {
- this->setBGColor(0xFFDDDDDD);
- }
-
-protected:
- virtual SkString name() { return SkString("LayerMask"); }
-
- void drawMask(SkCanvas* canvas, const SkRect& r) {
- SkPaint paint;
- paint.setAntiAlias(true);
-
- if (true) {
- SkBitmap mask;
- int w = SkScalarRoundToInt(r.width());
- int h = SkScalarRoundToInt(r.height());
- mask.allocN32Pixels(w, h);
- mask.eraseColor(SK_ColorTRANSPARENT);
- SkCanvas c(mask);
- SkRect bounds = r;
- bounds.offset(-bounds.fLeft, -bounds.fTop);
- c.drawOval(bounds, paint);
-
- paint.setBlendMode(SkBlendMode::kDstIn);
- canvas->drawBitmap(mask, r.fLeft, r.fTop, &paint);
- } else {
- SkPath p;
- p.addOval(r);
- p.setFillType(SkPathFillType::kInverseWinding);
- paint.setBlendMode(SkBlendMode::kDstOut);
- canvas->drawPath(p, paint);
- }
- }
-
- virtual void onDrawContent(SkCanvas* canvas) {
- SkRect r;
- r.setLTRB(20, 20, 120, 120);
- canvas->saveLayer(&r, nullptr);
- canvas->drawColor(SK_ColorRED);
- drawMask(canvas, r);
- canvas->restore();
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new LayerMaskView(); )
diff --git a/third_party/skia/samplecode/SampleLayers.cpp b/third_party/skia/samplecode/SampleLayers.cpp
index aeddc46..c228578 100644
--- a/third_party/skia/samplecode/SampleLayers.cpp
+++ b/third_party/skia/samplecode/SampleLayers.cpp
@@ -15,12 +15,9 @@
#include "include/core/SkShader.h"
#include "include/core/SkTime.h"
#include "include/core/SkTypeface.h"
-#include "include/effects/SkBlurMaskFilter.h"
#include "include/effects/SkGradientShader.h"
#include "include/utils/SkCamera.h"
-#include "include/utils/SkInterpolator.h"
#include "samplecode/Sample.h"
-#include "src/core/SkClipOpPriv.h"
#include "src/utils/SkUTF.h"
static void make_paint(SkPaint* paint, const SkMatrix& localMatrix) {
@@ -37,9 +34,6 @@
SkRect r;
- SkPaint p;
- p.setAlpha(0x88);
-
SkAutoCanvasRestore ar2(canvas, false);
// create the layers
@@ -56,7 +50,7 @@
// now draw the "content"
- if (true) {
+ if ((true)) {
r.setWH(100, 100);
canvas->saveLayerAlpha(&r, 0x80);
@@ -109,7 +103,7 @@
void onDrawContent(SkCanvas* canvas) override {
this->drawBG(canvas);
- if (true) {
+ if ((true)) {
SkRect r;
r.setWH(220, 120);
SkPaint p;
@@ -122,7 +116,7 @@
return;
}
- if (false) {
+ if ((false)) {
SkRect r;
r.setWH(220, 120);
SkPaint p;
@@ -141,7 +135,7 @@
canvas->drawOval(r, p);
}
- if (false) {
+ if ((false)) {
SkPaint p;
p.setAlpha(0x88);
p.setAntiAlias(true);
@@ -164,7 +158,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new LayersView; )
@@ -191,7 +185,7 @@
SkString name() override { return SkString("Backdrop"); }
void onDrawContent(SkCanvas* canvas) override {
- canvas->drawImage(fImage.get(), 0, 0, nullptr);
+ canvas->drawImage(fImage.get(), 0, 0);
const SkScalar w = 250;
const SkScalar h = 150;
@@ -202,12 +196,12 @@
m.postTranslate(fCenter.x(), fCenter.y());
path.transform(m);
- canvas->clipPath(path, kIntersect_SkClipOp, true);
+ canvas->clipPath(path, SkClipOp::kIntersect, true);
const SkRect bounds = path.getBounds();
SkPaint paint;
paint.setAlpha(0xCC);
- canvas->saveLayer({ &bounds, &paint, fFilter.get(), nullptr, nullptr, 0 });
+ canvas->saveLayer(SkCanvas::SaveLayerRec(&bounds, &paint, fFilter.get(), 0));
canvas->restore();
}
@@ -227,6 +221,6 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new BackdropView; )
diff --git a/third_party/skia/samplecode/SampleLighting.cpp b/third_party/skia/samplecode/SampleLighting.cpp
deleted file mode 100644
index 24a0a64..0000000
--- a/third_party/skia/samplecode/SampleLighting.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2015 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/SkPoint3.h"
-#include "samplecode/DecodeFile.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkNormalSource.h"
-#include "src/shaders/SkLightingShader.h"
-#include "tools/Resources.h"
-
-static sk_sp<SkLights> create_lights(SkScalar angle, SkScalar blue) {
-
- const SkVector3 dir = SkVector3::Make(SkScalarSin(angle)*SkScalarSin(SK_ScalarPI*0.25f),
- SkScalarCos(angle)*SkScalarSin(SK_ScalarPI*0.25f),
- SkScalarCos(SK_ScalarPI*0.25f));
-
- SkLights::Builder builder;
-
- builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, blue), dir));
- builder.setAmbientLightColor(SkColor3f::Make(0.1f, 0.1f, 0.1f));
-
- return builder.finish();
-}
-
-////////////////////////////////////////////////////////////////////////////
-
-class LightingView : public Sample {
-public:
- LightingView() : fLightAngle(0.0f), fColorFactor(0.0f) {}
-
-protected:
- SkString name() override { return SkString("Lighting"); }
-
- void onOnceBeforeDraw() override {
- {
- SkBitmap diffuseBitmap;
- SkAssertResult(GetResourceAsBitmap("images/brickwork-texture.jpg", &diffuseBitmap));
-
- fRect = SkRect::MakeIWH(diffuseBitmap.width(), diffuseBitmap.height());
-
- fDiffuseShader = diffuseBitmap.makeShader();
- }
-
- {
- SkBitmap normalBitmap;
- SkAssertResult(GetResourceAsBitmap("images/brickwork_normal-map.jpg", &normalBitmap));
-
- sk_sp<SkShader> normalMap = normalBitmap.makeShader();
- fNormalSource = SkNormalSource::MakeFromNormalMap(std::move(normalMap), SkMatrix::I());
- }
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- sk_sp<SkLights> lights(create_lights(fLightAngle, fColorFactor));
-
- SkPaint paint;
- paint.setShader(SkLightingShader::Make(fDiffuseShader,
- fNormalSource,
- std::move(lights)));
- paint.setColor(SK_ColorBLACK);
-
- canvas->drawRect(fRect, paint);
- }
-
- Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
- return this->INHERITED::onFindClickHandler(x, y, modi);
- }
-
- bool onAnimate(double nanos) override {
- fLightAngle += 0.015f;
- fColorFactor += 0.01f;
- if (fColorFactor > 1.0f) {
- fColorFactor = 0.0f;
- }
-
- return true;
- }
-
-private:
- SkRect fRect;
- sk_sp<SkShader> fDiffuseShader;
- sk_sp<SkNormalSource> fNormalSource;
-
- SkScalar fLightAngle;
- SkScalar fColorFactor;
-
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new LightingView(); )
diff --git a/third_party/skia/samplecode/SampleLitAtlas.cpp b/third_party/skia/samplecode/SampleLitAtlas.cpp
deleted file mode 100644
index d43e6d7..0000000
--- a/third_party/skia/samplecode/SampleLitAtlas.cpp
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Copyright 2016 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/SkDrawable.h"
-#include "include/core/SkRSXform.h"
-#include "include/utils/SkRandom.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkNormalSource.h"
-#include "src/shaders/SkBitmapProcShader.h"
-#include "src/shaders/SkLightingShader.h"
-#include "src/shaders/SkLights.h"
-
-#include "tools/ToolUtils.h"
-
-// A crude normal mapped asteroids-like sample
-class DrawLitAtlasDrawable : public SkDrawable {
-public:
- DrawLitAtlasDrawable(const SkRect& r)
- : fBounds(r)
- , fUseColors(false)
- , fLightDir(SkVector3::Make(1.0f, 0.0f, 0.0f)) {
- fAtlas = MakeAtlas();
-
- SkRandom rand;
- for (int i = 0; i < kNumAsteroids; ++i) {
- fAsteroids[i].initAsteroid(&rand, fBounds, &fDiffTex[i], &fNormTex[i]);
- }
-
- fShip.initShip(fBounds, &fDiffTex[kNumAsteroids], &fNormTex[kNumAsteroids]);
-
- this->updateLights();
- }
-
- void toggleUseColors() {
- fUseColors = !fUseColors;
- }
-
- void rotateLight() {
- SkScalar r = SK_ScalarPI / 6.0f,
- s = SkScalarSin(r),
- c = SkScalarCos(r);
-
- SkScalar newX = c * fLightDir.fX - s * fLightDir.fY;
- SkScalar newY = s * fLightDir.fX + c * fLightDir.fY;
-
- fLightDir.set(newX, newY, 0.0f);
-
- this->updateLights();
- }
-
- void left() {
- SkScalar newRot = SkScalarMod(fShip.rot() + (2*SK_ScalarPI - SK_ScalarPI/32.0f),
- 2 * SK_ScalarPI);
- fShip.setRot(newRot);
- }
-
- void right() {
- SkScalar newRot = SkScalarMod(fShip.rot() + SK_ScalarPI/32.0f, 2 * SK_ScalarPI);
- fShip.setRot(newRot);
- }
-
- void thrust() {
- SkScalar s = SkScalarSin(fShip.rot()),
- c = SkScalarCos(fShip.rot());
-
- SkVector newVel = fShip.velocity();
- newVel.fX += s;
- newVel.fY += -c;
-
- SkScalar len = newVel.length();
- if (len > kMaxShipSpeed) {
- newVel.setLength(SkIntToScalar(kMaxShipSpeed));
- }
-
- fShip.setVelocity(newVel);
- }
-
-protected:
- void onDraw(SkCanvas* canvas) override {
- SkRSXform xforms[kNumAsteroids+kNumShips];
- SkColor colors[kNumAsteroids+kNumShips];
-
- for (int i = 0; i < kNumAsteroids; ++i) {
- fAsteroids[i].advance(fBounds);
- xforms[i] = fAsteroids[i].asRSXform();
- if (fUseColors) {
- colors[i] = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
- }
- }
-
- fShip.advance(fBounds);
- xforms[kNumAsteroids] = fShip.asRSXform();
- if (fUseColors) {
- colors[kNumAsteroids] = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
- }
-
-#ifdef SK_DEBUG
- canvas->drawBitmap(fAtlas, 0, 0); // just to see the atlas
-
- this->drawLightDir(canvas, fBounds.centerX(), fBounds.centerY());
-#endif
-
-#if 0
- // TODO: revitalize when drawLitAtlas API lands
- SkPaint paint;
- paint.setFilterQuality(kLow_SkFilterQuality);
-
- const SkRect cull = this->getBounds();
- const SkColor* colorsPtr = fUseColors ? colors : NULL;
-
- canvas->drawLitAtlas(fAtlas, xforms, fDiffTex, fNormTex, colorsPtr, kNumAsteroids+1,
- SkXfermode::kModulate_Mode, &cull, &paint, fLights);
-#else
- SkMatrix diffMat, normalMat;
-
- for (int i = 0; i < kNumAsteroids+1; ++i) {
- colors[i] = colors[i] & 0xFF000000; // to silence compilers
- SkPaint paint;
-
- SkRect r = fDiffTex[i];
- r.offsetTo(0, 0);
-
- diffMat.setRectToRect(fDiffTex[i], r, SkMatrix::kFill_ScaleToFit);
- normalMat.setRectToRect(fNormTex[i], r, SkMatrix::kFill_ScaleToFit);
-
- SkMatrix m;
- m.setRSXform(xforms[i]);
-
- sk_sp<SkShader> normalMap = fAtlas.makeShader(&normalMat);
- sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(
- std::move(normalMap), m);
- sk_sp<SkShader> diffuseShader = fAtlas.makeShader(&diffMat);
- paint.setShader(SkLightingShader::Make(std::move(diffuseShader),
- std::move(normalSource), fLights));
-
- canvas->save();
- canvas->setMatrix(m);
- canvas->drawRect(r, paint);
- canvas->restore();
- }
-#endif
-
-#ifdef SK_DEBUG
- {
- SkPaint paint;
- paint.setColor(SK_ColorRED);
-
- for (int i = 0; i < kNumAsteroids; ++i) {
- canvas->drawCircle(fAsteroids[i].pos().x(), fAsteroids[i].pos().y(), 2, paint);
- }
- canvas->drawCircle(fShip.pos().x(), fShip.pos().y(), 2, paint);
-
- paint.setStyle(SkPaint::kStroke_Style);
- canvas->drawRect(this->getBounds(), paint);
- }
-#endif
- }
-
- SkRect onGetBounds() override {
- return fBounds;
- }
-
-private:
-
- enum ObjType {
- kBigAsteroid_ObjType = 0,
- kMedAsteroid_ObjType,
- kSmAsteroid_ObjType,
- kShip_ObjType,
-
- kLast_ObjType = kShip_ObjType
- };
-
- static const int kObjTypeCount = kLast_ObjType + 1;
-
- void updateLights() {
- SkLights::Builder builder;
-
- builder.add(SkLights::Light::MakeDirectional(
- SkColor3f::Make(1.0f, 1.0f, 1.0f), fLightDir));
- builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
-
- fLights = builder.finish();
- }
-
-#ifdef SK_DEBUG
- // Draw a vector to the light
- void drawLightDir(SkCanvas* canvas, SkScalar centerX, SkScalar centerY) {
- static const int kBgLen = 30;
- static const int kSmLen = 5;
-
- // TODO: change the lighting coordinate system to be right handed
- SkPoint p1 = SkPoint::Make(centerX + kBgLen * fLightDir.fX,
- centerY - kBgLen * fLightDir.fY);
- SkPoint p2 = SkPoint::Make(centerX + (kBgLen-kSmLen) * fLightDir.fX,
- centerY - (kBgLen-kSmLen) * fLightDir.fY);
-
- SkPaint p;
- canvas->drawLine(centerX, centerY, p1.fX, p1.fY, p);
- canvas->drawLine(p1.fX, p1.fY,
- p2.fX - kSmLen * fLightDir.fY, p2.fY - kSmLen * fLightDir.fX, p);
- canvas->drawLine(p1.fX, p1.fY,
- p2.fX + kSmLen * fLightDir.fY, p2.fY + kSmLen * fLightDir.fX, p);
- }
-#endif
-
- // Create the mixed diffuse & normal atlas
- //
- // big color circle | big normal hemi
- // ------------------------------------
- // med color circle | med normal pyra
- // ------------------------------------
- // sm color circle | sm normal hemi
- // ------------------------------------
- // big ship | big tetra normal
- static SkBitmap MakeAtlas() {
-
- SkBitmap atlas;
- atlas.allocN32Pixels(kAtlasWidth, kAtlasHeight);
-
- for (int y = 0; y < kAtlasHeight; ++y) {
- int x = 0;
- for ( ; x < kBigSize+kPad; ++x) {
- *atlas.getAddr32(x, y) = SK_ColorTRANSPARENT;
- }
- for ( ; x < kAtlasWidth; ++x) {
- *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0x88, 0x88, 0xFF);
- }
- }
-
- // big asteroid
- {
- SkPoint bigCenter = SkPoint::Make(kDiffXOff + kBigSize/2.0f, kBigYOff + kBigSize/2.0f);
-
- for (int y = kBigYOff; y < kBigYOff+kBigSize; ++y) {
- for (int x = kDiffXOff; x < kDiffXOff+kBigSize; ++x) {
- SkScalar distSq = (x - bigCenter.fX) * (x - bigCenter.fX) +
- (y - bigCenter.fY) * (y - bigCenter.fY);
- if (distSq > kBigSize*kBigSize/4.0f) {
- *atlas.getAddr32(x, y) = SkPreMultiplyARGB(0, 0, 0, 0);
- } else {
- *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0xFF, 0, 0);
- }
- }
- }
-
- ToolUtils::create_hemi_normal_map(
- &atlas, SkIRect::MakeXYWH(kNormXOff, kBigYOff, kBigSize, kBigSize));
- }
-
- // medium asteroid
- {
- for (int y = kMedYOff; y < kMedYOff+kMedSize; ++y) {
- for (int x = kDiffXOff; x < kDiffXOff+kMedSize; ++x) {
- *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0xFF, 0);
- }
- }
-
- ToolUtils::create_frustum_normal_map(
- &atlas, SkIRect::MakeXYWH(kNormXOff, kMedYOff, kMedSize, kMedSize));
- }
-
- // small asteroid
- {
- SkPoint smCenter = SkPoint::Make(kDiffXOff + kSmSize/2.0f, kSmYOff + kSmSize/2.0f);
-
- for (int y = kSmYOff; y < kSmYOff+kSmSize; ++y) {
- for (int x = kDiffXOff; x < kDiffXOff+kSmSize; ++x) {
- SkScalar distSq = (x - smCenter.fX) * (x - smCenter.fX) +
- (y - smCenter.fY) * (y - smCenter.fY);
- if (distSq > kSmSize*kSmSize/4.0f) {
- *atlas.getAddr32(x, y) = SkPreMultiplyARGB(0, 0, 0, 0);
- } else {
- *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0, 0xFF);
- }
- }
- }
-
- ToolUtils::create_hemi_normal_map(
- &atlas, SkIRect::MakeXYWH(kNormXOff, kSmYOff, kSmSize, kSmSize));
- }
-
- // ship
- {
- SkScalar shipMidLine = kDiffXOff + kMedSize/2.0f;
-
- for (int y = kShipYOff; y < kShipYOff+kMedSize; ++y) {
- SkScalar scaledY = (y - kShipYOff)/(float)kMedSize; // 0..1
-
- for (int x = kDiffXOff; x < kDiffXOff+kMedSize; ++x) {
- SkScalar scaledX;
-
- if (x < shipMidLine) {
- scaledX = 1.0f - (x - kDiffXOff)/(kMedSize/2.0f); // 0..1
- } else {
- scaledX = (x - shipMidLine)/(kMedSize/2.0f); // 0..1
- }
-
- if (scaledX < scaledY) {
- *atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0xFF, 0xFF);
- } else {
- *atlas.getAddr32(x, y) = SkPackARGB32(0, 0, 0, 0);
- }
- }
- }
-
- ToolUtils::create_tetra_normal_map(
- &atlas, SkIRect::MakeXYWH(kNormXOff, kShipYOff, kMedSize, kMedSize));
- }
-
- return atlas;
- }
-
- class ObjectRecord {
- public:
- void initAsteroid(SkRandom *rand, const SkRect& bounds,
- SkRect* diffTex, SkRect* normTex) {
- static const SkScalar gMaxSpeeds[3] = { 1, 2, 5 }; // smaller asteroids can go faster
- static const SkScalar gYOffs[3] = { kBigYOff, kMedYOff, kSmYOff };
- static const SkScalar gSizes[3] = { kBigSize, kMedSize, kSmSize };
-
- static unsigned int asteroidType = 0;
- fObjType = static_cast<ObjType>(asteroidType++ % 3);
-
- fPosition.set(bounds.fLeft + rand->nextUScalar1() * bounds.width(),
- bounds.fTop + rand->nextUScalar1() * bounds.height());
- fVelocity.fX = rand->nextSScalar1();
- fVelocity.fY = sqrt(1.0f - fVelocity.fX * fVelocity.fX);
- SkASSERT(SkScalarNearlyEqual(fVelocity.length(), 1.0f));
- fVelocity *= gMaxSpeeds[fObjType];
- fRot = 0;
- fDeltaRot = rand->nextSScalar1() / 32;
-
- diffTex->setXYWH(SkIntToScalar(kDiffXOff), gYOffs[fObjType],
- gSizes[fObjType], gSizes[fObjType]);
- normTex->setXYWH(SkIntToScalar(kNormXOff), gYOffs[fObjType],
- gSizes[fObjType], gSizes[fObjType]);
- }
-
- void initShip(const SkRect& bounds, SkRect* diffTex, SkRect* normTex) {
- fObjType = kShip_ObjType;
- fPosition.set(bounds.centerX(), bounds.centerY());
- fVelocity = SkVector::Make(0.0f, 0.0f);
- fRot = 0.0f;
- fDeltaRot = 0.0f;
-
- diffTex->setXYWH(SkIntToScalar(kDiffXOff), SkIntToScalar(kShipYOff),
- SkIntToScalar(kMedSize), SkIntToScalar(kMedSize));
- normTex->setXYWH(SkIntToScalar(kNormXOff), SkIntToScalar(kShipYOff),
- SkIntToScalar(kMedSize), SkIntToScalar(kMedSize));
- }
-
- void advance(const SkRect& bounds) {
- fPosition += fVelocity;
- if (fPosition.fX > bounds.right()) {
- SkASSERT(fVelocity.fX > 0);
- fVelocity.fX = -fVelocity.fX;
- } else if (fPosition.fX < bounds.left()) {
- SkASSERT(fVelocity.fX < 0);
- fVelocity.fX = -fVelocity.fX;
- }
- if (fPosition.fY > bounds.bottom()) {
- if (fVelocity.fY > 0) {
- fVelocity.fY = -fVelocity.fY;
- }
- } else if (fPosition.fY < bounds.top()) {
- if (fVelocity.fY < 0) {
- fVelocity.fY = -fVelocity.fY;
- }
- }
-
- fRot += fDeltaRot;
- fRot = SkScalarMod(fRot, 2 * SK_ScalarPI);
- }
-
- const SkPoint& pos() const { return fPosition; }
-
- SkScalar rot() const { return fRot; }
- void setRot(SkScalar rot) { fRot = rot; }
-
- const SkPoint& velocity() const { return fVelocity; }
- void setVelocity(const SkPoint& velocity) { fVelocity = velocity; }
-
- SkRSXform asRSXform() const {
- static const SkScalar gHalfSizes[kObjTypeCount] = {
- SkScalarHalf(kBigSize),
- SkScalarHalf(kMedSize),
- SkScalarHalf(kSmSize),
- SkScalarHalf(kMedSize),
- };
-
- return SkRSXform::MakeFromRadians(1.0f, fRot, fPosition.x(), fPosition.y(),
- gHalfSizes[fObjType],
- gHalfSizes[fObjType]);
- }
-
- private:
- ObjType fObjType;
- SkPoint fPosition;
- SkVector fVelocity;
- SkScalar fRot; // In radians.
- SkScalar fDeltaRot; // In radiands. Not used by ship.
- };
-
-private:
- static const int kNumLights = 2;
- static const int kNumAsteroids = 6;
- static const int kNumShips = 1;
-
- static const int kBigSize = 128;
- static const int kMedSize = 64;
- static const int kSmSize = 32;
- static const int kPad = 1;
- static const int kAtlasWidth = kBigSize + kBigSize + 2 * kPad; // 2 pads in the middle
- static const int kAtlasHeight = kBigSize + kMedSize + kSmSize + kMedSize + 3 * kPad;
-
- static const int kDiffXOff = 0;
- static const int kNormXOff = kBigSize + 2 * kPad;
-
- static const int kBigYOff = 0;
- static const int kMedYOff = kBigSize + kPad;
- static const int kSmYOff = kMedYOff + kMedSize + kPad;
- static const int kShipYOff = kSmYOff + kSmSize + kPad;
- static const int kMaxShipSpeed = 5;
-
- SkBitmap fAtlas;
- ObjectRecord fAsteroids[kNumAsteroids];
- ObjectRecord fShip;
- SkRect fDiffTex[kNumAsteroids+kNumShips];
- SkRect fNormTex[kNumAsteroids+kNumShips];
- SkRect fBounds;
- bool fUseColors;
- SkVector3 fLightDir;
- sk_sp<SkLights> fLights;
-
- typedef SkDrawable INHERITED;
-};
-
-class DrawLitAtlasView : public Sample {
-public:
- DrawLitAtlasView() : fDrawable(new DrawLitAtlasDrawable(SkRect::MakeWH(640, 480))) {}
-
-protected:
- SkString name() override { return SkString("DrawLitAtlas"); }
-
- bool onChar(SkUnichar uni) override {
- switch (uni) {
- case 'C':
- fDrawable->toggleUseColors();
- return true;
- case 'j':
- fDrawable->left();
- return true;
- case 'k':
- fDrawable->thrust();
- return true;
- case 'l':
- fDrawable->right();
- return true;
- case 'o':
- fDrawable->rotateLight();
- return true;
- default:
- break;
- }
- return false;
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawDrawable(fDrawable.get());
- }
-
- bool onAnimate(double nanos) override { return true; }
-
-private:
- sk_sp<DrawLitAtlasDrawable> fDrawable;
-
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new DrawLitAtlasView(); )
diff --git a/third_party/skia/samplecode/SampleLua.cpp b/third_party/skia/samplecode/SampleLua.cpp
deleted file mode 100644
index 1a094bb..0000000
--- a/third_party/skia/samplecode/SampleLua.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2013 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/SkData.h"
-#include "include/utils/SkLua.h"
-#include "samplecode/Sample.h"
-#include "tools/Resources.h"
-
-extern "C" {
-#include "lua.h"
-#include "lualib.h"
-#include "lauxlib.h"
-}
-
-//#define LUA_FILENAME "lua/test.lua"
-#define LUA_FILENAME "lua/slides.lua"
-
-static const char gDrawName[] = "onDrawContent";
-static const char gClickName[] = "onClickHandler";
-static const char gUnicharName[] = "onCharHandler";
-
-static const char gMissingCode[] = ""
- "local paint = Sk.newPaint()"
- "paint:setAntiAlias(true)"
- "paint:setTextSize(30)"
- ""
- "function onDrawContent(canvas)"
- " canvas:drawText('missing \"test.lua\"', 20, 50, paint)"
- "end"
- ;
-
-class LuaView : public Sample {
-public:
- LuaView() : fLua(nullptr) {}
-
- ~LuaView() override { delete fLua; }
-
- void setImageFilename(lua_State* L) {
- SkString str = GetResourcePath("images/mandrill_256.png");
-
- lua_getglobal(L, "setImageFilename");
- if (lua_isfunction(L, -1)) {
- fLua->pushString(str.c_str());
- if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
- SkDebugf("lua err: %s\n", lua_tostring(L, -1));
- }
- }
- }
-
- lua_State* ensureLua() {
- if (nullptr == fLua) {
- fLua = new SkLua;
-
- sk_sp<SkData> data = GetResourceAsData(LUA_FILENAME);
- if (data) {
- fLua->runCode(data->data(), data->size());
- this->setImageFilename(fLua->get());
- } else {
- fLua->runCode(gMissingCode);
- }
- }
- return fLua->get();
- }
-
-protected:
- SkString name() override { return SkString("Lua"); }
-
- bool onChar(SkUnichar uni) override {
- lua_State* L = this->ensureLua();
- lua_getglobal(L, gUnicharName);
- if (lua_isfunction(L, -1)) {
- SkString str;
- str.appendUnichar(uni);
- fLua->pushString(str.c_str());
- if (lua_pcall(L, 1, 1, 0) != LUA_OK) {
- SkDebugf("lua err: %s\n", lua_tostring(L, -1));
- } else {
- if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
- return true;
- }
- }
- }
- return false;
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- lua_State* L = this->ensureLua();
-
- lua_getglobal(L, gDrawName);
- if (!lua_isfunction(L, -1)) {
- int t = lua_type(L, -1);
- SkDebugf("--- expected %s function %d, ignoring.\n", gDrawName, t);
- lua_pop(L, 1);
- } else {
- // does it make sense to try to "cache" the lua version of this
- // canvas between draws?
- fLua->pushCanvas(canvas);
- fLua->pushScalar(this->width());
- fLua->pushScalar(this->height());
- if (lua_pcall(L, 3, 1, 0) != LUA_OK) {
- SkDebugf("lua err: %s\n", lua_tostring(L, -1));
- }
- }
- }
-
- virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
- skui::ModifierKey modi) override {
- lua_State* L = this->ensureLua();
- lua_getglobal(L, gClickName);
- if (lua_isfunction(L, -1)) {
- fLua->pushScalar(x);
- fLua->pushScalar(y);
- fLua->pushString("down");
- if (lua_pcall(L, 3, 1, 0) != LUA_OK) {
- SkDebugf("lua err: %s\n", lua_tostring(L, -1));
- } else {
- if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
- return new Click();
- }
- }
- }
- return this->INHERITED::onFindClickHandler(x, y, modi);
- }
-
- bool onClick(Click* click) override {
- const char* state = nullptr;
- switch (click->fState) {
- case skui::InputState::kMove:
- state = "moved";
- break;
- case skui::InputState::kUp:
- state = "up";
- break;
- default:
- break;
- }
- if (state) {
- lua_State* L = fLua->get();
- lua_getglobal(L, gClickName);
- fLua->pushScalar(click->fCurr.x());
- fLua->pushScalar(click->fCurr.y());
- fLua->pushString(state);
- lua_pcall(L, 3, 1, 0);
- return lua_isboolean(L, -1) && lua_toboolean(L, -1);
- }
- return true;
- }
-
-private:
- SkLua* fLua;
-
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new LuaView(); )
diff --git a/third_party/skia/samplecode/SampleManyRects.cpp b/third_party/skia/samplecode/SampleManyRects.cpp
index cfd66c9..ba3bdb1 100644
--- a/third_party/skia/samplecode/SampleManyRects.cpp
+++ b/third_party/skia/samplecode/SampleManyRects.cpp
@@ -38,7 +38,7 @@
canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
// Uncomment to test rotated rect draw combining.
- if (false) {
+ if ((false)) {
SkMatrix rotate;
rotate.setRotate(fRandom.nextUScalar1() * 360,
SkIntToScalar(x) + SkScalarHalf(rect.fRight),
@@ -59,7 +59,7 @@
private:
SkRandom fRandom;
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleMaterialShadows.cpp b/third_party/skia/samplecode/SampleMaterialShadows.cpp
new file mode 100644
index 0000000..8cb951f
--- /dev/null
+++ b/third_party/skia/samplecode/SampleMaterialShadows.cpp
@@ -0,0 +1,147 @@
+
+/*
+ * Copyright 2020 Google LLC
+ *
+ * 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/SkPath.h"
+#include "include/core/SkPoint3.h"
+#include "include/pathops/SkPathOps.h"
+#include "include/utils/SkCamera.h"
+#include "include/utils/SkShadowUtils.h"
+#include "samplecode/Sample.h"
+#include "src/core/SkBlurMask.h"
+#include "src/utils/SkUTF.h"
+#include "tools/ToolUtils.h"
+#include "tools/timer/TimeUtils.h"
+
+////////////////////////////////////////////////////////////////////////////
+
+class MaterialShadowsView : public Sample {
+ SkPath fCirclePath;
+ SkPath fCapsulePath;
+ SkPath fLargeRRPath;
+ SkPath fSmallRRPath;
+
+ SkPoint3 fLightPos;
+
+ void onOnceBeforeDraw() override {
+ fCirclePath.addCircle(0, 0, 56/2);
+ fCapsulePath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-64, -24, 128, 48), 24, 24));
+ fLargeRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-64, -64, 128, 128), 4, 4));
+ fSmallRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-40, -40, 80, 80), 4, 4));
+
+ fLightPos = SkPoint3::Make(0, -700, 700);
+ }
+
+ SkString name() override { return SkString("MaterialShadows"); }
+
+ void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
+ const SkPoint3& zPlaneParams,
+ const SkPaint& paint, SkScalar ambientAlpha,
+ const SkPoint3& lightPos, SkScalar lightRadius, SkScalar spotAlpha) {
+ uint32_t flags = 0;
+ flags |= SkShadowFlags::kDirectionalLight_ShadowFlag;
+
+ SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 0, 0, 0);
+ SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 0);
+ SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, lightPos, lightRadius,
+ ambientColor, spotColor, flags);
+
+ canvas->drawPath(path, paint);
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ canvas->drawColor(0xFFFFFFFF);
+
+ const SkScalar kLightRadius = 1.1f;
+ const SkScalar kAmbientAlpha = 0.05f;
+ const SkScalar kSpotAlpha = 0.35f;
+
+ const SkScalar elevations[] = { 1, 3, 6, 8, 12, 24 };
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkPoint3 lightPos = fLightPos;
+ SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0);
+
+ paint.setColor(SK_ColorWHITE);
+ canvas->save();
+ canvas->translate(80, 80);
+ for (unsigned int i = 0; i < SK_ARRAY_COUNT(elevations); ++i) {
+ zPlaneParams.fZ = elevations[i];
+ this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, kAmbientAlpha,
+ lightPos, kLightRadius, kSpotAlpha);
+ canvas->translate(80, 0);
+ }
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(120, 175);
+ for (unsigned int i = 0; i < SK_ARRAY_COUNT(elevations); ++i) {
+ zPlaneParams.fZ = elevations[i];
+ this->drawShadowedPath(canvas, fCapsulePath, zPlaneParams, paint, kAmbientAlpha,
+ lightPos, kLightRadius, kSpotAlpha);
+ canvas->translate(160, 0);
+ }
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(120, 320);
+ for (unsigned int i = 0; i < SK_ARRAY_COUNT(elevations); ++i) {
+ zPlaneParams.fZ = elevations[i];
+ this->drawShadowedPath(canvas, fLargeRRPath, zPlaneParams, paint, kAmbientAlpha,
+ lightPos, kLightRadius, kSpotAlpha);
+ canvas->translate(160, 0);
+ }
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(100, 475);
+ for (unsigned int i = 0; i < SK_ARRAY_COUNT(elevations); ++i) {
+ zPlaneParams.fZ = elevations[i];
+ this->drawShadowedPath(canvas, fSmallRRPath, zPlaneParams, paint, kAmbientAlpha,
+ lightPos, kLightRadius, kSpotAlpha);
+ canvas->translate(160, 0);
+ }
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(100, 600);
+ for (unsigned int i = 0; i < SK_ARRAY_COUNT(elevations); ++i) {
+ canvas->save();
+ zPlaneParams.fZ = elevations[i];
+ canvas->rotate(10);
+ this->drawShadowedPath(canvas, fSmallRRPath, zPlaneParams, paint, kAmbientAlpha,
+ lightPos, kLightRadius, kSpotAlpha);
+ canvas->restore();
+ canvas->translate(160, 0);
+ }
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(100, 725);
+ for (unsigned int i = 0; i < SK_ARRAY_COUNT(elevations); ++i) {
+ canvas->save();
+ zPlaneParams.fZ = elevations[i];
+ canvas->rotate(45);
+ this->drawShadowedPath(canvas, fSmallRRPath, zPlaneParams, paint, kAmbientAlpha,
+ lightPos, kLightRadius, kSpotAlpha);
+ canvas->restore();
+ canvas->translate(160, 0);
+ }
+ canvas->restore();
+
+ }
+
+private:
+ using INHERITED = Sample;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_SAMPLE( return new MaterialShadowsView(); )
diff --git a/third_party/skia/samplecode/SampleMegaStroke.cpp b/third_party/skia/samplecode/SampleMegaStroke.cpp
index 33fa431..15579d9 100644
--- a/third_party/skia/samplecode/SampleMegaStroke.cpp
+++ b/third_party/skia/samplecode/SampleMegaStroke.cpp
@@ -76,7 +76,7 @@
SkRect fClip;
int fAngle;
int fPlusMinus;
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleMixer.cpp b/third_party/skia/samplecode/SampleMixer.cpp
index 7e39ab1..aa164b4 100644
--- a/third_party/skia/samplecode/SampleMixer.cpp
+++ b/third_party/skia/samplecode/SampleMixer.cpp
@@ -40,13 +40,14 @@
void dodraw(SkCanvas* canvas, sk_sp<SkColorFilter> cf0, sk_sp<SkColorFilter> cf1, float gap) {
SkPaint paint;
paint.setColorFilter(cf0);
- canvas->drawImage(fImg, 0, 0, &paint);
+ canvas->drawImage(fImg, 0, 0, SkSamplingOptions(), &paint);
paint.setColorFilter(SkColorFilters::Lerp(fWeight, cf0, cf1));
- canvas->drawImage(fImg, fImg->width() + gap * fWeight, 0, &paint);
+ canvas->drawImage(fImg, fImg->width() + gap * fWeight, 0,
+ SkSamplingOptions(), &paint);
paint.setColorFilter(cf1);
- canvas->drawImage(fImg, 2*fImg->width() + gap, 0, &paint);
+ canvas->drawImage(fImg, 2*fImg->width() + gap, 0, SkSamplingOptions(), &paint);
}
void onDrawContent(SkCanvas* canvas) override {
@@ -71,7 +72,7 @@
}
}
- virtual Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
+ Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
return fRect.contains(SkScalarRoundToInt(x),
SkScalarRoundToInt(y)) ? new Click() : nullptr;
}
@@ -85,94 +86,6 @@
private:
SkIRect fRect;
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new MixerView; )
-
-//////////////////////////////////////////////////////////////////////////////
-
-#include "include/core/SkMaskFilter.h"
-#include "include/core/SkSurface.h"
-
-static sk_sp<SkShader> make_resource_shader(const char path[], int size) {
- auto img = GetResourceAsImage(path);
- if (!img) {
- return nullptr;
- }
- SkRect src = SkRect::MakeIWH(img->width(), img->height());
- SkRect dst = SkRect::MakeIWH(size, size);
- SkMatrix m;
- m.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
- return img->makeShader(&m);
-}
-
-class ShaderMixerView : public Sample {
- sk_sp<SkShader> fSH0;
- sk_sp<SkShader> fSH1;
- sk_sp<SkSurface> fSurface;
- SkBlendMode fMode = SkBlendMode::kClear;
-
- enum { SIZE = 256 };
-
- const SkRect fRect = SkRect::MakeXYWH(10, 10 + SIZE + 10, SIZE, SIZE);
-
-public:
- ShaderMixerView() {}
-
- void onOnceBeforeDraw() override {
- fSH0 = make_resource_shader("images/mandrill_256.png", SIZE);
- fSH1 = make_resource_shader("images/baby_tux.png", SIZE);
- }
-
-protected:
- SkString name() override { return SkString("ShaderMixer"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- if (!fSurface) {
- fSurface = canvas->makeSurface(SkImageInfo::MakeN32Premul(SIZE, SIZE));
- }
-
- SkPaint paint;
- const SkRect r = SkRect::MakeIWH(SIZE, SIZE);
-
- canvas->translate(10, 10);
-
- canvas->save();
- paint.setShader(fSH0); canvas->drawRect(r, paint);
- canvas->translate(SIZE + 10.f, 0);
- paint.setShader(fSH1); canvas->drawRect(r, paint);
- canvas->restore();
-
- canvas->translate(0, SIZE + 10.f);
-
- auto sh = fSurface->makeImageSnapshot()->makeShader();
-
- canvas->save();
- paint.setShader(sh); canvas->drawRect(r, paint);
- canvas->translate(SIZE + 10.f, 0);
- paint.setShader(SkShaders::Lerp(sh, fSH0, fSH1)); canvas->drawRect(r, paint);
- canvas->restore();
- }
-
- virtual Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
- fMode = (fMode == SkBlendMode::kSrcOver) ? SkBlendMode::kClear : SkBlendMode::kSrcOver;
- return fRect.contains(SkScalarRoundToInt(x),
- SkScalarRoundToInt(y)) ? new Click() : nullptr;
- }
-
- bool onClick(Click* click) override {
- SkPaint p;
- p.setAntiAlias(true);
- p.setColor(SK_ColorRED);
- p.setBlendMode(fMode);
- p.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 12));
- SkScalar x = click->fCurr.fX - fRect.fLeft;
- SkScalar y = click->fCurr.fY - fRect.fTop;
- fSurface->getCanvas()->drawCircle(x, y, 10, p);
- return true;
- }
-
-private:
- typedef Sample INHERITED;
-};
-DEF_SAMPLE( return new ShaderMixerView; )
diff --git a/third_party/skia/samplecode/SampleParagraph.cpp b/third_party/skia/samplecode/SampleParagraph.cpp
deleted file mode 100644
index cc10e03..0000000
--- a/third_party/skia/samplecode/SampleParagraph.cpp
+++ /dev/null
@@ -1,1720 +0,0 @@
-// Copyright 2019 Google LLC.
-#include "include/core/SkCanvas.h"
-#include "include/core/SkColorFilter.h"
-#include "include/core/SkColorPriv.h"
-#include "include/core/SkGraphics.h"
-#include "include/core/SkPath.h"
-#include "include/core/SkRegion.h"
-#include "include/core/SkShader.h"
-#include "include/core/SkStream.h"
-#include "include/core/SkTextBlob.h"
-#include "include/core/SkTime.h"
-#include "include/core/SkTypeface.h"
-#include "include/effects/SkBlurMaskFilter.h"
-#include "include/effects/SkGradientShader.h"
-#include "include/utils/SkRandom.h"
-#include "modules/skparagraph/include/Paragraph.h"
-#include "modules/skparagraph/include/TypefaceFontProvider.h"
-#include "modules/skparagraph/src/ParagraphBuilderImpl.h"
-#include "modules/skparagraph/src/ParagraphImpl.h"
-#include "modules/skparagraph/utils/TestFontCollection.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkOSFile.h"
-#include "src/shaders/SkColorShader.h"
-#include "src/utils/SkOSPath.h"
-#include "src/utils/SkUTF.h"
-#include "tools/Resources.h"
-
-using namespace skia::textlayout;
-namespace {
-
-class ParagraphView_Base : public Sample {
-protected:
- sk_sp<TestFontCollection> getFontCollection() {
- // If we reset font collection we need to reset paragraph cache
- static sk_sp<TestFontCollection> fFC = nullptr;
- if (fFC == nullptr) {
- fFC = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
- }
- return fFC;
- }
-};
-
-sk_sp<SkShader> setgrad(const SkRect& r, SkColor c0, SkColor c1) {
- SkColor colors[] = {c0, c1};
- SkPoint pts[] = {{r.fLeft, r.fTop}, {r.fRight, r.fTop}};
- return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
-}
-/*
-void writeHtml(const char* name, Paragraph* paragraph) {
- SkString tmpDir = skiatest::GetTmpDir();
- if (!tmpDir.isEmpty()) {
- SkString path = SkOSPath::Join(tmpDir.c_str(), name);
- SkFILEWStream file(path.c_str());
- file.write(nullptr, 0);
- }
-}
-*/
-} // namespace
-
-class ParagraphView1 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph1"); }
-
- void drawTest(SkCanvas* canvas, SkScalar w, SkScalar h, SkColor fg, SkColor bg) {
- const std::vector<
- std::tuple<std::string, bool, bool, int, SkColor, SkColor, bool, TextDecorationStyle>>
- gParagraph = {{"monospace", true, false, 14, SK_ColorWHITE, SK_ColorRED, true,
- TextDecorationStyle::kDashed},
- {"Assyrian", false, false, 20, SK_ColorWHITE, SK_ColorBLUE, false,
- TextDecorationStyle::kDotted},
- {"serif", true, true, 10, SK_ColorWHITE, SK_ColorRED, true,
- TextDecorationStyle::kDouble},
- {"Arial", false, true, 16, SK_ColorGRAY, SK_ColorGREEN, true,
- TextDecorationStyle::kSolid},
- {"sans-serif", false, false, 8, SK_ColorWHITE, SK_ColorRED, false,
- TextDecorationStyle::kWavy}};
- SkAutoCanvasRestore acr(canvas, true);
-
- canvas->clipRect(SkRect::MakeWH(w, h));
- canvas->drawColor(SK_ColorWHITE);
-
- SkScalar margin = 20;
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(fg);
-
- SkPaint blue;
- blue.setColor(SK_ColorBLUE);
-
- TextStyle defaultStyle;
- defaultStyle.setBackgroundColor(blue);
- defaultStyle.setForegroundColor(paint);
- ParagraphStyle paraStyle;
-
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- for (auto i = 1; i < 5; ++i) {
- defaultStyle.setFontSize(24 * i);
- paraStyle.setTextStyle(defaultStyle);
- ParagraphBuilderImpl builder(paraStyle, fontCollection);
- std::string name = "Paragraph: " + std::to_string(24 * i);
- builder.addText(name.c_str(), name.length());
- for (auto para : gParagraph) {
- TextStyle style;
- style.setFontFamilies({SkString(std::get<0>(para).c_str())});
- SkFontStyle fontStyle(std::get<1>(para) ? SkFontStyle::Weight::kBold_Weight
- : SkFontStyle::Weight::kNormal_Weight,
- SkFontStyle::Width::kNormal_Width,
- std::get<2>(para) ? SkFontStyle::Slant::kItalic_Slant
- : SkFontStyle::Slant::kUpright_Slant);
- style.setFontStyle(fontStyle);
- style.setFontSize(std::get<3>(para) * i);
- SkPaint background;
- background.setColor(std::get<4>(para));
- style.setBackgroundColor(background);
- SkPaint foreground;
- foreground.setColor(std::get<5>(para));
- foreground.setAntiAlias(true);
- style.setForegroundColor(foreground);
- if (std::get<6>(para)) {
- style.addShadow(TextShadow(SK_ColorBLACK, SkPoint::Make(5, 5), 2));
- }
-
- auto decoration = (i % 4);
- if (decoration == 3) {
- decoration = 4;
- }
-
- bool test = (TextDecoration)decoration != TextDecoration::kNoDecoration;
- std::string deco = std::to_string((int)decoration);
- if (test) {
- style.setDecoration((TextDecoration)decoration);
- style.setDecorationStyle(std::get<7>(para));
- style.setDecorationColor(std::get<5>(para));
- }
- builder.pushStyle(style);
- std::string name = " " + std::get<0>(para) + " " +
- (std::get<1>(para) ? ", bold" : "") +
- (std::get<2>(para) ? ", italic" : "") + " " +
- std::to_string(std::get<3>(para) * i) +
- (std::get<4>(para) != bg ? ", background" : "") +
- (std::get<5>(para) != fg ? ", foreground" : "") +
- (std::get<6>(para) ? ", shadow" : "") +
- (test ? ", decorations " + deco : "") + ";";
- builder.addText(name.c_str(), name.length());
- builder.pop();
- }
-
- auto paragraph = builder.Build();
- paragraph->layout(w - margin * 2);
- paragraph->paint(canvas, margin, margin);
-
- canvas->translate(0, paragraph->getHeight());
- }
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- drawTest(canvas, this->width(), this->height(), SK_ColorRED, SK_ColorWHITE);
- }
-
-private:
-
- typedef Sample INHERITED;
-};
-
-class ParagraphView2 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph2"); }
-
- void drawCode(SkCanvas* canvas, SkScalar w, SkScalar h) {
- SkPaint comment;
- comment.setColor(SK_ColorGRAY);
- SkPaint constant;
- constant.setColor(SK_ColorMAGENTA);
- SkPaint null;
- null.setColor(SK_ColorMAGENTA);
- SkPaint literal;
- literal.setColor(SK_ColorGREEN);
- SkPaint code;
- code.setColor(SK_ColorDKGRAY);
- SkPaint number;
- number.setColor(SK_ColorBLUE);
- SkPaint name;
- name.setColor(SK_ColorRED);
-
- SkPaint white;
- white.setColor(SK_ColorWHITE);
-
- TextStyle defaultStyle;
- defaultStyle.setBackgroundColor(white);
- defaultStyle.setForegroundColor(code);
- defaultStyle.setFontFamilies({SkString("monospace")});
- defaultStyle.setFontSize(30);
- ParagraphStyle paraStyle;
- paraStyle.setTextStyle(defaultStyle);
-
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- ParagraphBuilderImpl builder(paraStyle, fontCollection);
-
- const char* text1 = "RaisedButton";
- const char* text2 = "(\n";
- const char* text3 = " child: ";
- const char* text4 = "const";
- const char* text5 = "Text";
- const char* text6 = "'BUTTON TITLE'";
- const char* text7 = "),\n";
-
- builder.pushStyle(style(name));
- builder.addText(text1, strlen(text1));
- builder.pop();
- builder.addText(text2, strlen(text2));
- builder.addText(text3, strlen(text3));
- builder.pushStyle(style(constant));
- builder.addText(text4, strlen(text4));
- builder.pop();
- builder.addText(" ", 1);
- builder.pushStyle(style(name));
- builder.addText(text5, strlen(text5));
- builder.pop();
- builder.addText("(", 1);
- builder.pushStyle(style(literal));
- builder.addText(text6, strlen(text6));
- builder.pop();
- builder.addText(text7, strlen(text7));
-
- auto paragraph = builder.Build();
- paragraph->layout(w - 20);
-
- paragraph->paint(canvas, 20, 20);
- }
-
- TextStyle style(SkPaint paint) {
- TextStyle style;
- paint.setAntiAlias(true);
- style.setForegroundColor(paint);
- style.setFontFamilies({SkString("monospace")});
- style.setFontSize(30);
-
- return style;
- }
-
- void drawText(SkCanvas* canvas, SkScalar w, SkScalar h, std::vector<const char*>& text,
- SkColor fg = SK_ColorDKGRAY, SkColor bg = SK_ColorWHITE,
- const char* ff = "sans-serif", SkScalar fs = 24,
- size_t lineLimit = 30,
- const std::u16string& ellipsis = u"\u2026") {
- SkAutoCanvasRestore acr(canvas, true);
-
- canvas->clipRect(SkRect::MakeWH(w, h));
- canvas->drawColor(bg);
-
- SkScalar margin = 20;
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(fg);
-
- SkPaint blue;
- blue.setColor(SK_ColorBLUE);
-
- SkPaint background;
- background.setColor(bg);
-
- TextStyle style;
- style.setBackgroundColor(blue);
- style.setForegroundColor(paint);
- style.setFontFamilies({SkString(ff)});
- style.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight,
- SkFontStyle::kNormal_Width,
- SkFontStyle::kUpright_Slant));
- style.setFontSize(fs);
- ParagraphStyle paraStyle;
- paraStyle.setTextStyle(style);
- paraStyle.setMaxLines(lineLimit);
-
- paraStyle.setEllipsis(ellipsis);
- TextStyle defaultStyle;
- defaultStyle.setFontSize(20);
- paraStyle.setTextStyle(defaultStyle);
- ParagraphBuilderImpl builder(paraStyle, getFontCollection());
-
- SkPaint foreground;
- foreground.setColor(fg);
- style.setForegroundColor(foreground);
- style.setBackgroundColor(background);
-
- for (auto& part : text) {
- builder.pushStyle(style);
- builder.addText(part, strlen(part));
- builder.pop();
- }
-
- auto paragraph = builder.Build();
- paragraph->layout(w - margin * 2);
- paragraph->paint(canvas, margin, margin);
-
- canvas->translate(0, paragraph->getHeight() + margin);
- }
-
- void drawLine(SkCanvas* canvas, SkScalar w, SkScalar h, const std::string& text,
- TextAlign align) {
- SkAutoCanvasRestore acr(canvas, true);
-
- canvas->clipRect(SkRect::MakeWH(w, h));
- canvas->drawColor(SK_ColorWHITE);
-
- SkScalar margin = 20;
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SK_ColorBLUE);
-
- SkPaint gray;
- gray.setColor(SK_ColorLTGRAY);
-
- TextStyle style;
- style.setBackgroundColor(gray);
- style.setForegroundColor(paint);
- style.setFontFamilies({SkString("Arial")});
- style.setFontSize(30);
- ParagraphStyle paraStyle;
- paraStyle.setTextStyle(style);
- paraStyle.setTextAlign(align);
-
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- ParagraphBuilderImpl builder(paraStyle, fontCollection);
- builder.addText(text.c_str(), text.length());
-
- auto paragraph = builder.Build();
- paragraph->layout(w - margin * 2);
- paragraph->layout(w - margin);
- paragraph->paint(canvas, margin, margin);
-
- canvas->translate(0, paragraph->getHeight() + margin);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- std::vector<const char*> cupertino = {
- "google_logogoogle_gsuper_g_logo 1 "
- "google_logogoogle_gsuper_g_logo 12 "
- "google_logogoogle_gsuper_g_logo 123 "
- "google_logogoogle_gsuper_g_logo 1234 "
- "google_logogoogle_gsuper_g_logo 12345 "
- "google_logogoogle_gsuper_g_logo 123456 "
- "google_logogoogle_gsuper_g_logo 1234567 "
- "google_logogoogle_gsuper_g_logo 12345678 "
- "google_logogoogle_gsuper_g_logo 123456789 "
- "google_logogoogle_gsuper_g_logo 1234567890 "
- "google_logogoogle_gsuper_g_logo 123456789 "
- "google_logogoogle_gsuper_g_logo 12345678 "
- "google_logogoogle_gsuper_g_logo 1234567 "
- "google_logogoogle_gsuper_g_logo 123456 "
- "google_logogoogle_gsuper_g_logo 12345 "
- "google_logogoogle_gsuper_g_logo 1234 "
- "google_logogoogle_gsuper_g_logo 123 "
- "google_logogoogle_gsuper_g_logo 12 "
- "google_logogoogle_gsuper_g_logo 1 "
- "google_logogoogle_gsuper_g_logo "
- "google_logogoogle_gsuper_g_logo "
- "google_logogoogle_gsuper_g_logo "
- "google_logogoogle_gsuper_g_logo "
- "google_logogoogle_gsuper_g_logo "
- "google_logogoogle_gsuper_g_logo"};
- std::vector<const char*> text = {
- "My neighbor came over to say,\n"
- "Although not in a neighborly way,\n\n"
- "That he'd knock me around,\n\n\n"
- "If I didn't stop the sound,\n\n\n\n"
- "Of the classical music I play."};
-
- std::vector<const char*> long_word = {
- "A_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
- "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
- "very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_very_"
- "very_very_very_very_very_very_very_long_text"};
-
- std::vector<const char*> very_long = {
- "A very very very very very very very very very very very very very very very very "
- "very very very very very very very very very very very very very very very very "
- "very very very very very very very very very very very very very very very very "
- "very very very very very very very long text"};
-
- std::vector<const char*> very_word = {
- "A very_very_very_very_very_very_very_very_very_very "
- "very_very_very_very_very_very_very_very_very_very very very very very very very "
- "very very very very very very very very very very very very very very very very "
- "very very very very very very very very very very very very very long text"};
-
- SkScalar width = this->width() / 5;
- SkScalar height = this->height();
- drawText(canvas, width, height, long_word, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
- canvas->translate(width, 0);
- drawText(canvas, width, height, very_long, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
- canvas->translate(width, 0);
- drawText(canvas, width, height, very_word, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
- canvas->translate(width, 0);
- drawText(canvas, width, height / 2, text, SK_ColorBLACK, SK_ColorWHITE, "Roboto", 20, 100,
- u"\u2026");
- canvas->translate(0, height / 2);
- drawCode(canvas, width, height / 2);
- canvas->translate(width, -height / 2);
-
- drawText(canvas, width, height, cupertino, SK_ColorBLACK, SK_ColorWHITE, "Google Sans", 30);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView3 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph3"); }
-
- void drawLine(SkCanvas* canvas, SkScalar w, SkScalar h, const std::string& text,
- TextAlign align, size_t lineLimit = std::numeric_limits<size_t>::max(),
- bool RTL = false, SkColor background = SK_ColorGRAY,
- const std::u16string& ellipsis = u"\u2026") {
- SkAutoCanvasRestore acr(canvas, true);
-
- canvas->clipRect(SkRect::MakeWH(w, h));
- canvas->drawColor(SK_ColorWHITE);
-
- SkScalar margin = 20;
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SK_ColorBLACK);
-
- SkPaint gray;
- gray.setColor(background);
-
- SkPaint yellow;
- yellow.setColor(SK_ColorYELLOW);
-
- TextStyle style;
- style.setBackgroundColor(gray);
- style.setForegroundColor(paint);
- style.setFontFamilies({SkString("sans-serif")});
- style.setFontSize(30);
- ParagraphStyle paraStyle;
- paraStyle.setTextStyle(style);
- paraStyle.setTextAlign(align);
- paraStyle.setMaxLines(lineLimit);
- paraStyle.setEllipsis(ellipsis);
- // paraStyle.setTextDirection(RTL ? SkTextDirection::rtl : SkTextDirection::ltr);
-
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- ParagraphBuilderImpl builder(paraStyle, fontCollection);
- if (RTL) {
- builder.addText(mirror(text));
- } else {
- builder.addText(normal(text));
- }
-
- canvas->drawRect(SkRect::MakeXYWH(margin, margin, w - margin * 2, h - margin * 2), yellow);
- auto paragraph = builder.Build();
- paragraph->layout(w - margin * 2);
- paragraph->paint(canvas, margin, margin);
- }
-
- std::u16string mirror(const std::string& text) {
- std::u16string result;
- result += u"\u202E";
- // for (auto i = text.size(); i > 0; --i) {
- // result += text[i - 1];
- //}
-
- for (auto i = text.size(); i > 0; --i) {
- auto ch = text[i - 1];
- if (ch == ',') {
- result += u"!";
- } else if (ch == '.') {
- result += u"!";
- } else {
- result += ch;
- }
- }
-
- result += u"\u202C";
- return result;
- }
-
- std::u16string normal(const std::string& text) {
- std::u16string result;
- result += u"\u202D";
- for (auto ch : text) {
- result += ch;
- }
- result += u"\u202C";
- return result;
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- const std::string options = // { "open-source open-source open-source open-source" };
- {"Flutter is an open-source project to help developers "
- "build high-performance, high-fidelity, mobile apps for "
- "iOS and Android "
- "from a single codebase. This design lab is a playground "
- "and showcase of Flutter's many widgets, behaviors, "
- "animations, layouts, and more."};
-
- canvas->drawColor(SK_ColorDKGRAY);
- SkScalar width = this->width() / 4;
- SkScalar height = this->height() / 2;
-
- const std::string line =
- "World domination is such an ugly phrase - I prefer to call it world optimisation";
-
- drawLine(canvas, width, height, line, TextAlign::kLeft, 1, false, SK_ColorLTGRAY);
- canvas->translate(width, 0);
- drawLine(canvas, width, height, line, TextAlign::kRight, 2, false, SK_ColorLTGRAY);
- canvas->translate(width, 0);
- drawLine(canvas, width, height, line, TextAlign::kCenter, 3, false, SK_ColorLTGRAY);
- canvas->translate(width, 0);
- drawLine(canvas, width, height, line, TextAlign::kJustify, 4, false, SK_ColorLTGRAY);
- canvas->translate(-width * 3, height);
-
- drawLine(canvas, width, height, line, TextAlign::kLeft, 1, true, SK_ColorLTGRAY);
- canvas->translate(width, 0);
- drawLine(canvas, width, height, line, TextAlign::kRight, 2, true, SK_ColorLTGRAY);
- canvas->translate(width, 0);
- drawLine(canvas, width, height, line, TextAlign::kCenter, 3, true, SK_ColorLTGRAY);
- canvas->translate(width, 0);
- drawLine(canvas, width, height, line, TextAlign::kJustify, 4, true, SK_ColorLTGRAY);
- canvas->translate(width, 0);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView4 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph4"); }
-
- void drawFlutter(SkCanvas* canvas, SkScalar w, SkScalar h,
- const char* ff = "Google Sans", SkScalar fs = 30,
- size_t lineLimit = std::numeric_limits<size_t>::max(),
- const std::u16string& ellipsis = u"\u2026") {
- SkAutoCanvasRestore acr(canvas, true);
-
- canvas->clipRect(SkRect::MakeWH(w, h));
-
- SkScalar margin = 20;
-
- SkPaint black;
- black.setAntiAlias(true);
- black.setColor(SK_ColorBLACK);
-
- SkPaint blue;
- blue.setAntiAlias(true);
- blue.setColor(SK_ColorBLUE);
-
- SkPaint red;
- red.setAntiAlias(true);
- red.setColor(SK_ColorRED);
-
- SkPaint green;
- green.setAntiAlias(true);
- green.setColor(SK_ColorGREEN);
-
- SkPaint gray;
- gray.setColor(SK_ColorLTGRAY);
-
- SkPaint yellow;
- yellow.setColor(SK_ColorYELLOW);
-
- SkPaint magenta;
- magenta.setAntiAlias(true);
- magenta.setColor(SK_ColorMAGENTA);
-
- TextStyle style;
- style.setFontFamilies({SkString(ff)});
- style.setFontSize(fs);
-
- TextStyle style0;
- style0.setForegroundColor(black);
- style0.setBackgroundColor(gray);
- style0.setFontFamilies({SkString(ff)});
- style0.setFontSize(fs);
- style0.setDecoration(TextDecoration::kUnderline);
- style0.setDecorationStyle(TextDecorationStyle::kDouble);
- style0.setDecorationColor(SK_ColorBLACK);
-
- TextStyle style1;
- style1.setForegroundColor(blue);
- style1.setBackgroundColor(yellow);
- style1.setFontFamilies({SkString(ff)});
- style1.setFontSize(fs);
- style1.setDecoration(TextDecoration::kOverline);
- style1.setDecorationStyle(TextDecorationStyle::kWavy);
- style1.setDecorationColor(SK_ColorBLACK);
-
- TextStyle style2;
- style2.setForegroundColor(red);
- style2.setFontFamilies({SkString(ff)});
- style2.setFontSize(fs);
-
- TextStyle style3;
- style3.setForegroundColor(green);
- style3.setFontFamilies({SkString(ff)});
- style3.setFontSize(fs);
-
- TextStyle style4;
- style4.setForegroundColor(magenta);
- style4.setFontFamilies({SkString(ff)});
- style4.setFontSize(fs);
-
- ParagraphStyle paraStyle;
- paraStyle.setTextStyle(style);
- paraStyle.setMaxLines(lineLimit);
-
- paraStyle.setEllipsis(ellipsis);
-
- const char* logo1 = "google_";
- const char* logo2 = "logo";
- const char* logo3 = "go";
- const char* logo4 = "ogle_logo";
- const char* logo5 = "google_lo";
- const char* logo6 = "go";
- {
- ParagraphBuilderImpl builder(paraStyle, getFontCollection());
-
- builder.pushStyle(style0);
- builder.addText(logo1, strlen(logo1));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo2, strlen(logo2));
- builder.pop();
-
- builder.addText(" ", 1);
-
- builder.pushStyle(style0);
- builder.addText(logo3, strlen(logo3));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo4, strlen(logo4));
- builder.pop();
-
- builder.addText(" ", 1);
-
- builder.pushStyle(style0);
- builder.addText(logo5, strlen(logo5));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo6, strlen(logo6));
- builder.pop();
-
- auto paragraph = builder.Build();
- paragraph->layout(w - margin * 2);
- paragraph->paint(canvas, margin, margin);
- canvas->translate(0, h + margin);
- }
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
- SkScalar width = this->width();
- SkScalar height = this->height();
-
- drawFlutter(canvas, width, height / 2);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView5 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph5"); }
-
- void bidi(SkCanvas* canvas, SkScalar w, SkScalar h, const std::u16string& text,
- const std::u16string& expected, size_t lineLimit = std::numeric_limits<size_t>::max(),
- const char* ff = "Roboto", SkScalar fs = 30,
- const std::u16string& ellipsis = u"\u2026") {
- SkAutoCanvasRestore acr(canvas, true);
-
- canvas->clipRect(SkRect::MakeWH(w, h));
-
- SkScalar margin = 20;
-
- SkPaint black;
- black.setColor(SK_ColorBLACK);
- SkPaint gray;
- gray.setColor(SK_ColorLTGRAY);
-
- TextStyle style;
- style.setForegroundColor(black);
- style.setFontFamilies({SkString(ff)});
- style.setFontSize(fs);
-
- TextStyle style0;
- style0.setForegroundColor(black);
- style0.setFontFamilies({SkString(ff)});
- style0.setFontSize(fs);
- style0.setFontStyle(SkFontStyle(SkFontStyle::kNormal_Weight, SkFontStyle::kNormal_Width,
- SkFontStyle::kItalic_Slant));
-
- TextStyle style1;
- style1.setForegroundColor(gray);
- style1.setFontFamilies({SkString(ff)});
- style1.setFontSize(fs);
- style1.setFontStyle(SkFontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width,
- SkFontStyle::kUpright_Slant));
-
- ParagraphStyle paraStyle;
- paraStyle.setTextStyle(style);
- paraStyle.setMaxLines(lineLimit);
-
- paraStyle.setEllipsis(ellipsis);
-
- ParagraphBuilderImpl builder(paraStyle, getFontCollection());
-
- if (text.empty()) {
- const std::u16string text0 = u"\u202Dabc";
- const std::u16string text1 = u"\u202EFED";
- const std::u16string text2 = u"\u202Dghi";
- const std::u16string text3 = u"\u202ELKJ";
- const std::u16string text4 = u"\u202Dmno";
- builder.pushStyle(style0);
- builder.addText(text0);
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(text1);
- builder.pop();
- builder.pushStyle(style0);
- builder.addText(text2);
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(text3);
- builder.pop();
- builder.pushStyle(style0);
- builder.addText(text4);
- builder.pop();
- } else {
- // icu::UnicodeString unicode((UChar*) text.data(), SkToS32(text.size()));
- // std::string str;
- // unicode.toUTF8String(str);
- // SkDebugf("Text: %s\n", str.c_str());
- builder.addText(text + expected);
- }
-
- auto paragraph = builder.Build();
- paragraph->layout(w - margin * 2);
- paragraph->paint(canvas, margin, margin);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
- SkScalar width = this->width();
- SkScalar height = this->height() / 8;
-
- const std::u16string text1 =
- u"A \u202ENAC\u202Cner, exceedingly \u202ENAC\u202Cny,\n"
- "One morning remarked to his granny:\n"
- "A \u202ENAC\u202Cner \u202ENAC\u202C \u202ENAC\u202C,\n"
- "Anything that he \u202ENAC\u202C,\n"
- "But a \u202ENAC\u202Cner \u202ENAC\u202C't \u202ENAC\u202C a \u202ENAC\u202C, "
- "\u202ENAC\u202C he?";
- bidi(canvas, width, height * 3, text1, u"", 5);
- canvas->translate(0, height * 3);
-
- bidi(canvas, width, height, u"\u2067DETALOSI\u2069", u"");
- canvas->translate(0, height);
-
- bidi(canvas, width, height, u"\u202BDEDDEBME\u202C", u"");
- canvas->translate(0, height);
-
- bidi(canvas, width, height, u"\u202EEDIRREVO\u202C", u"");
- canvas->translate(0, height);
-
- bidi(canvas, width, height, u"\u200FTICILPMI\u200E", u"");
- canvas->translate(0, height);
-
- bidi(canvas, width, height, u"123 456 7890 \u202EZYXWV UTS RQP ONM LKJ IHG FED CBA\u202C.",
- u"", 2);
- canvas->translate(0, height);
-
- // bidi(canvas, width, height, u"", u"");
- // canvas->translate(0, height);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView6 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph6"); }
-
- void hangingS(SkCanvas* canvas, SkScalar w, SkScalar h, SkScalar fs = 60.0) {
- auto ff = "HangingS";
-
- canvas->drawColor(SK_ColorLTGRAY);
-
- SkPaint black;
- black.setAntiAlias(true);
- black.setColor(SK_ColorBLACK);
-
- SkPaint blue;
- blue.setAntiAlias(true);
- blue.setColor(SK_ColorBLUE);
-
- SkPaint red;
- red.setAntiAlias(true);
- red.setColor(SK_ColorRED);
-
- SkPaint green;
- green.setAntiAlias(true);
- green.setColor(SK_ColorGREEN);
-
- SkPaint gray;
- gray.setColor(SK_ColorCYAN);
-
- SkPaint yellow;
- yellow.setColor(SK_ColorYELLOW);
-
- SkPaint magenta;
- magenta.setAntiAlias(true);
- magenta.setColor(SK_ColorMAGENTA);
-
- SkFontStyle fontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width,
- SkFontStyle::kItalic_Slant);
-
- TextStyle style;
- style.setFontFamilies({SkString(ff)});
- style.setFontSize(fs);
- style.setFontStyle(fontStyle);
-
- TextStyle style0;
- style0.setForegroundColor(black);
- style0.setBackgroundColor(gray);
- style0.setFontFamilies({SkString(ff)});
- style0.setFontSize(fs);
- style0.setFontStyle(fontStyle);
-
- TextStyle style1;
- style1.setForegroundColor(blue);
- style1.setBackgroundColor(yellow);
- style1.setFontFamilies({SkString(ff)});
- style1.setFontSize(fs);
- style1.setFontStyle(fontStyle);
-
- TextStyle style2;
- style2.setForegroundColor(red);
- style2.setFontFamilies({SkString(ff)});
- style2.setFontSize(fs);
- style2.setFontStyle(fontStyle);
-
- TextStyle style3;
- style3.setForegroundColor(green);
- style3.setFontFamilies({SkString(ff)});
- style3.setFontSize(fs);
- style3.setFontStyle(fontStyle);
-
- TextStyle style4;
- style4.setForegroundColor(magenta);
- style4.setFontFamilies({SkString(ff)});
- style4.setFontSize(fs);
- style4.setFontStyle(fontStyle);
-
- ParagraphStyle paraStyle;
- paraStyle.setTextStyle(style);
-
- const char* logo1 = "S";
- const char* logo2 = "kia";
- const char* logo3 = "Sk";
- const char* logo4 = "ia";
- const char* logo5 = "Ski";
- const char* logo6 = "a";
- {
- ParagraphBuilderImpl builder(paraStyle, getFontCollection());
-
- builder.pushStyle(style0);
- builder.addText(logo1, strlen(logo1));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo2, strlen(logo2));
- builder.pop();
-
- builder.addText(" ", 3);
-
- builder.pushStyle(style0);
- builder.addText(logo3, strlen(logo3));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo4, strlen(logo4));
- builder.pop();
-
- builder.addText(" ", 3);
-
- builder.pushStyle(style0);
- builder.addText(logo5, strlen(logo5));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo6, strlen(logo6));
- builder.pop();
-
- auto paragraph = builder.Build();
- paragraph->layout(w);
- paragraph->paint(canvas, 40, 40);
- canvas->translate(0, h);
- }
-
- const char* logo11 = "S";
- const char* logo12 = "S";
- const char* logo13 = "S";
- const char* logo14 = "S";
- const char* logo15 = "S";
- const char* logo16 = "S";
- {
- ParagraphBuilderImpl builder(paraStyle, getFontCollection());
-
- builder.pushStyle(style0);
- builder.addText(logo11, strlen(logo1));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo12, strlen(logo2));
- builder.pop();
-
- builder.addText(" ", 3);
-
- builder.pushStyle(style0);
- builder.addText(logo13, strlen(logo3));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo14, strlen(logo4));
- builder.pop();
-
- builder.addText(" ", 3);
-
- builder.pushStyle(style0);
- builder.addText(logo15, strlen(logo5));
- builder.pop();
- builder.pushStyle(style1);
- builder.addText(logo16, strlen(logo6));
- builder.pop();
-
- auto paragraph = builder.Build();
- paragraph->layout(w);
- paragraph->paint(canvas, 40, h);
- canvas->translate(0, h);
- }
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
- SkScalar width = this->width();
- SkScalar height = this->height() / 4;
-
- hangingS(canvas, width, height);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView7 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph7"); }
-
- void drawText(SkCanvas* canvas, SkColor background, SkScalar letterSpace, SkScalar w,
- SkScalar h) {
- SkAutoCanvasRestore acr(canvas, true);
- canvas->clipRect(SkRect::MakeWH(w, h));
- canvas->drawColor(background);
-
- const char* line =
- "World domination is such an ugly phrase - I prefer to call it world optimisation.";
-
- ParagraphStyle paragraphStyle;
- paragraphStyle.setTextAlign(TextAlign::kLeft);
- paragraphStyle.setMaxLines(10);
- paragraphStyle.turnHintingOff();
- TextStyle textStyle;
- textStyle.setFontFamilies({SkString("Roboto")});
- textStyle.setFontSize(30);
- textStyle.setLetterSpacing(letterSpace);
- textStyle.setColor(SK_ColorBLACK);
- textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
- SkFontStyle::kUpright_Slant));
-
- ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
- builder.pushStyle(textStyle);
- builder.addText(line, strlen(line));
- builder.pop();
-
- auto paragraph = builder.Build();
- paragraph->layout(w - 20);
- paragraph->paint(canvas, 10, 10);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- auto h = this->height() / 4;
- auto w = this->width() / 2;
-
- drawText(canvas, SK_ColorGRAY, 1, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorLTGRAY, 2, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorCYAN, 3, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorGRAY, 4, w, h);
- canvas->translate(w, -3 * h);
-
- drawText(canvas, SK_ColorYELLOW, 5, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorGREEN, 10, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorRED, 15, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorBLUE, 20, w, h);
- canvas->translate(0, h);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView8 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph8"); }
-
- void drawText(SkCanvas* canvas, SkColor background, SkScalar wordSpace, SkScalar w,
- SkScalar h) {
- SkAutoCanvasRestore acr(canvas, true);
- canvas->clipRect(SkRect::MakeWH(w, h));
- canvas->drawColor(background);
-
- const char* line =
- "World domination is such an ugly phrase - I prefer to call it world optimisation.";
-
- ParagraphStyle paragraphStyle;
- paragraphStyle.setTextAlign(TextAlign::kLeft);
- paragraphStyle.setMaxLines(10);
- paragraphStyle.turnHintingOff();
- TextStyle textStyle;
- textStyle.setFontFamilies({SkString("Roboto")});
- textStyle.setFontSize(30);
- textStyle.setWordSpacing(wordSpace);
- textStyle.setColor(SK_ColorBLACK);
- textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
- SkFontStyle::kUpright_Slant));
-
- ParagraphBuilderImpl builder(paragraphStyle, getFontCollection());
- builder.pushStyle(textStyle);
- builder.addText(line, strlen(line));
- builder.pop();
-
- auto paragraph = builder.Build();
- paragraph->layout(w - 20);
- paragraph->paint(canvas, 10, 10);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- auto h = this->height() / 4;
- auto w = this->width() / 2;
-
- drawText(canvas, SK_ColorGRAY, 1, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorLTGRAY, 2, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorCYAN, 3, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorGRAY, 4, w, h);
- canvas->translate(w, -3 * h);
-
- drawText(canvas, SK_ColorYELLOW, 5, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorGREEN, 10, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorRED, 15, w, h);
- canvas->translate(0, h);
-
- drawText(canvas, SK_ColorBLUE, 20, w, h);
- canvas->translate(0, h);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView9 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph9"); }
-
- bool onChar(SkUnichar uni) override {
- switch (uni) {
- case 'w':
- ++wordSpacing;
- return true;
- case 'q':
- if (wordSpacing > 0) --wordSpacing;
- return true;
- case 'l':
- ++letterSpacing;
- return true;
- case 'k':
- if (letterSpacing > 0) --letterSpacing;
- return true;
- default:
- break;
- }
- return false;
- }
-
- void drawText(SkCanvas* canvas, SkColor background, SkScalar w, SkScalar h) {
- SkAutoCanvasRestore acr(canvas, true);
- canvas->clipRect(SkRect::MakeWH(w, h));
- canvas->drawColor(background);
-
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- fontCollection->enableFontFallback();
-
- const char* text =
- "( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
- " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)("
- " ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)( ´・‿・`)";
- auto multiplier = 5.67;
- ParagraphStyle paragraphStyle;
- paragraphStyle.setTextAlign(TextAlign::kLeft);
- paragraphStyle.setMaxLines(10);
- paragraphStyle.turnHintingOff();
- TextStyle textStyle;
- textStyle.setFontFamilies({SkString("Roboto")});
- textStyle.setFontSize(5 * multiplier);
- textStyle.setHeight(1.3f);
- textStyle.setColor(SK_ColorBLACK);
- textStyle.setFontStyle(SkFontStyle(SkFontStyle::kMedium_Weight, SkFontStyle::kNormal_Width,
- SkFontStyle::kUpright_Slant));
-
- ParagraphBuilderImpl builder(paragraphStyle, fontCollection);
- builder.pushStyle(textStyle);
- builder.addText(text, strlen(text));
- builder.pop();
-
- auto paragraph = builder.Build();
- paragraph->layout(200 * multiplier);
-
- std::vector<size_t> sizes = {0, 1, 2, 8, 19, 21, 22, 30, 150};
-
- std::vector<size_t> colors = {SK_ColorBLUE, SK_ColorCYAN, SK_ColorLTGRAY, SK_ColorGREEN,
- SK_ColorRED, SK_ColorWHITE, SK_ColorYELLOW, SK_ColorMAGENTA};
-
- RectHeightStyle rect_height_style = RectHeightStyle::kTight;
- RectWidthStyle rect_width_style = RectWidthStyle::kTight;
-
- for (size_t i = 0; i < sizes.size() - 1; ++i) {
- size_t from = sizes[i];
- size_t to = sizes[i + 1];
- auto boxes = paragraph->getRectsForRange(from, to, rect_height_style, rect_width_style);
- if (boxes.empty()) {
- continue;
- }
- for (auto& box : boxes) {
- SkPaint paint;
- paint.setColor(colors[i % colors.size()]);
- paint.setShader(setgrad(box.rect, colors[i % colors.size()], SK_ColorWHITE));
- canvas->drawRect(box.rect, paint);
- }
- }
-
- paragraph->paint(canvas, 0, 0);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- auto h = this->height();
- auto w = this->width();
-
- drawText(canvas, SK_ColorGRAY, w, h);
- }
-
-private:
- typedef Sample INHERITED;
- SkScalar letterSpacing;
- SkScalar wordSpacing;
-};
-
-class ParagraphView10 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph10"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
- auto multiplier = 5.67;
- const char* text = "English English 字典 字典 😀😃😄 😀😃😄";
-
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- fontCollection->enableFontFallback();
-
- ParagraphStyle paragraph_style;
- paragraph_style.turnHintingOff();
- ParagraphBuilderImpl builder(paragraph_style, fontCollection);
-
- TextStyle text_style;
- text_style.setFontFamilies({SkString("Roboto"),
- SkString("Noto Color Emoji"),
- SkString("Noto Serif CJK JP")});
- text_style.setFontSize(10 * multiplier);
- text_style.setLetterSpacing(0);
- text_style.setWordSpacing(0);
- text_style.setColor(SK_ColorBLACK);
- text_style.setHeight(1);
- builder.pushStyle(text_style);
- builder.addText(text, strlen(text));
- builder.pop();
-
- auto paragraph = builder.Build();
- paragraph->layout(width());
-
- paragraph->paint(canvas, 0, 0);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView11 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph11"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- auto text = "\U0001f469\U0000200D\U0001f469\U0000200D\U0001f466\U0001f469\U0000200D\U0001f469\U0000200D\U0001f467\U0000200D\U0001f467\U0001f1fa\U0001f1f8";
-
- TextStyle text_style;
- text_style.setFontFamilies({SkString("Ahem")});
- text_style.setColor(SK_ColorBLACK);
- text_style.setFontSize(60);
- text_style.setLetterSpacing(0);
- text_style.setWordSpacing(0);
- ParagraphStyle paragraph_style;
- paragraph_style.setTextStyle(text_style);
-
- auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), true, true);
- ParagraphBuilderImpl builder(paragraph_style, fontCollection);
- builder.addText(text, strlen(text));
- auto paragraph = builder.Build();
- paragraph->layout(1000);
- paragraph->paint(canvas, 0, 0);
-
- struct pair {
- unsigned fX;
- unsigned fY;
- };
-
- pair hit1[] =
- {{ 0, 8},{1, 33}, {2, 34}, { 3, 19}, {4, 20},
- { 5, 21}, { 6, 22 }, { 7, 23 }, {8, 24 }, { 9, 25},
- { 10, 26}, { 11, 27}, {12, 28}, { 13, 21}, {14, 22 },
- { 15, 23}, {16, 24}, {17, 21}, { 18, 22}, {19, 21},
- { 20, 24}, { 21, 23}, };
-
- pair miss[] =
- {{ 0, 4},{1, 17}, {2, 18}, { 3, 11}, {4, 12},
- { 5, 13}, { 6, 14 }, { 7, 15 }, {8, 16 }, { 9, 17},
- { 10, 18}, { 11, 19}, {12, 20}, { 13, 17}, {14, 18 },
- { 15, 19}, {16, 20}, {17, 19}, { 18, 20},
- { 20, 22}, };
-
- auto rects = paragraph->getRectsForRange(7, 9, RectHeightStyle::kTight, RectWidthStyle::kTight);
- SkPaint paint;
- paint.setColor(SK_ColorRED);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setAntiAlias(true);
- paint.setStrokeWidth(1);
- if (!rects.empty()) {
- canvas->drawRect(rects[0].rect, paint);
- }
-
- for (auto& query : hit1) {
- auto rects = paragraph->getRectsForRange(query.fX, query.fY, RectHeightStyle::kTight, RectWidthStyle::kTight);
- if (rects.size() >= 1 && rects[0].rect.width() > 0) {
- } else {
- SkDebugf("+[%d:%d): Bad\n", query.fX, query.fY);
- }
- }
-
- for (auto& query : miss) {
- auto miss = paragraph->getRectsForRange(query.fX, query.fY, RectHeightStyle::kTight, RectWidthStyle::kTight);
- if (miss.empty()) {
- } else {
- SkDebugf("-[%d:%d): Bad\n", query.fX, query.fY);
- }
- }
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView12 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph12"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- const char* text = "Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges";
- TextStyle text_style;
- text_style.setFontFamilies({SkString("Ahem")});
- text_style.setColor(SK_ColorBLACK);
- text_style.setFontSize(16);
- //text_style.setLetterSpacing(-0.41);
- StrutStyle strut_style;
- strut_style.setStrutEnabled(false);
- ParagraphStyle paragraph_style;
- paragraph_style.setStrutStyle(strut_style);
- paragraph_style.setTextStyle(text_style);
- ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
- builder.addText(text);
- auto paragraph = builder.Build();
- paragraph->layout(1095.000000);
- auto result = paragraph->getRectsForRange(65, 66, RectHeightStyle::kTight, RectWidthStyle::kTight);
- paragraph->paint(canvas, 0, 0);
-
- SkPaint paint;
- paint.setColor(SK_ColorRED);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setAntiAlias(true);
- paint.setStrokeWidth(1);
- canvas->drawRect(result.front().rect, paint);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView14 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph14"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
- TextStyle text_style;
- text_style.setFontFamilies({SkString("Ahem")});
- text_style.setColor(SK_ColorBLACK);
- text_style.setFontSize(25);
- text_style.setDecoration((TextDecoration)(TextDecoration::kUnderline | TextDecoration::kOverline | TextDecoration::kLineThrough));
- text_style.setDecorationColor(SK_ColorBLUE);
- text_style.setDecorationStyle(TextDecorationStyle::kWavy);
- text_style.setDecorationThicknessMultiplier(4.0f);
- ParagraphStyle paragraph_style;
- paragraph_style.setTextStyle(text_style);
- paragraph_style.setTextDirection(TextDirection::kRtl);
- ParagraphBuilderImpl builder(paragraph_style, getFontCollection());
- builder.pushStyle(text_style);
- builder.addText("Hello, wor!\nabcd.");
- auto paragraph = builder.Build();
- paragraph->layout(300);
- paragraph->paint(canvas, 0, 0);
- SkPaint paint;
- paint.setColor(SK_ColorRED);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setAntiAlias(true);
- paint.setStrokeWidth(1);
- canvas->drawRect(SkRect::MakeXYWH(0, 0, 300, 100), paint);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView15 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph15"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- TextStyle text_style;
- text_style.setFontFamilies({SkString("abc.ttf")});
- text_style.setFontSize(50);
-
- auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false);
-
- fontCollection->addFontFromFile("abc/abc.ttf", "abc");
- fontCollection->addFontFromFile("abc/abc+grave.ttf", "abc+grave");
- fontCollection->addFontFromFile("abc/abc+agrave.ttf", "abc+agrave");
-
- ParagraphStyle paragraph_style;
- ParagraphBuilderImpl builder(paragraph_style, fontCollection);
-
- text_style.setFontFamilies({SkString("abc"), SkString("abc+grave")});
- text_style.setColor(SK_ColorBLUE);
- builder.pushStyle(text_style);
- builder.addText(u"a\u0300");
- text_style.setColor(SK_ColorMAGENTA);
- builder.pushStyle(text_style);
- builder.addText(u"à");
-
- text_style.setFontFamilies({SkString("abc"), SkString("abc+agrave")});
-
- text_style.setColor(SK_ColorRED);
- builder.pushStyle(text_style);
- builder.addText(u"a\u0300");
- text_style.setColor(SK_ColorGREEN);
- builder.pushStyle(text_style);
- builder.addText(u"à");
-
- auto paragraph = builder.Build();
- paragraph->layout(800);
- paragraph->paint(canvas, 50, 50);
-
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView16 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph16"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- const char* text = "content";
-
- ParagraphStyle paragraph_style;
- paragraph_style.setMaxLines(1);
- paragraph_style.setEllipsis(u"\u2026");
- //auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- fontCollection->enableFontFallback();
- ParagraphBuilderImpl builder(paragraph_style, fontCollection);
-
- TextStyle text_style;
- text_style.setFontFamilies({SkString(".SF Pro Text")});
- text_style.setColor(SK_ColorBLACK);
- text_style.setFontSize(17.0f * 99.0f);
- text_style.setLetterSpacing(0.41f);
- builder.pushStyle(text_style);
- builder.addText(text);
-
- auto paragraph = builder.Build();
- paragraph->layout(800);
- paragraph->paint(canvas, 0, 0);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView17 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph17"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- fontCollection->enableFontFallback();
- auto navy = SkColorSetRGB(0, 0, 139);
- auto ltgray = SkColorSetRGB(211, 211, 211);
- auto multiplier = 5.67;
-
- const char* text = ">Sͬ͑̀͐̈͒̈́̋̎ͮͩ̽̓ͬ̂̆̔͗́̓ͣͧ͊ͫ͛̉͌̐̑ͪ͗̚͝҉̴͉͢k̡̊̓ͫͭͩ͂͊ͨͪͬ̑ͫ̍̌̄͛̌̂̑̂̋̊̔ͫ͛̽̑ͨ̍ͭ̓̀ͪͪ̉͐͗̌̓̃̚͟͝҉̢͏̫̞̙͇͖̮͕̗̟͕͇͚̻͈̣̻̪͉̰̲̣̫ͅͅP̴̅̍͒̿͗͗̇ͩ̃͆͌̀̽͏̧̡͕͖̝̖̼̺̰̣̬͔͖͔̼͙̞̦̫͓̘͜a̸̴̸̴̢̢̨̨̫͍͓̥̼̭̼̻̤̯̙̤̻̠͚̍̌͋̂ͦͨ̽̇͌͌͆̀̽̎͒̄ͪ̐ͦ̈ͫ͐͗̓̚̚͜ͅr͐͐ͤͫ̐ͥ͂̈́̿́ͮ̃͗̓̏ͫ̀̿͏̸̵̧́͘̕͟͝͠͞͠҉̷̧͚͢͟a̓̽̎̄͗̔͛̄̐͊͛ͫ͂͌̂̂̈̈̓̔̅̅̄͊̉́ͪ̑̄͆ͬ̍͆ͭ͋̐ͬ͏̷̵̨̢̩̹̖͓̥̳̰͔̱̬͖̙͓̙͇̀̀̕͜͟͟͢͟͜͠͡g̨̅̇ͦ͋̂ͦͨͭ̓͐͆̏̂͛̉ͧ̑ͫ̐̒͛ͫ̍̒͛́̚҉̷̨̛̛̀͜͢͞҉̩̘̲͍͎̯̹̝̭̗̱͇͉̲̱͔̯̠̹̥̻͉̲̜̤̰̪̗̺̖̺r̷͌̓̇̅ͭ̀̐̃̃ͭ͑͗̉̈̇̈́ͥ̓ͣ́ͤ͂ͤ͂̏͌̆̚҉̴̸̧̢̢̛̫͉̦̥̤̙͈͉͈͉͓̙̗̟̳̜͈̗̺̟̠̠͖͓̖̪͕̠̕̕͝ͅả̸̴̡̡̧͠͞͡͞҉̛̕͟͏̷̘̪̱͈̲͉̞̠̞̪̫͎̲̬̖̀̀͟͝͞͞͠p̛͂̈͐̚͠҉̵̸̡̢̢̩̹͙̯͖̙̙̮̥̙͚̠͔̥̭̮̞̣̪̬̥̠̖̝̥̪͎́̀̕͜͡͡ͅͅh̵̷̵̡̛ͤ̂͌̐̓̐̋̋͊̒̆̽́̀̀̀͢͠͞͞҉̷̸̢̕҉͚̯͖̫̜̞̟̠̱͉̝̲̹̼͉̟͉̩̮͔̤͖̞̭̙̹̬ͅ<";
-
- ParagraphStyle paragraph_style;
- ParagraphBuilderImpl builder(paragraph_style, fontCollection);
- SkPaint paint;
- paint.setColor(ltgray);
- TextStyle text_style;
- text_style.setBackgroundColor(paint);
- text_style.setColor(navy);
- text_style.setFontFamilies({SkString("Roboto")});
- text_style.setFontSize(20 * multiplier);
- builder.pushStyle(text_style);
- builder.addText(text);
- auto paragraph = builder.Build();
- paragraph->layout(10000);
- paragraph->paint(canvas, 0, 0);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class Zalgo {
- private:
- std::u16string COMBINING_DOWN = u"\u0316\u0317\u0318\u0319\u031c\u031d\u031e\u031f\u0320\u0324\u0325\u0326\u0329\u032a\u032b\u032c\u032d\u032e\u032f\u0330\u0331\u0332\u0333\u0339\u033a\u033b\u033c\u0345\u0347\u0348\u0349\u034d\u034e\u0353\u0354\u0355\u0356\u0359\u035a\u0323";
- std::u16string COMBINING_UP = u"\u030d\u030e\u0304\u0305\u033f\u0311\u0306\u0310\u0352\u0357\u0351\u0307\u0308\u030a\u0342\u0343\u0344\u034a\u034b\u034c\u0303\u0302\u030c\u0350\u0300\u0301\u030b\u030f\u0312\u0313\u0314\u033d\u0309\u0363\u0364\u0365\u0366\u0367\u0368\u0369\u036a\u036b\u036c\u036d\u036e\u035b\u0346\u031a";
- std::u16string COMBINING_MIDDLE = u"\u0315\u031b\u0340\u0341\u0358\u0321\u0322\u0327\u0328\u0334\u0335\u0336\u034f\u035c\u035d\u035e\u035f\u0360\u0362\u0338\u0337\u0361\u0489";
-
- std::u16string randomMarks(std::u16string& combiningMarks) {
- std::u16string result;
- auto num = std::rand() % (combiningMarks.size() / 1);
- for (size_t i = 0; i < num; ++i) {
- auto index = std::rand() % combiningMarks.size();
- result += combiningMarks[index];
- }
- return result;
- }
-
-public:
- std::u16string zalgo(std::string victim) {
- std::u16string result;
- for (auto& c : victim) {
- result += c;
- result += randomMarks(COMBINING_UP);
- result += randomMarks(COMBINING_MIDDLE);
- result += randomMarks(COMBINING_DOWN);
- }
- return result;
- }
-};
-
-class ParagraphView18 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph18"); }
-
- bool onChar(SkUnichar uni) override {
- switch (uni) {
- case ' ':
- fLimit = 400;
- return true;
- case 's':
- fLimit += 10;
- return true;
- case 'f':
- if (fLimit > 10) {
- fLimit -= 10;
- }
- return true;
- default:
- break;
- }
- return false;
- }
-
- bool onAnimate(double nanos) override {
- if (++fIndex > fLimit) {
- fRedraw = true;
- fIndex = 0;
- } else {
- fRepeat = true;
- }
- return true;
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- auto navy = SkColorSetRGB(0, 0, 139);
- auto ltgray = SkColorSetRGB(211, 211, 211);
-
- auto multiplier = 5.67;
- auto fontCollection = sk_make_sp<FontCollection>();
- fontCollection->setDefaultFontManager(SkFontMgr::RefDefault());
- fontCollection->enableFontFallback();
-
- ParagraphStyle paragraph_style;
- TextStyle text_style;
- text_style.setFontFamilies({SkString("Roboto")});
- text_style.setFontSize(20 * multiplier);
- text_style.setColor(navy);
- SkPaint paint;
- paint.setColor(ltgray);
- text_style.setBackgroundColor(paint);
-
- Zalgo zalgo;
-
- if (fRedraw || fRepeat) {
-
- if (fRedraw || fParagraph.get() == nullptr) {
- ParagraphBuilderImpl builder(paragraph_style, fontCollection);
- builder.pushStyle(text_style);
- auto utf16text = zalgo.zalgo("SkParagraph");
- icu::UnicodeString unicode((UChar*)utf16text.data(), SkToS32(utf16text.size()));
- std::string str;
- unicode.toUTF8String(str);
- SkDebugf("Text:>%s<\n", str.data());
- builder.addText(utf16text);
- fParagraph = builder.Build();
- }
-
- auto impl = static_cast<ParagraphImpl*>(fParagraph.get());
- impl->setState(InternalState::kUnknown);
- fParagraph->layout(1000);
- fParagraph->paint(canvas, 300, 200);
-
- for (auto& run : impl->runs()) {
- SkString fontFamily("unresolved");
- if (run.font().getTypeface() != nullptr) {
- run.font().getTypeface()->getFamilyName(&fontFamily);
- }
- if (run.font().getTypeface() != nullptr) {
- for (size_t i = 0; i < run.size(); ++i) {
- auto glyph = run.glyphs().begin() + i;
- if (*glyph == 0) {
- SkDebugf("Run[%d] @pos=%d\n", run.index(), i);
- SkASSERT(false);
- }
- }
- } else {
- SkDebugf("Run[%d]: %s\n", run.index(), fontFamily.c_str());
- SkASSERT(false);
- }
- }
- fRedraw = false;
- fRepeat = false;
- }
- }
-
-private:
- bool fRedraw = true;
- bool fRepeat = false;
- size_t fIndex = 0;
- size_t fLimit = 20;
- std::unique_ptr<Paragraph> fParagraph;
- typedef Sample INHERITED;
-};
-
-class ParagraphView19 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph19"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
-
- const char* text = "World domination is such an ugly phrase - I prefer to call it world optimisation";
- ParagraphStyle paragraph_style;
- paragraph_style.setMaxLines(7);
- paragraph_style.setEllipsis(u"\u2026");
- ParagraphBuilderImpl builder(paragraph_style, fontCollection);
- TextStyle text_style;
- text_style.setColor(SK_ColorBLACK);
- text_style.setFontFamilies({SkString("Roboto")});
- text_style.setFontSize(40);
- builder.pushStyle(text_style);
- builder.addText(text);
- auto paragraph = builder.Build();
- paragraph->layout(this->width());
-
- paragraph->paint(canvas, 0, 0);
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-class ParagraphView20 : public ParagraphView_Base {
-protected:
- SkString name() override { return SkString("Paragraph20"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorWHITE);
-
- auto fontCollection = sk_make_sp<TestFontCollection>(GetResourcePath("fonts").c_str(), false, true);
-
- const char* text = "";
- ParagraphStyle paragraph_style;
- paragraph_style.setMaxLines(std::numeric_limits<size_t>::max());
- //paragraph_style.setEllipsis(u"\u2026");
- ParagraphBuilderImpl builder(paragraph_style, fontCollection);
- TextStyle text_style;
- text_style.setColor(SK_ColorBLACK);
- text_style.setFontFamilies({SkString("Roboto")});
- text_style.setFontSize(40);
- builder.pushStyle(text_style);
- builder.addText(text);
- auto paragraph = builder.Build();
- paragraph->layout(this->width());
-
- paragraph->paint(canvas, 0, 0);
- }
-
-private:
- typedef Sample INHERITED;
-};
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE(return new ParagraphView1();)
-DEF_SAMPLE(return new ParagraphView2();)
-DEF_SAMPLE(return new ParagraphView3();)
-DEF_SAMPLE(return new ParagraphView4();)
-DEF_SAMPLE(return new ParagraphView5();)
-DEF_SAMPLE(return new ParagraphView6();)
-DEF_SAMPLE(return new ParagraphView7();)
-DEF_SAMPLE(return new ParagraphView8();)
-DEF_SAMPLE(return new ParagraphView9();)
-DEF_SAMPLE(return new ParagraphView10();)
-DEF_SAMPLE(return new ParagraphView11();)
-DEF_SAMPLE(return new ParagraphView12();)
-DEF_SAMPLE(return new ParagraphView14();)
-DEF_SAMPLE(return new ParagraphView15();)
-DEF_SAMPLE(return new ParagraphView16();)
-DEF_SAMPLE(return new ParagraphView17();)
-DEF_SAMPLE(return new ParagraphView18();)
-DEF_SAMPLE(return new ParagraphView19();)
-DEF_SAMPLE(return new ParagraphView20();)
diff --git a/third_party/skia/samplecode/SamplePatch.cpp b/third_party/skia/samplecode/SamplePatch.cpp
index 3fd7d3d..98dde31 100644
--- a/third_party/skia/samplecode/SamplePatch.cpp
+++ b/third_party/skia/samplecode/SamplePatch.cpp
@@ -34,7 +34,7 @@
SkBitmap bm;
decode_file(GetResourceAsData("images/dog.jpg"), &bm);
*size = SkIPoint{bm.width(), bm.height()};
- return bm.makeShader();
+ return bm.makeShader(SkSamplingOptions(SkFilterMode::kLinear));
}
static sk_sp<SkShader> make_shader1(const SkIPoint& size) {
@@ -241,7 +241,6 @@
SkPaint paint;
paint.setDither(true);
- paint.setFilterQuality(kLow_SkFilterQuality);
canvas->translate(DX, DY);
@@ -314,7 +313,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
} // namespace
DEF_SAMPLE( return new PatchView(); )
@@ -345,8 +344,7 @@
int vertCount = pts.count();
int indexCount = 0; // no texture
- unsigned flags = SkVertices::kHasColors_BuilderFlag |
- SkVertices::kIsNonVolatile_BuilderFlag;
+ unsigned flags = SkVertices::kHasColors_BuilderFlag;
SkVertices::Builder builder(SkVertices::kTriangleStrip_VertexMode,
vertCount, indexCount, flags);
memcpy(builder.positions(), pts.begin(), vertCount * sizeof(SkPoint));
@@ -416,7 +414,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
} // namespace
DEF_SAMPLE( return new PseudoInkView(); )
@@ -503,7 +501,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
} // namespace
DEF_SAMPLE( return new ManyStrokesView(); )
diff --git a/third_party/skia/samplecode/SamplePath.cpp b/third_party/skia/samplecode/SamplePath.cpp
index 478f6a0..ac725d9 100644
--- a/third_party/skia/samplecode/SamplePath.cpp
+++ b/third_party/skia/samplecode/SamplePath.cpp
@@ -11,7 +11,7 @@
#include "include/core/SkColorPriv.h"
#include "include/core/SkFont.h"
#include "include/core/SkGraphics.h"
-#include "include/core/SkPath.h"
+#include "include/core/SkPathBuilder.h"
#include "include/core/SkRegion.h"
#include "include/core/SkShader.h"
#include "include/core/SkTime.h"
@@ -195,7 +195,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new PathView; )
@@ -279,38 +279,29 @@
canvas->drawPath(path, fSkeletonPaint);
}
- bool onClick(Click* click) override {
- int32_t index;
- if (click->fMeta.findS32("index", &index)) {
- SkASSERT((unsigned)index < N);
- fPts[index] = click->fCurr;
- return true;
- }
- return false;
- }
-
Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
const SkScalar tol = 4;
const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
for (int i = 0; i < N; ++i) {
if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
- Click* click = new Click();
- click->fMeta.setS32("index", i);
- return click;
+ return new Click([this, i](Click* c) {
+ fPts[i] = c->fCurr;
+ return true;
+ });
}
}
return nullptr;
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new ArcToView; )
/////////////
class FatStroke : public Sample {
- bool fClosed, fShowStroke, fShowHidden, fShowSkeleton;
+ bool fClosed, fShowStroke, fShowHidden, fShowSkeleton, fAsCurves = false;
int fJoinType, fCapType;
float fWidth = 30;
SkPaint fPtsPaint, fHiddenPaint, fSkeletonPaint, fStrokePaint;
@@ -366,6 +357,7 @@
case '4': this->toggle3(fJoinType); return true;
case '5': this->toggle3(fCapType); return true;
case '6': this->toggle(fClosed); return true;
+ case 'c': this->toggle(fAsCurves); return true;
case '-': fWidth -= 5; return true;
case '=': fWidth += 5; return true;
default: break;
@@ -375,8 +367,15 @@
void makePath(SkPath* path) {
path->moveTo(fPts[0]);
- for (int i = 1; i < N; ++i) {
- path->lineTo(fPts[i]);
+ if (fAsCurves) {
+ for (int i = 1; i < N-2; ++i) {
+ path->quadTo(fPts[i], (fPts[i+1] + fPts[i]) * 0.5f);
+ }
+ path->quadTo(fPts[N-2], fPts[N-1]);
+ } else {
+ for (int i = 1; i < N; ++i) {
+ path->lineTo(fPts[i]);
+ }
}
if (fClosed) {
path->close();
@@ -407,31 +406,22 @@
canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint);
}
- bool onClick(Click* click) override {
- int32_t index;
- if (click->fMeta.findS32("index", &index)) {
- SkASSERT((unsigned)index < N);
- fPts[index] = click->fCurr;
- return true;
- }
- return false;
- }
-
Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
const SkScalar tol = 4;
const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
for (int i = 0; i < N; ++i) {
if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
- Click* click = new Click();
- click->fMeta.setS32("index", i);
- return click;
+ return new Click([this, i](Click* c) {
+ fPts[i] = c->fCurr;
+ return true;
+ });
}
}
return nullptr;
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new FatStroke; )
@@ -524,31 +514,22 @@
}
}
- bool onClick(Click* click) override {
- int32_t index;
- if (click->fMeta.findS32("index", &index)) {
- SkASSERT((unsigned)index < N);
- fPts[index] = click->fCurr;
- return true;
- }
- return false;
- }
-
Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
const SkScalar tol = 8;
const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
for (int i = 0; i < N; ++i) {
if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
- Click* click = new Click();
- click->fMeta.setS32("index", i);
- return click;
+ return new Click([this, i](Click* c) {
+ fPts[i] = c->fCurr;
+ return true;
+ });
}
}
return this->INHERITED::onFindClickHandler(x, y, modi);
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new CubicCurve; )
@@ -581,6 +562,7 @@
SkScalar fT = 0.5f;
bool fShowSub = false;
bool fShowFlatness = false;
+ bool fShowInnerQuads = false;
SkScalar fScale = 0.75;
CubicCurve2() {
@@ -603,18 +585,25 @@
case 'f': fShowFlatness = !fShowFlatness; break;
case '-': fT -= 1.0f / 32; break;
case '=': fT += 1.0f / 32; break;
+ case 'q': fShowInnerQuads = !fShowInnerQuads; break;
default: return false;
}
fT = std::min(1.0f, std::max(0.0f, fT));
return true;
}
+ static void Dot(SkCanvas* canvas, SkPoint p, SkScalar radius, SkColor c) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(c);
+ canvas->drawCircle(p.fX, p.fY, radius, paint);
+ }
+
void showFrame(SkCanvas* canvas, const SkPoint pts[], int count, const SkPaint& p) {
SkPaint paint(p);
SkPoint storage[3 + 2 + 1];
SkPoint* tmp = storage;
const SkPoint* prev = pts;
- int n = count;
for (int n = count; n > 0; --n) {
for (int i = 0; i < n; ++i) {
canvas->drawLine(prev[i], prev[i+1], paint);
@@ -626,9 +615,9 @@
paint.setColor(SK_ColorBLUE);
paint.setStyle(SkPaint::kFill_Style);
- n = tmp - storage;
+ int n = tmp - storage;
for (int i = 0; i < n; ++i) {
- canvas->drawCircle(storage[i].fX, storage[i].fY, 4, paint);
+ Dot(canvas, storage[i], 4, SK_ColorBLUE);
}
}
@@ -672,6 +661,33 @@
// not sure we can get here
}
+ void showInnerQuads(SkCanvas* canvas) {
+ auto draw_quad = [canvas](SkPoint a, SkPoint b, SkPoint c, SkColor color) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStroke(true);
+ paint.setColor(color);
+
+ canvas->drawPath(SkPathBuilder().moveTo(a).quadTo(b, c).detach(), paint);
+ };
+
+ SkPoint p0 = SkEvalQuadAt(&fPts[0], fT),
+ p1 = SkEvalQuadAt(&fPts[1], fT),
+ p2 = lerp(p0, p1, fT);
+
+ draw_quad(fPts[0], fPts[1], fPts[2], SK_ColorRED);
+ Dot(canvas, p0, 4, SK_ColorRED);
+
+ draw_quad(fPts[1], fPts[2], fPts[3], SK_ColorBLUE);
+ Dot(canvas, p1, 4, SK_ColorBLUE);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(0xFF008800);
+ canvas->drawLine(p0, p1, paint);
+ Dot(canvas, p2, 4, 0xFF00AA00);
+ }
+
void onDrawContent(SkCanvas* canvas) override {
SkPaint paint;
paint.setAntiAlias(true);
@@ -702,13 +718,20 @@
this->showFlattness(canvas);
}
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(SK_ColorRED);
- for (SkPoint p : fPts) {
- canvas->drawCircle(p.fX, p.fY, 7, paint);
+ if (fShowInnerQuads) {
+ this->showInnerQuads(canvas);
}
- {
+ paint.setColor(SK_ColorGRAY);
+ paint.setStroke(true);
+ canvas->drawPath(SkPathBuilder().addPolygon(fPts, 4, false).detach(), paint);
+ canvas->drawPath(SkPathBuilder().addPolygon(fQuad, 3, false).detach(), paint);
+
+ for (SkPoint p : fPts) {
+ Dot(canvas, p, 7, SK_ColorBLACK);
+ }
+
+ if ((false)) {
SkScalar ts[2];
int n = SkFindCubicInflections(fPts, ts);
for (int i = 0; i < n; ++i) {
@@ -720,31 +743,22 @@
}
- bool onClick(Click* click) override {
- int32_t index;
- if (click->fMeta.findS32("index", &index)) {
- SkASSERT((unsigned)index < N);
- fPts[index] = click->fCurr;
- return true;
- }
- return false;
- }
-
Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
const SkScalar tol = 8;
const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
for (int i = 0; i < N; ++i) {
if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
- Click* click = new Click();
- click->fMeta.setS32("index", i);
- return click;
+ return new Click([this, i](Click* c) {
+ fPts[i] = c->fCurr;
+ return true;
+ });
}
}
return this->INHERITED::onFindClickHandler(x, y, modi);
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new CubicCurve2; )
diff --git a/third_party/skia/samplecode/SamplePathClip.cpp b/third_party/skia/samplecode/SamplePathClip.cpp
index c7852ab..8db008d 100644
--- a/third_party/skia/samplecode/SamplePathClip.cpp
+++ b/third_party/skia/samplecode/SamplePathClip.cpp
@@ -53,16 +53,14 @@
}
Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
- return new Click();
- }
-
- bool onClick(Click* click) override {
- fCenter.set(click->fCurr.fX, click->fCurr.fY);
- return false;
+ return new Click([&](Click* c) {
+ fCenter = c->fCurr;
+ return false;
+ });
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new PathClipView; )
@@ -298,11 +296,11 @@
bool onClick(Click* click) override {
((MyClick*)click)->handleMove();
- return false;
+ return true;
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
DEF_SAMPLE( return new EdgeClipView; )
diff --git a/third_party/skia/samplecode/SamplePathEffects.cpp b/third_party/skia/samplecode/SamplePathEffects.cpp
index ccdc541..5ed3241 100644
--- a/third_party/skia/samplecode/SamplePathEffects.cpp
+++ b/third_party/skia/samplecode/SamplePathEffects.cpp
@@ -137,7 +137,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SamplePathOverstroke.cpp b/third_party/skia/samplecode/SamplePathOverstroke.cpp
index a01562b..9ebf1d4 100644
--- a/third_party/skia/samplecode/SamplePathOverstroke.cpp
+++ b/third_party/skia/samplecode/SamplePathOverstroke.cpp
@@ -191,7 +191,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SamplePathTessellators.cpp b/third_party/skia/samplecode/SamplePathTessellators.cpp
new file mode 100644
index 0000000..30f4383
--- /dev/null
+++ b/third_party/skia/samplecode/SamplePathTessellators.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2019 Google LLC.
+ *
+ * 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 "samplecode/Sample.h"
+#include "src/core/SkPathPriv.h"
+
+#if SK_SUPPORT_GPU
+
+#include "src/core/SkCanvasPriv.h"
+#include "src/gpu/GrOpFlushState.h"
+#include "src/gpu/GrRecordingContextPriv.h"
+#include "src/gpu/ops/GrDrawOp.h"
+#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
+#include "src/gpu/ops/TessellationPathRenderer.h"
+#include "src/gpu/tessellate/AffineMatrix.h"
+#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
+#include "src/gpu/tessellate/PathCurveTessellator.h"
+#include "src/gpu/tessellate/PathWedgeTessellator.h"
+#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
+#include "src/gpu/v1/SurfaceDrawContext_v1.h"
+
+namespace skgpu {
+
+namespace {
+
+enum class Mode {
+ kWedgeMiddleOut,
+ kCurveMiddleOut,
+ kWedgeTessellate,
+ kCurveTessellate
+};
+
+static const char* ModeName(Mode mode) {
+ switch (mode) {
+ case Mode::kWedgeMiddleOut:
+ return "MiddleOutShader (kWedges)";
+ case Mode::kCurveMiddleOut:
+ return "MiddleOutShader (kCurves)";
+ case Mode::kWedgeTessellate:
+ return "HardwareWedgeShader";
+ case Mode::kCurveTessellate:
+ return "HardwareCurveShader";
+ }
+ SkUNREACHABLE;
+}
+
+// Draws a path directly to the screen using a specific tessellator.
+class SamplePathTessellatorOp : public GrDrawOp {
+private:
+ DEFINE_OP_CLASS_ID
+
+ SamplePathTessellatorOp(const SkRect& drawBounds, const SkPath& path, const SkMatrix& m,
+ GrPipeline::InputFlags pipelineFlags, Mode mode)
+ : GrDrawOp(ClassID())
+ , fPath(path)
+ , fMatrix(m)
+ , fPipelineFlags(pipelineFlags)
+ , fMode(mode) {
+ this->setBounds(drawBounds, HasAABloat::kNo, IsHairline::kNo);
+ }
+ const char* name() const override { return "SamplePathTessellatorOp"; }
+ void visitProxies(const GrVisitProxyFunc&) const override {}
+ FixedFunctionFlags fixedFunctionFlags() const override {
+ return FixedFunctionFlags::kUsesHWAA;
+ }
+ GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
+ GrClampType clampType) override {
+ SkPMColor4f color;
+ return fProcessors.finalize(SK_PMColor4fWHITE, GrProcessorAnalysisCoverage::kNone, clip,
+ nullptr, caps, clampType, &color);
+ }
+ void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView&, GrAppliedClip*,
+ const GrDstProxyView&, GrXferBarrierFlags, GrLoadOp colorLoadOp) override {}
+ void onPrepare(GrOpFlushState* flushState) override {
+ constexpr static SkPMColor4f kCyan = {0,1,1,1};
+ auto alloc = flushState->allocator();
+ const SkMatrix& shaderMatrix = SkMatrix::I();
+ const SkMatrix& pathMatrix = fMatrix;
+ const GrCaps& caps = flushState->caps();
+ const GrShaderCaps& shaderCaps = *caps.shaderCaps();
+ int numVerbsToGetMiddleOut = 0;
+ int numVerbsToGetTessellation = caps.minPathVerbsForHwTessellation();
+ auto pipeline = GrSimpleMeshDrawOpHelper::CreatePipeline(flushState, std::move(fProcessors),
+ fPipelineFlags);
+ int numVerbs;
+ bool needsInnerFan;
+ switch (fMode) {
+ case Mode::kWedgeMiddleOut:
+ fTessellator = PathWedgeTessellator::Make(alloc, shaderCaps.infinitySupport());
+ numVerbs = numVerbsToGetMiddleOut;
+ needsInnerFan = false;
+ break;
+ case Mode::kCurveMiddleOut:
+ fTessellator = PathCurveTessellator::Make(alloc,
+ shaderCaps.infinitySupport());
+ numVerbs = numVerbsToGetMiddleOut;
+ needsInnerFan = true;
+ break;
+ case Mode::kWedgeTessellate:
+ fTessellator = PathWedgeTessellator::Make(alloc, shaderCaps.infinitySupport());
+ numVerbs = numVerbsToGetTessellation;
+ needsInnerFan = false;
+ break;
+ case Mode::kCurveTessellate:
+ fTessellator = PathCurveTessellator::Make(alloc,
+ shaderCaps.infinitySupport());
+ numVerbs = numVerbsToGetTessellation;
+ needsInnerFan = true;
+ break;
+ }
+ auto* tessShader = GrPathTessellationShader::Make(alloc,
+ shaderMatrix,
+ kCyan,
+ numVerbs,
+ *pipeline,
+ fTessellator->patchAttribs(),
+ caps);
+ fProgram = GrTessellationShader::MakeProgram({alloc, flushState->writeView(),
+ flushState->usesMSAASurface(),
+ &flushState->dstProxyView(),
+ flushState->renderPassBarriers(),
+ GrLoadOp::kClear, &flushState->caps()},
+ tessShader,
+ pipeline,
+ &GrUserStencilSettings::kUnused);
+
+
+ int patchPreallocCount = fTessellator->patchPreallocCount(fPath.countVerbs());
+ if (needsInnerFan) {
+ patchPreallocCount += fPath.countVerbs() - 1;
+ }
+ PatchWriter patchWriter(flushState,
+ fTessellator,
+ tessShader->maxTessellationSegments(*caps.shaderCaps()),
+ patchPreallocCount);
+
+ if (needsInnerFan) {
+ // Write out inner fan triangles.
+ AffineMatrix m(pathMatrix);
+ for (PathMiddleOutFanIter it(fPath); !it.done();) {
+ for (auto [p0, p1, p2] : it.nextStack()) {
+ auto [mp0, mp1] = m.map2Points(p0, p1);
+ auto mp2 = m.map1Point(&p2);
+ patchWriter.writeTriangle(mp0, mp1, mp2);
+ }
+ }
+ }
+
+ // Write out the curves.
+ fTessellator->writePatches(patchWriter, shaderMatrix, {pathMatrix, fPath, kCyan});
+
+ if (!tessShader->willUseTessellationShaders()) {
+ fTessellator->prepareFixedCountBuffers(flushState);
+ }
+
+ }
+ void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
+ flushState->bindPipeline(*fProgram, chainBounds);
+ fTessellator->draw(flushState, fProgram->geomProc().willUseTessellationShaders());
+ }
+
+ const SkPath fPath;
+ const SkMatrix fMatrix;
+ const GrPipeline::InputFlags fPipelineFlags;
+ const Mode fMode;
+ PathTessellator* fTessellator = nullptr;
+ GrProgramInfo* fProgram;
+ GrProcessorSet fProcessors{SkBlendMode::kSrcOver};
+
+ friend class GrOp; // For ctor.
+};
+
+} // namespace
+
+// This sample enables wireframe and visualizes the triangles generated by path tessellators.
+class SamplePathTessellators : public Sample {
+public:
+ SamplePathTessellators() {
+#if 0
+ // For viewing middle-out triangulations of the inner fan.
+ fPath.moveTo(1, 0);
+ int numSides = 32 * 3;
+ for (int i = 1; i < numSides; ++i) {
+ float theta = 2*3.1415926535897932384626433832785 * i / numSides;
+ fPath.lineTo(std::cos(theta), std::sin(theta));
+ }
+ fPath.transform(SkMatrix::Scale(200, 200));
+ fPath.transform(SkMatrix::Translate(300, 300));
+#else
+ fPath.moveTo(100, 500);
+ fPath.cubicTo(300, 400, -100, 300, 100, 200);
+ fPath.quadTo(250, 0, 400, 200);
+ fPath.conicTo(600, 350, 400, 500, fConicWeight);
+ fPath.close();
+#endif
+ }
+
+private:
+ void onDrawContent(SkCanvas*) override;
+ Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
+ bool onClick(Sample::Click*) override;
+ bool onChar(SkUnichar) override;
+
+ SkString name() override { return SkString("PathTessellators"); }
+
+ SkPath fPath;
+ GrPipeline::InputFlags fPipelineFlags = GrPipeline::InputFlags::kWireframe;
+ Mode fMode = Mode::kWedgeMiddleOut;
+
+ float fConicWeight = .5;
+
+ class Click;
+};
+
+void SamplePathTessellators::onDrawContent(SkCanvas* canvas) {
+ canvas->clear(SK_ColorBLACK);
+
+ auto ctx = canvas->recordingContext();
+ auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas);
+
+ SkString error;
+ if (!sdc || !ctx) {
+ error = "GPU Only.";
+ } else if (!skgpu::v1::TessellationPathRenderer::IsSupported(*ctx->priv().caps())) {
+ error = "TessellationPathRenderer not supported.";
+ } else if (fMode >= Mode::kWedgeTessellate &&
+ !ctx->priv().caps()->shaderCaps()->tessellationSupport()) {
+ error.printf("%s requires hardware tessellation support.", ModeName(fMode));
+ }
+ if (!error.isEmpty()) {
+ canvas->clear(SK_ColorRED);
+ SkFont font(nullptr, 20);
+ SkPaint captionPaint;
+ captionPaint.setColor(SK_ColorWHITE);
+ canvas->drawString(error.c_str(), 10, 30, font, captionPaint);
+ return;
+ }
+
+ sdc->addDrawOp(GrOp::Make<SamplePathTessellatorOp>(ctx,
+ sdc->asRenderTargetProxy()->getBoundsRect(),
+ fPath, canvas->getTotalMatrix(),
+ fPipelineFlags, fMode));
+
+ // Draw the path points.
+ SkPaint pointsPaint;
+ pointsPaint.setColor(SK_ColorBLUE);
+ pointsPaint.setStrokeWidth(8);
+ SkPath devPath = fPath;
+ devPath.transform(canvas->getTotalMatrix());
+ {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->setMatrix(SkMatrix::I());
+ SkString caption(ModeName(fMode));
+ caption.appendf(" (w=%g)", fConicWeight);
+ SkFont font(nullptr, 20);
+ SkPaint captionPaint;
+ captionPaint.setColor(SK_ColorWHITE);
+ canvas->drawString(caption, 10, 30, font, captionPaint);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, devPath.countPoints(),
+ SkPathPriv::PointData(devPath), pointsPaint);
+ }
+}
+
+class SamplePathTessellators::Click : public Sample::Click {
+public:
+ Click(int ptIdx) : fPtIdx(ptIdx) {}
+
+ void doClick(SkPath* path) {
+ SkPoint pt = path->getPoint(fPtIdx);
+ SkPathPriv::UpdatePathPoint(path, fPtIdx, pt + fCurr - fPrev);
+ }
+
+private:
+ int fPtIdx;
+};
+
+Sample::Click* SamplePathTessellators::onFindClickHandler(SkScalar x, SkScalar y,
+ skui::ModifierKey) {
+ const SkPoint* pts = SkPathPriv::PointData(fPath);
+ float fuzz = 30;
+ for (int i = 0; i < fPath.countPoints(); ++i) {
+ if (fabs(x - pts[i].x()) < fuzz && fabsf(y - pts[i].y()) < fuzz) {
+ return new Click(i);
+ }
+ }
+ return nullptr;
+}
+
+bool SamplePathTessellators::onClick(Sample::Click* click) {
+ Click* myClick = (Click*)click;
+ myClick->doClick(&fPath);
+ return true;
+}
+
+static SkPath update_weight(const SkPath& path, float w) {
+ SkPath path_;
+ for (auto [verb, pts, _] : SkPathPriv::Iterate(path)) {
+ switch (verb) {
+ case SkPathVerb::kMove:
+ path_.moveTo(pts[0]);
+ break;
+ case SkPathVerb::kLine:
+ path_.lineTo(pts[1]);
+ break;
+ case SkPathVerb::kQuad:
+ path_.quadTo(pts[1], pts[2]);
+ break;
+ case SkPathVerb::kCubic:
+ path_.cubicTo(pts[1], pts[2], pts[3]);
+ break;
+ case SkPathVerb::kConic:
+ path_.conicTo(pts[1], pts[2], (w != 1) ? w : .99f);
+ break;
+ case SkPathVerb::kClose:
+ break;
+ }
+ }
+ return path_;
+}
+
+bool SamplePathTessellators::onChar(SkUnichar unichar) {
+ switch (unichar) {
+ case 'w':
+ fPipelineFlags = (GrPipeline::InputFlags)(
+ (int)fPipelineFlags ^ (int)GrPipeline::InputFlags::kWireframe);
+ return true;
+ case 'D': {
+ fPath.dump();
+ return true;
+ }
+ case '+':
+ fConicWeight *= 2;
+ fPath = update_weight(fPath, fConicWeight);
+ return true;
+ case '=':
+ fConicWeight *= 5/4.f;
+ fPath = update_weight(fPath, fConicWeight);
+ return true;
+ case '_':
+ fConicWeight *= .5f;
+ fPath = update_weight(fPath, fConicWeight);
+ return true;
+ case '-':
+ fConicWeight *= 4/5.f;
+ fPath = update_weight(fPath, fConicWeight);
+ return true;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ fMode = (Mode)(unichar - '1');
+ return true;
+ }
+ return false;
+}
+
+Sample* MakeTessellatedPathSample() { return new SamplePathTessellators; }
+static SampleRegistry gTessellatedPathSample(MakeTessellatedPathSample);
+
+} // namespace skgpu
+
+#endif // SK_SUPPORT_GPU
diff --git a/third_party/skia/samplecode/SamplePathText.cpp b/third_party/skia/samplecode/SamplePathText.cpp
index 0b8ef02..1f5cd82 100644
--- a/third_party/skia/samplecode/SamplePathText.cpp
+++ b/third_party/skia/samplecode/SamplePathText.cpp
@@ -10,7 +10,8 @@
#include "include/core/SkPath.h"
#include "include/utils/SkRandom.h"
#include "samplecode/Sample.h"
-#include "src/core/SkStrike.h"
+#include "src/core/SkPathPriv.h"
+#include "src/core/SkScalerCache.h"
#include "src/core/SkStrikeCache.h"
#include "src/core/SkStrikeSpec.h"
#include "src/core/SkTaskGroup.h"
@@ -29,18 +30,24 @@
for (Glyph& glyph : fGlyphs) {
glyph.reset(fRand, this->width(), this->height());
}
+ fGlyphAnimator->reset(&fRand, this->width(), this->height());
}
void onOnceBeforeDraw() final {
SkFont defaultFont;
SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(defaultFont);
- auto cache = strikeSpec.findOrCreateExclusiveStrike();
+ auto strike = strikeSpec.findOrCreateStrike();
+ SkArenaAlloc alloc(1 << 12); // This is a mock SkStrikeCache.
SkPath glyphPaths[52];
for (int i = 0; i < 52; ++i) {
// I and l are rects on OS X ...
char c = "aQCDEFGH7JKLMNOPBRZTUVWXYSAbcdefghijk1mnopqrstuvwxyz"[i];
SkPackedGlyphID id(defaultFont.unicharToGlyph(c));
- sk_ignore_unused_variable(cache->getScalerContext()->getPath(id, &glyphPaths[i]));
+ SkGlyph glyph = strike->getScalerContext()->makeGlyph(id, &alloc);
+ strike->getScalerContext()->getPath(glyph, &alloc);
+ if (glyph.path()) {
+ glyphPaths[i] = *glyph.path();
+ }
}
for (int i = 0; i < kNumPaths; ++i) {
@@ -48,43 +55,30 @@
fGlyphs[i].init(fRand, p);
}
- this->INHERITED::onOnceBeforeDraw();
+ this->Sample::onOnceBeforeDraw();
this->reset();
}
- void onSizeChange() final { this->INHERITED::onSizeChange(); this->reset(); }
+ void onSizeChange() final { this->Sample::onSizeChange(); this->reset(); }
SkString name() override { return SkString(this->getName()); }
- bool onChar(SkUnichar unichar) override {
- if (unichar == 'X') {
- fDoClip = !fDoClip;
- return true;
- }
- return false;
+ bool onChar(SkUnichar) override;
+
+ bool onAnimate(double nanos) final {
+ return fGlyphAnimator->animate(nanos, this->width(), this->height());
}
void onDrawContent(SkCanvas* canvas) override {
if (fDoClip) {
SkPath deviceSpaceClipPath = fClipPath;
- deviceSpaceClipPath.transform(SkMatrix::MakeScale(this->width(), this->height()));
+ deviceSpaceClipPath.transform(SkMatrix::Scale(this->width(), this->height()));
canvas->save();
canvas->clipPath(deviceSpaceClipPath, SkClipOp::kDifference, true);
canvas->clear(SK_ColorBLACK);
canvas->restore();
canvas->clipPath(deviceSpaceClipPath, SkClipOp::kIntersect, true);
}
- this->drawGlyphs(canvas);
- }
-
- virtual void drawGlyphs(SkCanvas* canvas) {
- for (Glyph& glyph : fGlyphs) {
- SkAutoCanvasRestore acr(canvas, true);
- canvas->translate(glyph.fPosition.x(), glyph.fPosition.y());
- canvas->scale(glyph.fZoom, glyph.fZoom);
- canvas->rotate(glyph.fSpin);
- canvas->translate(-glyph.fMidpt.x(), -glyph.fMidpt.y());
- canvas->drawPath(glyph.fPath, glyph.fPaint);
- }
+ fGlyphAnimator->draw(canvas);
}
protected:
@@ -100,12 +94,36 @@
SkPoint fMidpt;
};
- Glyph fGlyphs[kNumPaths];
- SkRandom fRand{25};
- SkPath fClipPath = ToolUtils::make_star(SkRect{0, 0, 1, 1}, 11, 3);
- bool fDoClip = false;
+ class GlyphAnimator {
+ public:
+ GlyphAnimator(Glyph* glyphs) : fGlyphs(glyphs) {}
+ virtual void reset(SkRandom*, int screenWidth, int screenHeight) {}
+ virtual bool animate(double nanos, int screenWidth, int screenHeight) { return false; }
+ virtual void draw(SkCanvas* canvas) {
+ for (int i = 0; i < kNumPaths; ++i) {
+ Glyph& glyph = fGlyphs[i];
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(glyph.fPosition.x(), glyph.fPosition.y());
+ canvas->scale(glyph.fZoom, glyph.fZoom);
+ canvas->rotate(glyph.fSpin);
+ canvas->translate(-glyph.fMidpt.x(), -glyph.fMidpt.y());
+ canvas->drawPath(glyph.fPath, glyph.fPaint);
+ }
+ }
+ virtual ~GlyphAnimator() {}
- typedef Sample INHERITED;
+ protected:
+ Glyph* const fGlyphs;
+ };
+
+ class MovingGlyphAnimator;
+ class WavyGlyphAnimator;
+
+ Glyph fGlyphs[kNumPaths];
+ SkRandom fRand{25};
+ SkPath fClipPath = ToolUtils::make_star(SkRect{0, 0, 1, 1}, 11, 3);
+ bool fDoClip = false;
+ std::unique_ptr<GlyphAnimator> fGlyphAnimator = std::make_unique<GlyphAnimator>(fGlyphs);
};
void PathText::Glyph::init(SkRandom& rand, const SkPath& path) {
@@ -115,62 +133,60 @@
}
void PathText::Glyph::reset(SkRandom& rand, int w, int h) {
- int screensize = SkTMax(w, h);
+ int screensize = std::max(w, h);
const SkRect& bounds = fPath.getBounds();
SkScalar t;
fPosition = {rand.nextF() * w, rand.nextF() * h};
t = pow(rand.nextF(), 100);
fZoom = ((1 - t) * screensize / 50 + t * screensize / 3) /
- SkTMax(bounds.width(), bounds.height());
+ std::max(bounds.width(), bounds.height());
fSpin = rand.nextF() * 360;
fMidpt = {bounds.centerX(), bounds.centerY()};
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Text from paths with animated transformation matrices.
-class MovingPathText : public PathText {
+class PathText::MovingGlyphAnimator : public PathText::GlyphAnimator {
public:
- const char* getName() const override { return "MovingPathText"; }
-
- MovingPathText()
- : fFrontMatrices(kNumPaths)
- , fBackMatrices(kNumPaths) {
+ MovingGlyphAnimator(Glyph* glyphs)
+ : GlyphAnimator(glyphs)
+ , fFrontMatrices(kNumPaths)
+ , fBackMatrices(kNumPaths) {
}
- ~MovingPathText() override {
+ ~MovingGlyphAnimator() override {
fBackgroundAnimationTask.wait();
}
- void reset() override {
- const SkScalar screensize = static_cast<SkScalar>(SkTMax(this->width(), this->height()));
- this->INHERITED::reset();
+ void reset(SkRandom* rand, int screenWidth, int screenHeight) override {
+ const SkScalar screensize = static_cast<SkScalar>(std::max(screenWidth, screenHeight));
for (auto& v : fVelocities) {
for (SkScalar* d : {&v.fDx, &v.fDy}) {
- SkScalar t = pow(fRand.nextF(), 3);
- *d = ((1 - t) / 60 + t / 10) * (fRand.nextBool() ? screensize : -screensize);
+ SkScalar t = pow(rand->nextF(), 3);
+ *d = ((1 - t) / 60 + t / 10) * (rand->nextBool() ? screensize : -screensize);
}
- SkScalar t = pow(fRand.nextF(), 25);
- v.fDSpin = ((1 - t) * 360 / 7.5 + t * 360 / 1.5) * (fRand.nextBool() ? 1 : -1);
+ SkScalar t = pow(rand->nextF(), 25);
+ v.fDSpin = ((1 - t) * 360 / 7.5 + t * 360 / 1.5) * (rand->nextBool() ? 1 : -1);
}
// Get valid front data.
fBackgroundAnimationTask.wait();
- this->runAnimationTask(0, 0, this->width(), this->height());
- memcpy(fFrontMatrices, fBackMatrices, kNumPaths * sizeof(SkMatrix));
+ this->runAnimationTask(0, 0, screenWidth, screenHeight);
+ std::copy_n(fBackMatrices.get(), kNumPaths, fFrontMatrices.get());
fLastTick = 0;
}
- bool onAnimate(double nanos) final {
+ bool animate(double nanos, int screenWidth, int screenHeight) final {
fBackgroundAnimationTask.wait();
this->swapAnimationBuffers();
const double tsec = 1e-9 * nanos;
const double dt = fLastTick ? (1e-9 * nanos - fLastTick) : 0;
- fBackgroundAnimationTask.add(std::bind(&MovingPathText::runAnimationTask, this, tsec,
- dt, this->width(), this->height()));
+ fBackgroundAnimationTask.add(std::bind(&MovingGlyphAnimator::runAnimationTask, this, tsec,
+ dt, screenWidth, screenHeight));
fLastTick = 1e-9 * nanos;
return true;
}
@@ -215,7 +231,7 @@
std::swap(fFrontMatrices, fBackMatrices);
}
- void drawGlyphs(SkCanvas* canvas) override {
+ void draw(SkCanvas* canvas) override {
for (int i = 0; i < kNumPaths; ++i) {
SkAutoCanvasRestore acr(canvas, true);
canvas->concat(fFrontMatrices[i]);
@@ -229,42 +245,40 @@
SkScalar fDSpin;
};
- Velocity fVelocities[kNumPaths];
- SkAutoTMalloc<SkMatrix> fFrontMatrices;
- SkAutoTMalloc<SkMatrix> fBackMatrices;
- SkTaskGroup fBackgroundAnimationTask;
- double fLastTick;
-
- typedef PathText INHERITED;
+ Velocity fVelocities[kNumPaths];
+ SkAutoTArray<SkMatrix> fFrontMatrices;
+ SkAutoTArray<SkMatrix> fBackMatrices;
+ SkTaskGroup fBackgroundAnimationTask;
+ double fLastTick;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Text from paths with animated control points.
-class WavyPathText : public MovingPathText {
+class PathText::WavyGlyphAnimator : public PathText::MovingGlyphAnimator {
public:
- const char* getName() const override { return "WavyPathText"; }
+ WavyGlyphAnimator(Glyph* glyphs)
+ : MovingGlyphAnimator(glyphs)
+ , fFrontPaths(kNumPaths)
+ , fBackPaths(kNumPaths) {
+ }
- WavyPathText()
- : fFrontPaths(kNumPaths)
- , fBackPaths(kNumPaths) {}
-
- ~WavyPathText() override {
+ ~WavyGlyphAnimator() override {
fBackgroundAnimationTask.wait();
}
- void reset() override {
- fWaves.reset(fRand, this->width(), this->height());
- this->INHERITED::reset();
+ void reset(SkRandom* rand, int screenWidth, int screenHeight) override {
+ fWaves.reset(*rand, screenWidth, screenHeight);
+ this->MovingGlyphAnimator::reset(rand, screenWidth, screenHeight);
std::copy(fBackPaths.get(), fBackPaths.get() + kNumPaths, fFrontPaths.get());
}
/**
* Called on a background thread. Here we can only modify fBackPaths.
*/
- void runAnimationTask(double t, double dt, int w, int h) override {
+ void runAnimationTask(double t, double dt, int width, int height) override {
const float tsec = static_cast<float>(t);
- this->INHERITED::runAnimationTask(t, 0.5 * dt, w, h);
+ this->MovingGlyphAnimator::runAnimationTask(t, 0.5 * dt, width, height);
for (int i = 0; i < kNumPaths; ++i) {
const Glyph& glyph = fGlyphs[i];
@@ -280,35 +294,30 @@
backpath->reset();
backpath->setFillType(SkPathFillType::kEvenOdd);
- SkPath::RawIter iter(glyph.fPath);
- SkPath::Verb verb;
- SkPoint pts[4];
-
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ for (auto [verb, pts, w] : SkPathPriv::Iterate(glyph.fPath)) {
switch (verb) {
- case SkPath::kMove_Verb: {
+ case SkPathVerb::kMove: {
SkPoint pt = fWaves.apply(tsec, matrix, pts[0]);
backpath->moveTo(pt.x(), pt.y());
break;
}
- case SkPath::kLine_Verb: {
+ case SkPathVerb::kLine: {
SkPoint endpt = fWaves.apply(tsec, matrix, pts[1]);
backpath->lineTo(endpt.x(), endpt.y());
break;
}
- case SkPath::kQuad_Verb: {
+ case SkPathVerb::kQuad: {
SkPoint controlPt = fWaves.apply(tsec, matrix, pts[1]);
SkPoint endpt = fWaves.apply(tsec, matrix, pts[2]);
backpath->quadTo(controlPt.x(), controlPt.y(), endpt.x(), endpt.y());
break;
}
- case SkPath::kClose_Verb: {
+ case SkPathVerb::kClose: {
backpath->close();
break;
}
- case SkPath::kCubic_Verb:
- case SkPath::kConic_Verb:
- case SkPath::kDone_Verb:
+ case SkPathVerb::kCubic:
+ case SkPathVerb::kConic:
SK_ABORT("Unexpected path verb");
break;
}
@@ -317,11 +326,11 @@
}
void swapAnimationBuffers() override {
- this->INHERITED::swapAnimationBuffers();
+ this->MovingGlyphAnimator::swapAnimationBuffers();
std::swap(fFrontPaths, fBackPaths);
}
- void drawGlyphs(SkCanvas* canvas) override {
+ void draw(SkCanvas* canvas) override {
for (int i = 0; i < kNumPaths; ++i) {
canvas->drawPath(fFrontPaths[i], fGlyphs[i].fPaint);
}
@@ -348,15 +357,13 @@
float fOffsets[4];
};
- SkAutoTArray<SkPath> fFrontPaths;
- SkAutoTArray<SkPath> fBackPaths;
- Waves fWaves;
-
- typedef MovingPathText INHERITED;
+ SkAutoTArray<SkPath> fFrontPaths;
+ SkAutoTArray<SkPath> fBackPaths;
+ Waves fWaves;
};
-void WavyPathText::Waves::reset(SkRandom& rand, int w, int h) {
- const double pixelsPerMeter = 0.06 * SkTMax(w, h);
+void PathText::WavyGlyphAnimator::Waves::reset(SkRandom& rand, int w, int h) {
+ const double pixelsPerMeter = 0.06 * std::max(w, h);
const double medianWavelength = 8 * pixelsPerMeter;
const double medianWaveAmplitude = 0.05 * 4 * pixelsPerMeter;
const double gravity = 9.8 * pixelsPerMeter;
@@ -375,7 +382,8 @@
}
}
-SkPoint WavyPathText::Waves::apply(float tsec, const Sk2f matrix[3], const SkPoint& pt) const {
+SkPoint PathText::WavyGlyphAnimator::Waves::apply(float tsec, const Sk2f matrix[3],
+ const SkPoint& pt) const {
constexpr static int kTablePeriod = 1 << 12;
static float sin2table[kTablePeriod + 1];
static SkOnce initTable;
@@ -422,8 +430,28 @@
return {devicePt[0] + offsetY[0] + offsetY[1], devicePt[1] - offsetX[0] - offsetX[1]};
}
+bool PathText::onChar(SkUnichar unichar) {
+ switch (unichar) {
+ case 'X':
+ fDoClip = !fDoClip;
+ return true;
+ case 'S':
+ fGlyphAnimator = std::make_unique<GlyphAnimator>(fGlyphs);
+ fGlyphAnimator->reset(&fRand, this->width(), this->height());
+ return true;
+ case 'M':
+ fGlyphAnimator = std::make_unique<MovingGlyphAnimator>(fGlyphs);
+ fGlyphAnimator->reset(&fRand, this->width(), this->height());
+ return true;
+ case 'W':
+ fGlyphAnimator = std::make_unique<WavyGlyphAnimator>(fGlyphs);
+ fGlyphAnimator->reset(&fRand, this->width(), this->height());
+ return true;
+ }
+ return false;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
-DEF_SAMPLE( return new WavyPathText; )
-DEF_SAMPLE( return new MovingPathText; )
-DEF_SAMPLE( return new PathText; )
+Sample* MakePathTextSample() { return new PathText; }
+static SampleRegistry gPathTextSample(MakePathTextSample);
diff --git a/third_party/skia/samplecode/SamplePolyToPoly.cpp b/third_party/skia/samplecode/SamplePolyToPoly.cpp
index f8caf38..41af4a0 100644
--- a/third_party/skia/samplecode/SamplePolyToPoly.cpp
+++ b/third_party/skia/samplecode/SamplePolyToPoly.cpp
@@ -50,26 +50,24 @@
(void) m2.setPolyToPoly((const SkPoint*)src1, (SkPoint*)dst1, 4);
- {
- const SkPoint src[] = {
- { SkIntToScalar(1), SkIntToScalar(0) },
- { SkIntToScalar(4), SkIntToScalar(7) },
- { SkIntToScalar(10), SkIntToScalar(2) }
- };
- const SkPoint dst[] = {
- { SkIntToScalar(4), SkIntToScalar(2) },
- { SkIntToScalar(45), SkIntToScalar(26) },
- { SkIntToScalar(32), SkIntToScalar(17) }
- };
+ const SkPoint src2[] = {
+ { SkIntToScalar(1), SkIntToScalar(0) },
+ { SkIntToScalar(4), SkIntToScalar(7) },
+ { SkIntToScalar(10), SkIntToScalar(2) }
+ };
+ const SkPoint dst2[] = {
+ { SkIntToScalar(4), SkIntToScalar(2) },
+ { SkIntToScalar(45), SkIntToScalar(26) },
+ { SkIntToScalar(32), SkIntToScalar(17) }
+ };
- SkMatrix m0;
- m0.setPolyToPoly(src, dst, 3);
- }
+ SkMatrix m0;
+ m0.setPolyToPoly(src2, dst2, 3);
}
}
protected:
- virtual SkString name() { return SkString("PolyToPolyView"); }
+ SkString name() override { return SkString("PolyToPolyView"); }
static void doDraw(SkCanvas* canvas, SkPaint* paint, const SkFont& font, const int isrc[],
const int idst[], int count) {
@@ -105,7 +103,7 @@
canvas->restore();
}
- virtual void onDrawContent(SkCanvas* canvas) {
+ void onDrawContent(SkCanvas* canvas) override {
SkPaint paint;
paint.setAntiAlias(true);
paint.setStrokeWidth(SkIntToScalar(4));
@@ -147,7 +145,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleQuadStroker.cpp b/third_party/skia/samplecode/SampleQuadStroker.cpp
index 6b679e2..bd98ad7 100644
--- a/third_party/skia/samplecode/SampleQuadStroker.cpp
+++ b/third_party/skia/samplecode/SampleQuadStroker.cpp
@@ -28,6 +28,7 @@
#include "include/utils/SkTextUtils.h"
#include "samplecode/Sample.h"
#include "src/core/SkGeometry.h"
+#include "src/core/SkPathPriv.h"
#include "src/core/SkPointPriv.h"
#include "src/core/SkStroke.h"
#include "tools/ToolUtils.h"
@@ -42,18 +43,14 @@
}
static int getOnCurvePoints(const SkPath& path, SkPoint storage[]) {
- SkPath::RawIter iter(path);
- SkPoint pts[4];
- SkPath::Verb verb;
-
int count = 0;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
switch (verb) {
- case SkPath::kMove_Verb:
- case SkPath::kLine_Verb:
- case SkPath::kQuad_Verb:
- case SkPath::kConic_Verb:
- case SkPath::kCubic_Verb:
+ case SkPathVerb::kMove:
+ case SkPathVerb::kLine:
+ case SkPathVerb::kQuad:
+ case SkPathVerb::kConic:
+ case SkPathVerb::kCubic:
storage[count++] = pts[0];
break;
default:
@@ -64,25 +61,21 @@
}
static void getContourCounts(const SkPath& path, SkTArray<int>* contourCounts) {
- SkPath::RawIter iter(path);
- SkPoint pts[4];
- SkPath::Verb verb;
-
int count = 0;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
switch (verb) {
- case SkPath::kMove_Verb:
- case SkPath::kLine_Verb:
+ case SkPathVerb::kMove:
+ case SkPathVerb::kLine:
count += 1;
break;
- case SkPath::kQuad_Verb:
- case SkPath::kConic_Verb:
+ case SkPathVerb::kQuad:
+ case SkPathVerb::kConic:
count += 2;
break;
- case SkPath::kCubic_Verb:
+ case SkPathVerb::kCubic:
count += 3;
break;
- case SkPath::kClose_Verb:
+ case SkPathVerb::kClose:
contourCounts->push_back(count);
count = 0;
break;
@@ -218,7 +211,7 @@
fText = "";
break;
case '-':
- fTextSize = SkTMax(1.0f, fTextSize - 1);
+ fTextSize = std::max(1.0f, fTextSize - 1);
break;
case '+':
case '=':
@@ -259,7 +252,7 @@
SkCanvas* canvas = fMaxSurface->getCanvas();
canvas->save();
canvas->concat(fMatrix);
- fMinSurface->draw(canvas, 0, 0, nullptr);
+ fMinSurface->draw(canvas, 0, 0);
canvas->restore();
SkPaint paint;
@@ -356,14 +349,14 @@
for (SkScalar dist = 0; dist <= total; dist += delta) {
++ribs;
}
- SkPath::RawIter iter(path);
- SkPoint pts[4];
- if (SkPath::kMove_Verb != iter.next(pts)) {
+ const uint8_t* verbs = SkPathPriv::VerbData(path);
+ if (path.countVerbs() < 2 || SkPath::kMove_Verb != verbs[0]) {
SkASSERT(0);
return;
}
- SkPath::Verb verb = iter.next(pts);
+ auto verb = static_cast<SkPath::Verb>(verbs[1]);
SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb);
+ const SkPoint* pts = SkPathPriv::PointData(path);
SkPoint pos, tan;
for (int index = 0; index < ribs; ++index) {
SkScalar t = (SkScalar) index / ribs;
@@ -379,7 +372,7 @@
tan = SkEvalQuadTangentAt(pts, t);
break;
case SkPath::kConic_Verb: {
- SkConic conic(pts, iter.conicWeight());
+ SkConic conic(pts, SkPathPriv::ConicWeightData(path)[0]);
pos = conic.evalAt(t);
tan = conic.evalTangentAt(t);
} break;
@@ -421,7 +414,7 @@
if (drawText) {
fMinSurface->getCanvas()->drawPath(path, paint);
this->copyMinToMax();
- fMaxSurface->draw(canvas, 0, 0, nullptr);
+ fMaxSurface->draw(canvas, 0, 0);
}
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
@@ -478,7 +471,7 @@
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(width);
SkPath path;
- SkScalar maxSide = SkTMax(rect.width(), rect.height()) / 2;
+ SkScalar maxSide = std::max(rect.width(), rect.height()) / 2;
SkPoint center = { rect.fLeft + maxSide, rect.fTop + maxSide };
path.addCircle(center.fX, center.fY, maxSide);
canvas->drawPath(path, paint);
@@ -721,8 +714,7 @@
MyClick(int index) : fIndex(index) {}
};
- virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
- skui::ModifierKey modi) override {
+ Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); ++i) {
if (hittest(fPts[i], x, y)) {
return new MyClick((int)i);
@@ -793,13 +785,13 @@
}
#ifdef SK_DEBUG
else if (index == (int) SK_ARRAY_COUNT(fPts) + 3) {
- gDebugStrokerError = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY,
+ gDebugStrokerError = std::max(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY,
fErrorControl, kStrokerErrorMin, kStrokerErrorMax));
gDebugStrokerErrorSet = true;
}
#endif
else if (index == (int) SK_ARRAY_COUNT(fPts) + 4) {
- fWidth = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY, fWidthControl,
+ fWidth = std::max(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY, fWidthControl,
kWidthMin, kWidthMax));
fAnimate = fWidth <= kWidthMin;
}
@@ -807,7 +799,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleRectanizer.cpp b/third_party/skia/samplecode/SampleRectanizer.cpp
index c9faa78..2b81079 100644
--- a/third_party/skia/samplecode/SampleRectanizer.cpp
+++ b/third_party/skia/samplecode/SampleRectanizer.cpp
@@ -12,8 +12,8 @@
#include "samplecode/Sample.h"
#include "src/utils/SkUTF.h"
#if SK_SUPPORT_GPU
-#include "src/gpu/GrRectanizer_pow2.h"
-#include "src/gpu/GrRectanizer_skyline.h"
+#include "src/gpu/GrRectanizerPow2.h"
+#include "src/gpu/GrRectanizerSkyline.h"
// This slide visualizes the various GrRectanizer-derived classes behavior
// for various input sets
@@ -180,7 +180,7 @@
fCurRandRect = 0;
}
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleRegion.cpp b/third_party/skia/samplecode/SampleRegion.cpp
deleted file mode 100644
index 7c16c01..0000000
--- a/third_party/skia/samplecode/SampleRegion.cpp
+++ /dev/null
@@ -1,349 +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/SkBitmap.h"
-#include "include/core/SkCanvas.h"
-#include "include/core/SkFont.h"
-#include "include/core/SkFontMetrics.h"
-#include "include/core/SkPath.h"
-#include "include/core/SkRegion.h"
-#include "include/core/SkShader.h"
-#include "include/effects/SkGradientShader.h"
-#include "samplecode/Sample.h"
-#include "src/utils/SkUTF.h"
-
-#include <math.h>
-
-static void test_strokerect(SkCanvas* canvas) {
- int width = 100;
- int height = 100;
-
- SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeA8(width*2, height*2));
- bitmap.eraseColor(SK_ColorTRANSPARENT);
-
- SkScalar dx = 20;
- SkScalar dy = 20;
-
- SkPath path;
- path.addRect(0.0f, 0.0f,
- SkIntToScalar(width), SkIntToScalar(height),
- SkPathDirection::kCW);
- SkRect r = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
-
- SkCanvas c(bitmap);
- c.translate(dx, dy);
-
- SkPaint paint;
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(1);
-
- // use the rect
- c.clear(SK_ColorTRANSPARENT);
- c.drawRect(r, paint);
- canvas->drawBitmap(bitmap, 0, 0, nullptr);
-
- // use the path
- c.clear(SK_ColorTRANSPARENT);
- c.drawPath(path, paint);
- canvas->drawBitmap(bitmap, SkIntToScalar(2*width), 0, nullptr);
-}
-
-static void drawFadingText(SkCanvas* canvas,
- const char* text, size_t len, SkScalar x, SkScalar y,
- const SkFont& font, const SkPaint& paint) {
- // Need a bounds for the text
- SkRect bounds;
- SkFontMetrics fm;
-
- font.getMetrics(&fm);
- bounds.setLTRB(x, y + fm.fTop,
- x + font.measureText(text, len, SkTextEncoding::kUTF8), y + fm.fBottom);
-
- // may need to outset bounds a little, to account for hinting and/or
- // antialiasing
- bounds.inset(-SkIntToScalar(2), -SkIntToScalar(2));
-
- canvas->saveLayer(&bounds, nullptr);
- canvas->drawSimpleText(text, len, SkTextEncoding::kUTF8, x, y, font, paint);
-
- const SkPoint pts[] = {
- { bounds.fLeft, y },
- { bounds.fRight, y }
- };
- const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
-
- // pos[1] value is where we start to fade, relative to the width
- // of our pts[] array.
- const SkScalar pos[] = { 0, 0.9f, SK_Scalar1 };
-
- SkPaint p;
- p.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 3, SkTileMode::kClamp));
- p.setBlendMode(SkBlendMode::kDstIn);
- canvas->drawRect(bounds, p);
-
- canvas->restore();
-}
-
-static void test_text(SkCanvas* canvas) {
- SkPaint paint;
- paint.setAntiAlias(true);
-
- SkFont font;
- font.setSize(20);
-
- const char* str = "Hamburgefons";
- size_t len = strlen(str);
- SkScalar x = 20;
- SkScalar y = 20;
-
- canvas->drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
-
- y += 20;
-
- const SkPoint pts[] = { { x , y },
- { x + font.measureText(str, len, SkTextEncoding::kUTF8), y } };
- const SkColor colors[] = { SK_ColorBLACK, SK_ColorBLACK, 0 };
- const SkScalar pos[] = { 0, 0.9f, 1 };
- paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos,
- SK_ARRAY_COUNT(colors),
- SkTileMode::kClamp));
- canvas->drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
-
- y += 20;
- paint.setShader(nullptr);
- drawFadingText(canvas, str, len, x, y, font, paint);
-}
-
-static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
- dst->fLeft = (int)::roundf(src.fLeft * scale);
- dst->fTop = (int)::roundf(src.fTop * scale);
- dst->fRight = (int)::roundf(src.fRight * scale);
- dst->fBottom = (int)::roundf(src.fBottom * scale);
-}
-
-static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
- SkRegion tmp;
- SkRegion::Iterator iter(src);
-
- for (; !iter.done(); iter.next()) {
- SkIRect r;
- scale_rect(&r, iter.rect(), scale);
- tmp.op(r, SkRegion::kUnion_Op);
- }
- dst->swap(tmp);
-}
-
-static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
- const SkPaint& paint) {
- SkRegion scaled;
- scale_rgn(&scaled, rgn, 0.5f);
-
- SkRegion::Iterator iter(rgn);
-
- for (; !iter.done(); iter.next())
- {
- SkRect r;
- r.set(iter.rect());
- canvas->drawRect(r, paint);
- }
-}
-
-class RegionView : public Sample {
-public:
- RegionView() {
- fBase.setLTRB(100, 100, 150, 150);
- fRect = fBase;
- fRect.inset(5, 5);
- fRect.offset(25, 25);
- this->setBGColor(0xFFDDDDDD);
- }
-
- void build_base_rgn(SkRegion* rgn) {
- rgn->setRect(fBase);
- SkIRect r = fBase;
- r.offset(75, 20);
- rgn->op(r, SkRegion::kUnion_Op);
- }
-
- void build_rgn(SkRegion* rgn, SkRegion::Op op) {
- build_base_rgn(rgn);
- rgn->op(fRect, op);
- }
-
-
-protected:
- SkString name() override { return SkString("Regions"); }
-
- static void drawstr(SkCanvas* canvas, const char text[], const SkPoint& loc,
- bool hilite) {
- SkPaint paint;
- paint.setColor(hilite ? SK_ColorRED : 0x40FF0000);
- SkFont font;
- font.setSize(SkIntToScalar(20));
- canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, loc.fX, loc.fY, font, paint);
- }
-
- void drawPredicates(SkCanvas* canvas, const SkPoint pts[]) {
- SkRegion rgn;
- build_base_rgn(&rgn);
-
- drawstr(canvas, "Intersects", pts[0], rgn.intersects(fRect));
- drawstr(canvas, "Contains", pts[1], rgn.contains(fRect));
- }
-
- void drawOrig(SkCanvas* canvas, bool bg) {
- SkRect r;
- SkPaint paint;
-
- paint.setStyle(SkPaint::kStroke_Style);
- if (bg)
- paint.setColor(0xFFBBBBBB);
-
- SkRegion rgn;
- build_base_rgn(&rgn);
- paint_rgn(canvas, rgn, paint);
-
- r.set(fRect);
- canvas->drawRect(r, paint);
- }
-
- void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
- SkRegion rgn;
-
- this->build_rgn(&rgn, op);
-
- {
- SkRegion tmp, tmp2(rgn);
-
- tmp = tmp2;
- tmp.translate(5, -3);
-
- {
- char buffer[1000];
- SkDEBUGCODE(size_t size = ) tmp.writeToMemory(nullptr);
- SkASSERT(size <= sizeof(buffer));
- SkDEBUGCODE(size_t size2 = ) tmp.writeToMemory(buffer);
- SkASSERT(size == size2);
-
- SkRegion tmp3;
- SkDEBUGCODE(size2 = ) tmp3.readFromMemory(buffer, 1000);
- SkASSERT(size == size2);
-
- SkASSERT(tmp3 == tmp);
- }
-
- rgn.translate(20, 30, &tmp);
- SkASSERT(rgn.isEmpty() || tmp != rgn);
- tmp.translate(-20, -30);
- SkASSERT(tmp == rgn);
- }
-
- this->drawOrig(canvas, true);
-
- SkPaint paint;
- paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
- paint_rgn(canvas, rgn, paint);
-
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(color);
- paint_rgn(canvas, rgn, paint);
- }
-
- void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
- SkRegion rgn;
- SkPath path;
-
- this->build_rgn(&rgn, op);
- rgn.getBoundaryPath(&path);
-
- this->drawOrig(canvas, true);
-
- SkPaint paint;
-
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
- canvas->drawPath(path, paint);
- paint.setColor(color);
- paint.setStyle(SkPaint::kStroke_Style);
- canvas->drawPath(path, paint);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- if (false) { // avoid bit rot, suppress warning
- test_strokerect(canvas);
- return;
- }
- if (false) { // avoid bit rot, suppress warning
- test_text(canvas);
- return;
- }
-
- const SkPoint origins[] = {
- { 30*SK_Scalar1, 50*SK_Scalar1 },
- { 150*SK_Scalar1, 50*SK_Scalar1 },
- };
- this->drawPredicates(canvas, origins);
-
- static const struct {
- SkColor fColor;
- const char* fName;
- SkRegion::Op fOp;
- } gOps[] = {
- { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
- { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
- { 0xFF008800, "Union", SkRegion::kUnion_Op },
- { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
- };
-
- SkFont font;
- font.setSize(SK_Scalar1*24);
-
- this->drawOrig(canvas, false);
- canvas->save();
- canvas->translate(SkIntToScalar(200), 0);
- this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
- canvas->restore();
-
- canvas->translate(0, SkIntToScalar(200));
-
- for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
- canvas->drawSimpleText(gOps[op].fName, strlen(gOps[op].fName), SkTextEncoding::kUTF8,
- SkIntToScalar(75), SkIntToScalar(50), font, SkPaint());
-
- this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
-
- canvas->save();
- canvas->translate(0, SkIntToScalar(200));
- this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
- canvas->restore();
-
- canvas->translate(SkIntToScalar(200), 0);
- }
- }
-
- virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
- skui::ModifierKey modi) override {
- return fRect.contains(SkScalarRoundToInt(x),
- SkScalarRoundToInt(y)) ? new Click() : nullptr;
- }
-
- bool onClick(Click* click) override {
- fRect.offset(click->fCurr.fX - click->fPrev.fX,
- click->fCurr.fY - click->fPrev.fY);
- return true;
- }
-
-private:
- SkIRect fBase, fRect;
-
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new RegionView(); )
diff --git a/third_party/skia/samplecode/SampleRepeatTile.cpp b/third_party/skia/samplecode/SampleRepeatTile.cpp
index 3b7dea0..4022db6 100644
--- a/third_party/skia/samplecode/SampleRepeatTile.cpp
+++ b/third_party/skia/samplecode/SampleRepeatTile.cpp
@@ -35,7 +35,7 @@
SkBitmap bm;
make_bitmap(&bm);
- paint->setShader(bm.makeShader(tm, tm));
+ paint->setShader(bm.makeShader(tm, tm, SkSamplingOptions()));
}
class RepeatTileView : public Sample {
@@ -57,7 +57,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleSG.cpp b/third_party/skia/samplecode/SampleSG.cpp
index bb2bf89..1fa8994 100644
--- a/third_party/skia/samplecode/SampleSG.cpp
+++ b/third_party/skia/samplecode/SampleSG.cpp
@@ -52,7 +52,7 @@
SampleSG() {
fGroup = sksg::Group::Make();
- fScene = sksg::Scene::Make(fGroup, sksg::AnimatorList());
+ fScene = sksg::Scene::Make(fGroup);
auto r = sksg::Rect::Make({20, 20, 400, 300});
auto p = sksg::Color::Make(SK_ColorRED);
@@ -101,7 +101,7 @@
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleSVGFile.cpp b/third_party/skia/samplecode/SampleSVGFile.cpp
index 9fb62ed..b607d9a 100644
--- a/third_party/skia/samplecode/SampleSVGFile.cpp
+++ b/third_party/skia/samplecode/SampleSVGFile.cpp
@@ -7,11 +7,12 @@
#include "include/core/SkTypes.h"
-#ifdef SK_XML
+#if defined(SK_ENABLE_SVG)
-#include "experimental/svg/model/SkSVGDOM.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkStream.h"
+#include "modules/svg/include/SkSVGDOM.h"
+#include "modules/svg/include/SkSVGNode.h"
#include "samplecode/Sample.h"
#include "src/core/SkOSFile.h"
#include "src/utils/SkOSPath.h"
@@ -29,17 +30,11 @@
void onOnceBeforeDraw() override {
SkFILEStream svgStream(fPath.c_str());
if (!svgStream.isValid()) {
- SkDebugf("file not found: \"path\"\n", fPath.c_str());
+ SkDebugf("file not found: \"%s\"\n", fPath.c_str());
return;
}
- SkDOM xmlDom;
- if (!xmlDom.build(svgStream)) {
- SkDebugf("XML parsing failed: \"path\"\n", fPath.c_str());
- return;
- }
-
- fDom = SkSVGDOM::MakeFromDOM(xmlDom);
+ fDom = SkSVGDOM::MakeFromStream(svgStream);
if (fDom) {
fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
}
@@ -66,7 +61,7 @@
SkString fPath;
SkString fLabel;
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
} // anonymous namespace
@@ -75,4 +70,4 @@
Sample* CreateSampleSVGFileView(const SkString& filename) {
return new SVGFileView(filename);
}
-#endif // SK_XML
+#endif // defined(SK_ENABLE_SVG)
diff --git a/third_party/skia/samplecode/SampleShaders.cpp b/third_party/skia/samplecode/SampleShaders.cpp
deleted file mode 100644
index fb3fec9..0000000
--- a/third_party/skia/samplecode/SampleShaders.cpp
+++ /dev/null
@@ -1,82 +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/SkShader.h"
-#include "include/effects/SkGradientShader.h"
-#include "samplecode/DecodeFile.h"
-#include "samplecode/Sample.h"
-#include "tools/Resources.h"
-
-namespace {
-static sk_sp<SkShader> make_bitmapfade(const SkBitmap& bm) {
- SkPoint pts[2] = {
- {0, 0},
- {0, (float)bm.height()},
- };
- SkColor colors[2] = {
- SkColorSetARGB(255, 0, 0, 0),
- SkColorSetARGB(0, 0, 0, 0),
- };
- return SkShaders::Blend(SkBlendMode::kDstIn,
- bm.makeShader(),
- SkGradientShader::MakeLinear(pts, colors, nullptr, 2,
- SkTileMode::kClamp));
-}
-
-static sk_sp<SkShader> make_blend_shader() {
- SkPoint pts[2];
- SkColor colors[2];
-
- pts[0].set(0, 0);
- pts[1].set(SkIntToScalar(100), 0);
- colors[0] = SK_ColorRED;
- colors[1] = SK_ColorBLUE;
- auto shaderA = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
-
- pts[0].set(0, 0);
- pts[1].set(0, SkIntToScalar(100));
- colors[0] = SK_ColorBLACK;
- colors[1] = SkColorSetARGB(0x80, 0, 0, 0);
- auto shaderB = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
-
- return SkShaders::Blend(SkBlendMode::kDstIn, std::move(shaderA), std::move(shaderB));
-}
-
-struct ShaderView : public Sample {
- sk_sp<SkShader> fShader;
- sk_sp<SkShader> fShaderFade;
- SkBitmap fBitmap;
-
- void onOnceBeforeDraw() override {
- decode_file(GetResourceAsData("images/dog.jpg"), &fBitmap);
- fShader = make_blend_shader();
- fShaderFade = make_bitmapfade(fBitmap);
- }
-
- SkString name() override { return SkString("Shaders"); }
-
- void onDrawContent(SkCanvas* canvas) override {
- canvas->drawBitmap(fBitmap, 0, 0);
- canvas->translate(20, 120);
-
- SkPaint paint;
- paint.setColor(SK_ColorGREEN);
- canvas->drawRect(SkRect{0, 0, 100, 100}, paint);
- paint.setShader(fShader);
- canvas->drawRect(SkRect{0, 0, 100, 100}, paint);
-
- canvas->translate(SkIntToScalar(110), 0);
-
- paint.setShader(nullptr);
- canvas->drawRect(SkRect{0, 0, 120, 80}, paint);
- paint.setShader(fShaderFade);
- canvas->drawRect(SkRect{0, 0, 120, 80}, paint);
- }
-};
-} // namespace
-DEF_SAMPLE( return new ShaderView(); )
diff --git a/third_party/skia/samplecode/SampleShadowColor.cpp b/third_party/skia/samplecode/SampleShadowColor.cpp
index e0dd7fe..7313bda 100644
--- a/third_party/skia/samplecode/SampleShadowColor.cpp
+++ b/third_party/skia/samplecode/SampleShadowColor.cpp
@@ -74,11 +74,11 @@
handled = true;
break;
case '>':
- fZIndex = SkTMin(9, fZIndex+1);
+ fZIndex = std::min(9, fZIndex+1);
handled = true;
break;
case '<':
- fZIndex = SkTMax(0, fZIndex-1);
+ fZIndex = std::max(0, fZIndex-1);
handled = true;
break;
default:
@@ -115,9 +115,9 @@
if (paint.getColor() != SK_ColorBLACK) {
SkColor color = paint.getColor();
- uint8_t max = SkTMax(SkTMax(SkColorGetR(color), SkColorGetG(color)),
+ uint8_t max = std::max(std::max(SkColorGetR(color), SkColorGetG(color)),
SkColorGetB(color));
- uint8_t min = SkTMin(SkTMin(SkColorGetR(color), SkColorGetG(color)),
+ uint8_t min = std::min(std::min(SkColorGetR(color), SkColorGetG(color)),
SkColorGetB(color));
SkScalar luminance = 0.5f*(max + min) / 255.f;
SkScalar alpha = (.6 - .4*luminance)*luminance*luminance + 0.3f;
@@ -221,7 +221,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleShadowReference.cpp b/third_party/skia/samplecode/SampleShadowReference.cpp
index db8e9db..76439fb 100644
--- a/third_party/skia/samplecode/SampleShadowReference.cpp
+++ b/third_party/skia/samplecode/SampleShadowReference.cpp
@@ -191,7 +191,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleShadowUtils.cpp b/third_party/skia/samplecode/SampleShadowUtils.cpp
index 86151c1..e313875 100644
--- a/third_party/skia/samplecode/SampleShadowUtils.cpp
+++ b/third_party/skia/samplecode/SampleShadowUtils.cpp
@@ -9,7 +9,6 @@
#include "include/core/SkColorFilter.h"
#include "include/core/SkPath.h"
#include "include/core/SkPoint3.h"
-#include "include/effects/SkBlurMaskFilter.h"
#include "include/pathops/SkPathOps.h"
#include "include/utils/SkCamera.h"
#include "include/utils/SkShadowUtils.h"
@@ -172,13 +171,11 @@
SkScalar dy = 0;
SkTDArray<SkMatrix> matrices;
matrices.push()->reset();
- SkMatrix* m = matrices.push();
- m->setRotate(33.f, 25.f, 25.f);
- m->postScale(1.2f, 0.8f, 25.f, 25.f);
- SkPaint paint;
- paint.setColor(SK_ColorGREEN);
- paint.setAntiAlias(true);
- SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, SkTMax(1.0f, kHeight + fZDelta));
+ matrices.push()->setRotate(33.f, 25.f, 25.f).postScale(1.2f, 0.8f, 25.f, 25.f);
+ SkPaint greenPaint;
+ greenPaint.setColor(SK_ColorGREEN);
+ greenPaint.setAntiAlias(true);
+ SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, std::max(1.0f, kHeight + fZDelta));
// convex paths
for (auto& m : matrices) {
@@ -198,13 +195,13 @@
canvas->save();
canvas->concat(m);
- this->drawShadowedPath(canvas, path, zPlaneParams, paint, kAmbientAlpha,
+ this->drawShadowedPath(canvas, path, zPlaneParams, greenPaint, kAmbientAlpha,
lightPos, kLightR, kSpotAlpha, flags);
canvas->restore();
canvas->translate(dx, 0);
x += dx;
- dy = SkTMax(dy, postMBounds.height() + kPad + kHeight);
+ dy = std::max(dy, postMBounds.height() + kPad + kHeight);
}
}
}
@@ -224,13 +221,13 @@
canvas->save();
canvas->concat(m);
- this->drawShadowedPath(canvas, path, zPlaneParams, paint, kAmbientAlpha, lightPos,
- kLightR, kSpotAlpha, kNone_ShadowFlag);
+ this->drawShadowedPath(canvas, path, zPlaneParams, greenPaint, kAmbientAlpha,
+ lightPos, kLightR, kSpotAlpha, kNone_ShadowFlag);
canvas->restore();
canvas->translate(dx, 0);
x += dx;
- dy = SkTMax(dy, postMBounds.height() + kPad + kHeight);
+ dy = std::max(dy, postMBounds.height() + kPad + kHeight);
}
}
@@ -239,16 +236,16 @@
if (invCanvasM.invert(&invCanvasM)) {
canvas->save();
canvas->concat(invCanvasM);
- SkPaint paint;
- paint.setColor(SK_ColorBLACK);
- paint.setAntiAlias(true);
- canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, paint);
+ SkPaint blackPaint;
+ blackPaint.setColor(SK_ColorBLACK);
+ blackPaint.setAntiAlias(true);
+ canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, blackPaint);
canvas->restore();
}
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleShip.cpp b/third_party/skia/samplecode/SampleShip.cpp
index 8fdc9eb..a20f8b2 100644
--- a/third_party/skia/samplecode/SampleShip.cpp
+++ b/third_party/skia/samplecode/SampleShip.cpp
@@ -10,6 +10,7 @@
#include "include/core/SkRSXform.h"
#include "include/core/SkSurface.h"
#include "samplecode/Sample.h"
+#include "src/core/SkPaintPriv.h"
#include "tools/Resources.h"
#include "tools/timer/Timer.h"
@@ -20,25 +21,26 @@
static const int kHeight = 640;
typedef void (*DrawAtlasProc)(SkCanvas*, SkImage*, const SkRSXform[], const SkRect[],
-const SkColor[], int, const SkRect*, const SkPaint*);
+const SkColor[], int, const SkRect*, const SkSamplingOptions&, const SkPaint*);
static void draw_atlas(SkCanvas* canvas, SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count, const SkRect* cull,
- const SkPaint* paint) {
- canvas->drawAtlas(atlas, xform, tex, colors, count, SkBlendMode::kModulate, cull, paint);
+ const SkSamplingOptions& sampling, const SkPaint* paint) {
+ canvas->drawAtlas(atlas, xform, tex, colors, count, SkBlendMode::kModulate, sampling,
+ cull, paint);
}
static void draw_atlas_sim(SkCanvas* canvas, SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count, const SkRect* cull,
- const SkPaint* paint) {
+ const SkSamplingOptions& sampling, const SkPaint* paint) {
for (int i = 0; i < count; ++i) {
SkMatrix matrix;
matrix.setRSXform(xform[i]);
canvas->save();
canvas->concat(matrix);
- canvas->drawImageRect(atlas, tex[i], tex[i].makeOffset(-tex[i].x(), -tex[i].y()), paint,
- SkCanvas::kFast_SrcRectConstraint);
+ canvas->drawImageRect(atlas, tex[i], tex[i].makeOffset(-tex[i].x(), -tex[i].y()),
+ sampling, paint, SkCanvas::kFast_SrcRectConstraint);
canvas->restore();
}
}
@@ -96,7 +98,6 @@
}
SkPaint paint;
- paint.setFilterQuality(kLow_SkFilterQuality);
paint.setColor(SK_ColorWHITE);
SkScalar anchorX = fAtlas->width()*0.5f;
@@ -117,7 +118,8 @@
fXform[i].fTy += dy;
}
- fProc(canvas, fAtlas.get(), fXform, fTex, nullptr, kGrid*kGrid+1, nullptr, &paint);
+ fProc(canvas, fAtlas.get(), fXform, fTex, nullptr, kGrid*kGrid+1, nullptr,
+ SkSamplingOptions(SkFilterMode::kLinear), &paint);
}
bool onAnimate(double nanos) override {
@@ -135,7 +137,7 @@
SkRSXform fXform[kGrid*kGrid+1];
SkRect fTex[kGrid*kGrid+1];
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleSimpleStroker.cpp b/third_party/skia/samplecode/SampleSimpleStroker.cpp
new file mode 100644
index 0000000..651d2ed
--- /dev/null
+++ b/third_party/skia/samplecode/SampleSimpleStroker.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2020 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/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkPath.h"
+#include "include/utils/SkParsePath.h"
+#include "samplecode/Sample.h"
+
+#include "src/core/SkGeometry.h"
+
+namespace {
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkPoint rotate90(const SkPoint& p) { return {p.fY, -p.fX}; }
+static SkPoint rotate180(const SkPoint& p) { return p * -1; }
+static SkPoint setLength(SkPoint p, float len) {
+ if (!p.setLength(len)) {
+ SkDebugf("Failed to set point length\n");
+ }
+ return p;
+}
+static bool isClockwise(const SkPoint& a, const SkPoint& b) { return a.cross(b) > 0; }
+
+//////////////////////////////////////////////////////////////////////////////
+// Testing ground for a new stroker implementation
+
+/** Helper class for constructing paths, with undo support */
+class PathRecorder {
+public:
+ SkPath getPath() const {
+ return SkPath::Make(fPoints.data(), fPoints.size(), fVerbs.data(), fVerbs.size(), nullptr,
+ 0, SkPathFillType::kWinding);
+ }
+
+ void moveTo(SkPoint p) {
+ fVerbs.push_back(SkPath::kMove_Verb);
+ fPoints.push_back(p);
+ }
+
+ void lineTo(SkPoint p) {
+ fVerbs.push_back(SkPath::kLine_Verb);
+ fPoints.push_back(p);
+ }
+
+ void close() { fVerbs.push_back(SkPath::kClose_Verb); }
+
+ void rewind() {
+ fVerbs.clear();
+ fPoints.clear();
+ }
+
+ int countPoints() const { return fPoints.size(); }
+
+ int countVerbs() const { return fVerbs.size(); }
+
+ bool getLastPt(SkPoint* lastPt) const {
+ if (fPoints.empty()) {
+ return false;
+ }
+ *lastPt = fPoints.back();
+ return true;
+ }
+
+ void setLastPt(SkPoint lastPt) {
+ if (fPoints.empty()) {
+ moveTo(lastPt);
+ } else {
+ fPoints.back().set(lastPt.fX, lastPt.fY);
+ }
+ }
+
+ const std::vector<uint8_t>& verbs() const { return fVerbs; }
+
+ const std::vector<SkPoint>& points() const { return fPoints; }
+
+private:
+ std::vector<uint8_t> fVerbs;
+ std::vector<SkPoint> fPoints;
+};
+
+class SkPathStroker2 {
+public:
+ // Returns the fill path
+ SkPath getFillPath(const SkPath& path, const SkPaint& paint);
+
+private:
+ struct PathSegment {
+ SkPath::Verb fVerb;
+ SkPoint fPoints[4];
+ };
+
+ float fRadius;
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ PathRecorder fInner, fOuter;
+
+ // Initialize stroker state
+ void initForPath(const SkPath& path, const SkPaint& paint);
+
+ // Strokes a line segment
+ void strokeLine(const PathSegment& line, bool needsMove);
+
+ // Adds an endcap to fOuter
+ enum class CapLocation { Start, End };
+ void endcap(CapLocation loc);
+
+ // Adds a join between the two segments
+ void join(const PathSegment& prev, const PathSegment& curr);
+
+ // Appends path in reverse to result
+ static void appendPathReversed(const PathRecorder& path, PathRecorder* result);
+
+ // Returns the segment unit normal
+ static SkPoint unitNormal(const PathSegment& seg, float t);
+
+ // Returns squared magnitude of line segments.
+ static float squaredLineLength(const PathSegment& lineSeg);
+};
+
+void SkPathStroker2::initForPath(const SkPath& path, const SkPaint& paint) {
+ fRadius = paint.getStrokeWidth() / 2;
+ fCap = paint.getStrokeCap();
+ fJoin = paint.getStrokeJoin();
+ fInner.rewind();
+ fOuter.rewind();
+}
+
+SkPath SkPathStroker2::getFillPath(const SkPath& path, const SkPaint& paint) {
+ initForPath(path, paint);
+
+ // Trace the inner and outer paths simultaneously. Inner will therefore be
+ // recorded in reverse from how we trace the outline.
+ SkPath::Iter it(path, false);
+ PathSegment segment, prevSegment;
+ bool firstSegment = true;
+ while ((segment.fVerb = it.next(segment.fPoints)) != SkPath::kDone_Verb) {
+ // Join to the previous segment
+ if (!firstSegment) {
+ join(prevSegment, segment);
+ }
+
+ // Stroke the current segment
+ switch (segment.fVerb) {
+ case SkPath::kLine_Verb:
+ strokeLine(segment, firstSegment);
+ break;
+ case SkPath::kMove_Verb:
+ // Don't care about multiple contours currently
+ continue;
+ default:
+ SkDebugf("Unhandled path verb %d\n", segment.fVerb);
+ break;
+ }
+
+ std::swap(segment, prevSegment);
+ firstSegment = false;
+ }
+
+ // Open contour => endcap at the end
+ const bool isClosed = path.isLastContourClosed();
+ if (isClosed) {
+ SkDebugf("Unhandled closed contour\n");
+ } else {
+ endcap(CapLocation::End);
+ }
+
+ // Walk inner path in reverse, appending to result
+ appendPathReversed(fInner, &fOuter);
+ endcap(CapLocation::Start);
+
+ return fOuter.getPath();
+}
+
+void SkPathStroker2::strokeLine(const PathSegment& line, bool needsMove) {
+ const SkPoint tangent = line.fPoints[1] - line.fPoints[0];
+ const SkPoint normal = rotate90(tangent);
+ const SkPoint offset = setLength(normal, fRadius);
+ if (needsMove) {
+ fOuter.moveTo(line.fPoints[0] + offset);
+ fInner.moveTo(line.fPoints[0] - offset);
+ }
+ fOuter.lineTo(line.fPoints[1] + offset);
+ fInner.lineTo(line.fPoints[1] - offset);
+}
+
+void SkPathStroker2::endcap(CapLocation loc) {
+ const auto buttCap = [this](CapLocation loc) {
+ if (loc == CapLocation::Start) {
+ // Back at the start of the path: just close the stroked outline
+ fOuter.close();
+ } else {
+ // Inner last pt == first pt when appending in reverse
+ SkPoint innerLastPt;
+ fInner.getLastPt(&innerLastPt);
+ fOuter.lineTo(innerLastPt);
+ }
+ };
+
+ switch (fCap) {
+ case SkPaint::kButt_Cap:
+ buttCap(loc);
+ break;
+ default:
+ SkDebugf("Unhandled endcap %d\n", fCap);
+ buttCap(loc);
+ break;
+ }
+}
+
+void SkPathStroker2::join(const PathSegment& prev, const PathSegment& curr) {
+ const auto miterJoin = [this](const PathSegment& prev, const PathSegment& curr) {
+ // Common path endpoint of the two segments is the midpoint of the miter line.
+ const SkPoint miterMidpt = curr.fPoints[0];
+
+ SkPoint before = unitNormal(prev, 1);
+ SkPoint after = unitNormal(curr, 0);
+
+ // Check who's inside and who's outside.
+ PathRecorder *outer = &fOuter, *inner = &fInner;
+ if (!isClockwise(before, after)) {
+ std::swap(inner, outer);
+ before = rotate180(before);
+ after = rotate180(after);
+ }
+
+ const float cosTheta = before.dot(after);
+ if (SkScalarNearlyZero(1 - cosTheta)) {
+ // Nearly identical normals: don't bother.
+ return;
+ }
+
+ // Before and after have the same origin and magnitude, so before+after is the diagonal of
+ // their rhombus. Origin of this vector is the midpoint of the miter line.
+ SkPoint miterVec = before + after;
+
+ // Note the relationship (draw a right triangle with the miter line as its hypoteneuse):
+ // sin(theta/2) = strokeWidth / miterLength
+ // so miterLength = strokeWidth / sin(theta/2)
+ // where miterLength is the length of the miter from outer point to inner corner.
+ // miterVec's origin is the midpoint of the miter line, so we use strokeWidth/2.
+ // Sqrt is just an application of half-angle identities.
+ const float sinHalfTheta = sqrtf(0.5 * (1 + cosTheta));
+ const float halfMiterLength = fRadius / sinHalfTheta;
+ miterVec.setLength(halfMiterLength); // TODO: miter length limit
+
+ // Outer: connect to the miter point, and then to t=0 (on outside stroke) of next segment.
+ const SkPoint dest = setLength(after, fRadius);
+ outer->lineTo(miterMidpt + miterVec);
+ outer->lineTo(miterMidpt + dest);
+
+ // Inner miter is more involved. We're already at t=1 (on inside stroke) of 'prev'.
+ // Check 2 cases to see we can directly connect to the inner miter point
+ // (midpoint - miterVec), or if we need to add extra "loop" geometry.
+ const SkPoint prevUnitTangent = rotate90(before);
+ const float radiusSquared = fRadius * fRadius;
+ // 'alpha' is angle between prev tangent and the curr inwards normal
+ const float cosAlpha = prevUnitTangent.dot(-after);
+ // Solve triangle for len^2: radius^2 = len^2 + (radius * sin(alpha))^2
+ // This is the point at which the inside "corner" of curr at t=0 will lie on a
+ // line connecting the inner and outer corners of prev at t=0. If len is below
+ // this threshold, the inside corner of curr will "poke through" the start of prev,
+ // and we'll need the inner loop geometry.
+ const float threshold1 = radiusSquared * cosAlpha * cosAlpha;
+ // Solve triangle for len^2: halfMiterLen^2 = radius^2 + len^2
+ // This is the point at which the inner miter point will lie on the inner stroke
+ // boundary of the curr segment. If len is below this threshold, the miter point
+ // moves 'inside' of the stroked outline, and we'll need the inner loop geometry.
+ const float threshold2 = halfMiterLength * halfMiterLength - radiusSquared;
+ // If a segment length is smaller than the larger of the two thresholds,
+ // we'll have to add the inner loop geometry.
+ const float maxLenSqd = std::max(threshold1, threshold2);
+ const bool needsInnerLoop =
+ squaredLineLength(prev) < maxLenSqd || squaredLineLength(curr) < maxLenSqd;
+ if (needsInnerLoop) {
+ // Connect to the miter midpoint (common path endpoint of the two segments),
+ // and then to t=0 (on inside) of the next segment. This adds an interior "loop" of
+ // geometry that handles edge cases where segment lengths are shorter than the
+ // stroke width.
+ inner->lineTo(miterMidpt);
+ inner->lineTo(miterMidpt - dest);
+ } else {
+ // Directly connect to inner miter point.
+ inner->setLastPt(miterMidpt - miterVec);
+ }
+ };
+
+ switch (fJoin) {
+ case SkPaint::kMiter_Join:
+ miterJoin(prev, curr);
+ break;
+ default:
+ SkDebugf("Unhandled join %d\n", fJoin);
+ miterJoin(prev, curr);
+ break;
+ }
+}
+
+void SkPathStroker2::appendPathReversed(const PathRecorder& path, PathRecorder* result) {
+ const int numVerbs = path.countVerbs();
+ const int numPoints = path.countPoints();
+ const std::vector<uint8_t>& verbs = path.verbs();
+ const std::vector<SkPoint>& points = path.points();
+
+ for (int i = numVerbs - 1, j = numPoints; i >= 0; i--) {
+ auto verb = static_cast<SkPath::Verb>(verbs[i]);
+ switch (verb) {
+ case SkPath::kLine_Verb: {
+ j -= 1;
+ SkASSERT(j >= 1);
+ result->lineTo(points[j - 1]);
+ break;
+ }
+ case SkPath::kMove_Verb:
+ // Ignore
+ break;
+ default:
+ SkASSERT(false);
+ break;
+ }
+ }
+}
+
+SkPoint SkPathStroker2::unitNormal(const PathSegment& seg, float t) {
+ if (seg.fVerb != SkPath::kLine_Verb) {
+ SkDebugf("Unhandled verb for unit normal %d\n", seg.fVerb);
+ }
+
+ (void)t; // Not needed for lines
+ const SkPoint tangent = seg.fPoints[1] - seg.fPoints[0];
+ const SkPoint normal = rotate90(tangent);
+ return setLength(normal, 1);
+}
+
+float SkPathStroker2::squaredLineLength(const PathSegment& lineSeg) {
+ SkASSERT(lineSeg.fVerb == SkPath::kLine_Verb);
+ const SkPoint diff = lineSeg.fPoints[1] - lineSeg.fPoints[0];
+ return diff.dot(diff);
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+class SimpleStroker : public Sample {
+ bool fShowSkiaStroke, fShowHidden, fShowSkeleton;
+ float fWidth = 175;
+ SkPaint fPtsPaint, fStrokePaint, fMirrorStrokePaint, fNewFillPaint, fHiddenPaint,
+ fSkeletonPaint;
+ inline static constexpr int kN = 3;
+
+public:
+ SkPoint fPts[kN];
+
+ SimpleStroker() : fShowSkiaStroke(true), fShowHidden(true), fShowSkeleton(true) {
+ fPts[0] = {500, 200};
+ fPts[1] = {300, 200};
+ fPts[2] = {100, 100};
+
+ fPtsPaint.setAntiAlias(true);
+ fPtsPaint.setStrokeWidth(10);
+ fPtsPaint.setStrokeCap(SkPaint::kRound_Cap);
+
+ fStrokePaint.setAntiAlias(true);
+ fStrokePaint.setStyle(SkPaint::kStroke_Style);
+ fStrokePaint.setColor(0x80FF0000);
+
+ fMirrorStrokePaint.setAntiAlias(true);
+ fMirrorStrokePaint.setStyle(SkPaint::kStroke_Style);
+ fMirrorStrokePaint.setColor(0x80FFFF00);
+
+ fNewFillPaint.setAntiAlias(true);
+ fNewFillPaint.setColor(0x8000FF00);
+
+ fHiddenPaint.setAntiAlias(true);
+ fHiddenPaint.setStyle(SkPaint::kStroke_Style);
+ fHiddenPaint.setColor(0xFF0000FF);
+
+ fSkeletonPaint.setAntiAlias(true);
+ fSkeletonPaint.setStyle(SkPaint::kStroke_Style);
+ fSkeletonPaint.setColor(SK_ColorRED);
+ }
+
+ void toggle(bool& value) { value = !value; }
+
+protected:
+ SkString name() override { return SkString("SimpleStroker"); }
+
+ bool onChar(SkUnichar uni) override {
+ switch (uni) {
+ case '1':
+ this->toggle(fShowSkeleton);
+ return true;
+ case '2':
+ this->toggle(fShowSkiaStroke);
+ return true;
+ case '3':
+ this->toggle(fShowHidden);
+ return true;
+ case '-':
+ fWidth -= 5;
+ return true;
+ case '=':
+ fWidth += 5;
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ void makePath(SkPath* path) {
+ path->moveTo(fPts[0]);
+ for (int i = 1; i < kN; ++i) {
+ path->lineTo(fPts[i]);
+ }
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ canvas->drawColor(0xFFEEEEEE);
+
+ SkPath path;
+ this->makePath(&path);
+
+ fStrokePaint.setStrokeWidth(fWidth);
+
+ // The correct result
+ if (fShowSkiaStroke) {
+ canvas->drawPath(path, fStrokePaint);
+ }
+
+ // Simple stroker result
+ SkPathStroker2 stroker;
+ SkPath fillPath = stroker.getFillPath(path, fStrokePaint);
+ canvas->drawPath(fillPath, fNewFillPaint);
+
+ if (fShowHidden) {
+ canvas->drawPath(fillPath, fHiddenPaint);
+ }
+ if (fShowSkeleton) {
+ canvas->drawPath(path, fSkeletonPaint);
+ }
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, kN, fPts, fPtsPaint);
+
+ // Draw a mirror but using Skia's stroker.
+ canvas->translate(0, 400);
+ fMirrorStrokePaint.setStrokeWidth(fWidth);
+ canvas->drawPath(path, fMirrorStrokePaint);
+ if (fShowHidden) {
+ SkPath hidden;
+ fStrokePaint.getFillPath(path, &hidden);
+ canvas->drawPath(hidden, fHiddenPaint);
+ }
+ if (fShowSkeleton) {
+ canvas->drawPath(path, fSkeletonPaint);
+ }
+ }
+
+ Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
+ const SkScalar tol = 4;
+ const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
+ for (int i = 0; i < kN; ++i) {
+ if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
+ return new Click([this, i](Click* c) {
+ fPts[i] = c->fCurr;
+ return true;
+ });
+ }
+ }
+ return nullptr;
+ }
+
+private:
+ using INHERITED = Sample;
+};
+
+DEF_SAMPLE(return new SimpleStroker;)
diff --git a/third_party/skia/samplecode/SampleSlides.cpp b/third_party/skia/samplecode/SampleSlides.cpp
index d58f4f1..a17a674 100644
--- a/third_party/skia/samplecode/SampleSlides.cpp
+++ b/third_party/skia/samplecode/SampleSlides.cpp
@@ -7,7 +7,6 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/core/SkVertices.h"
-#include "include/effects/SkBlurMaskFilter.h"
#include "include/effects/SkGradientShader.h"
#include "samplecode/Sample.h"
#include "src/core/SkBlurMask.h"
@@ -246,7 +245,7 @@
decode_file("/skimages/logo.gif", &bm);
size->set(bm.width(), bm.height());
- return bm.makeShader();
+ return bm.makeShader(SkSamplingOptions(SkFilterMode::kLinear));
}
static sk_sp<SkShader> make_shader1(const SkIPoint& size) {
@@ -363,7 +362,6 @@
SkPaint paint;
paint.setDither(true);
- paint.setFilterQuality(kLow_SkFilterQuality);
for (size_t i = 0; i < SK_ARRAY_COUNT(fRecs); i++) {
auto verts = SkVertices::MakeCopy(fRecs[i].fMode, fRecs[i].fCount,
@@ -429,7 +427,7 @@
gProc[i](&canvas);
canvas.restore();
SkString str;
- str.printf("/skimages/slide_" SK_SIZE_T_SPECIFIER ".png", i);
+ str.printf("/skimages/slide_%zu.png", i);
ToolUtils::EncodeImageToFile(str.c_str(), bm, SkEncodedImageFormat::kPNG, 100);
}
this->setBGColor(BG_COLOR);
@@ -450,7 +448,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleStringArt.cpp b/third_party/skia/samplecode/SampleStringArt.cpp
index bda466c..9f2b3b1 100644
--- a/third_party/skia/samplecode/SampleStringArt.cpp
+++ b/third_party/skia/samplecode/SampleStringArt.cpp
@@ -32,7 +32,7 @@
SkPath path;
path.moveTo(center);
- while (length < (SkScalarHalf(SkMinScalar(this->width(), this->height())) - 10.f))
+ while (length < (SkScalarHalf(std::min(this->width(), this->height())) - 10.f))
{
SkPoint rp = SkPoint::Make(length*SkScalarCos(step) + center.fX,
length*SkScalarSin(step) + center.fY);
@@ -57,7 +57,7 @@
private:
SkScalar fAngle;
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleStrokePath.cpp b/third_party/skia/samplecode/SampleStrokePath.cpp
index b22ba8d..5feb87c 100644
--- a/third_party/skia/samplecode/SampleStrokePath.cpp
+++ b/third_party/skia/samplecode/SampleStrokePath.cpp
@@ -35,9 +35,7 @@
paint.setStrokeJoin(SkPaint::kRound_Join);
paint.setStyle(SkPaint::kStroke_Style);
- SkMatrix matrix;
- matrix.setRectToRect(srcR, dstR, SkMatrix::kCenter_ScaleToFit);
- canvas->concat(matrix);
+ canvas->concat(SkMatrix::RectToRect(srcR, dstR, SkMatrix::kCenter_ScaleToFit));
canvas->drawPath(path, paint);
}
@@ -140,7 +138,8 @@
}
void onDrawContent(SkCanvas* canvas) override {
- test_huge_stroke(canvas); return;
+ test_huge_stroke(canvas);
+#if 0
canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
SkPaint paint;
@@ -198,10 +197,11 @@
canvas->translate(0, fPath.getBounds().height() * 5 / 4);
fPath.setFillType(SkPathFillType::kEvenOdd);
drawSet(canvas, &paint);
+#endif
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleStrokeRect.cpp b/third_party/skia/samplecode/SampleStrokeRect.cpp
index 669a357..d4cc4ae 100644
--- a/third_party/skia/samplecode/SampleStrokeRect.cpp
+++ b/third_party/skia/samplecode/SampleStrokeRect.cpp
@@ -13,9 +13,9 @@
StrokeRectSample() {}
protected:
- virtual SkString name() { return SkString("Stroke Rects"); }
+ SkString name() override { return SkString("Stroke Rects"); }
- virtual void onDrawContent(SkCanvas* canvas) {
+ void onDrawContent(SkCanvas* canvas) override {
SkPaint paint;
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
@@ -56,7 +56,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleStrokeVerb.cpp b/third_party/skia/samplecode/SampleStrokeVerb.cpp
new file mode 100644
index 0000000..bb90ee3
--- /dev/null
+++ b/third_party/skia/samplecode/SampleStrokeVerb.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2017 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/SkTypes.h"
+
+#if SK_SUPPORT_GPU
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkFont.h"
+#include "include/core/SkPaint.h"
+#include "include/core/SkPath.h"
+#include "samplecode/Sample.h"
+#include "src/core/SkGeometry.h"
+
+enum class VerbType {
+ kTriangles,
+ kQuadratics,
+ kCubics,
+ kConics
+};
+
+static const char* verb_type_name(VerbType verbType) {
+ switch (verbType) {
+ case VerbType::kTriangles: return "kTriangles";
+ case VerbType::kQuadratics: return "kQuadratics";
+ case VerbType::kCubics: return "kCubics";
+ case VerbType::kConics: return "kConics";
+ }
+ SkUNREACHABLE;
+};
+
+/**
+ * This sample visualizes simple strokes.
+ */
+class StrokeVerbView : public Sample {
+ void onOnceBeforeDraw() override { this->updatePath(); }
+ void onDrawContent(SkCanvas*) override;
+
+ Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
+ bool onClick(Sample::Click*) override;
+ bool onChar(SkUnichar) override;
+ SkString name() override { return SkString("StrokeVerb"); }
+
+ class Click;
+
+ void updateAndInval() { this->updatePath(); }
+
+ void updatePath();
+
+ VerbType fVerbType = VerbType::kCubics;
+
+ SkPoint fPoints[4] = {
+ {100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}};
+
+ float fConicWeight = .5;
+ float fStrokeWidth = 40;
+ SkPaint::Join fStrokeJoin = SkPaint::kMiter_Join;
+ SkPaint::Cap fStrokeCap = SkPaint::kButt_Cap;
+
+ SkPath fPath;
+};
+
+void StrokeVerbView::onDrawContent(SkCanvas* canvas) {
+ canvas->clear(SK_ColorBLACK);
+
+ SkPaint outlinePaint;
+ outlinePaint.setColor(0xff808080);
+ outlinePaint.setStyle(SkPaint::kStroke_Style);
+ outlinePaint.setStrokeWidth(fStrokeWidth);
+ outlinePaint.setStrokeJoin(fStrokeJoin);
+ outlinePaint.setStrokeCap(fStrokeCap);
+ outlinePaint.setAntiAlias(true);
+ canvas->drawPath(fPath, outlinePaint);
+
+ SkString caption;
+ caption.appendf("VerbType_%s", verb_type_name(fVerbType));
+ if (VerbType::kCubics == fVerbType) {
+ caption.appendf(" (%s)", SkCubicTypeName(SkClassifyCubic(fPoints)));
+ } else if (VerbType::kConics == fVerbType) {
+ caption.appendf(" (w=%f)", fConicWeight);
+ }
+
+ caption.appendf(" (stroke_width=%f)", fStrokeWidth);
+
+ SkPaint pointsPaint;
+ pointsPaint.setColor(SK_ColorBLUE);
+ pointsPaint.setStrokeWidth(8);
+ pointsPaint.setAntiAlias(true);
+
+ if (VerbType::kCubics == fVerbType) {
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPoints, pointsPaint);
+ } else {
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, fPoints, pointsPaint);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, fPoints + 3, pointsPaint);
+ }
+
+ SkFont font(nullptr, 20);
+ SkPaint captionPaint;
+ captionPaint.setColor(SK_ColorWHITE);
+ canvas->drawString(caption, 10, 30, font, captionPaint);
+}
+
+void StrokeVerbView::updatePath() {
+ fPath.reset();
+ fPath.moveTo(fPoints[0]);
+ switch (fVerbType) {
+ case VerbType::kCubics:
+ fPath.cubicTo(fPoints[1], fPoints[2], fPoints[3]);
+ break;
+ case VerbType::kQuadratics:
+ fPath.quadTo(fPoints[1], fPoints[3]);
+ break;
+ case VerbType::kConics:
+ fPath.conicTo(fPoints[1], fPoints[3], fConicWeight);
+ break;
+ case VerbType::kTriangles:
+ fPath.lineTo(fPoints[1]);
+ fPath.lineTo(fPoints[3]);
+ fPath.close();
+ break;
+ }
+}
+
+class StrokeVerbView::Click : public Sample::Click {
+public:
+ Click(int ptIdx) : fPtIdx(ptIdx) {}
+
+ void doClick(SkPoint points[]) {
+ if (fPtIdx >= 0) {
+ points[fPtIdx] += fCurr - fPrev;
+ } else {
+ for (int i = 0; i < 4; ++i) {
+ points[i] += fCurr - fPrev;
+ }
+ }
+ }
+
+private:
+ int fPtIdx;
+};
+
+Sample::Click* StrokeVerbView::onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) {
+ for (int i = 0; i < 4; ++i) {
+ if (VerbType::kCubics != fVerbType && 2 == i) {
+ continue;
+ }
+ if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) {
+ return new Click(i);
+ }
+ }
+ return new Click(-1);
+}
+
+bool StrokeVerbView::onClick(Sample::Click* click) {
+ Click* myClick = (Click*)click;
+ myClick->doClick(fPoints);
+ this->updateAndInval();
+ return true;
+}
+
+bool StrokeVerbView::onChar(SkUnichar unichar) {
+ if (unichar >= '1' && unichar <= '4') {
+ fVerbType = VerbType(unichar - '1');
+ this->updateAndInval();
+ return true;
+ }
+ float* valueToScale = nullptr;
+ if (VerbType::kConics == fVerbType) {
+ valueToScale = &fConicWeight;
+ } else {
+ valueToScale = &fStrokeWidth;
+ }
+ if (valueToScale) {
+ if (unichar == '+') {
+ *valueToScale *= 2;
+ this->updateAndInval();
+ return true;
+ }
+ if (unichar == '+' || unichar == '=') {
+ *valueToScale *= 5/4.f;
+ this->updateAndInval();
+ return true;
+ }
+ if (unichar == '-') {
+ *valueToScale *= 4/5.f;
+ this->updateAndInval();
+ return true;
+ }
+ if (unichar == '_') {
+ *valueToScale *= .5f;
+ this->updateAndInval();
+ return true;
+ }
+ }
+ if (unichar == 'D') {
+ SkDebugf(" SkPoint fPoints[4] = {\n");
+ SkDebugf(" {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y());
+ SkDebugf(" {%ff, %ff},\n", fPoints[1].x(), fPoints[1].y());
+ SkDebugf(" {%ff, %ff},\n", fPoints[2].x(), fPoints[2].y());
+ SkDebugf(" {%ff, %ff}\n", fPoints[3].x(), fPoints[3].y());
+ SkDebugf(" };\n");
+ return true;
+ }
+ if (unichar == 'J') {
+ fStrokeJoin = (SkPaint::Join)((fStrokeJoin + 1) % 3);
+ this->updateAndInval();
+ return true;
+ }
+ if (unichar == 'C') {
+ fStrokeCap = (SkPaint::Cap)((fStrokeCap + 1) % 3);
+ this->updateAndInval();
+ return true;
+ }
+ return false;
+}
+
+DEF_SAMPLE(return new StrokeVerbView;)
+
+#endif // SK_SUPPORT_GPU
diff --git a/third_party/skia/samplecode/SampleSubpixelTranslate.cpp b/third_party/skia/samplecode/SampleSubpixelTranslate.cpp
deleted file mode 100644
index b658bc3..0000000
--- a/third_party/skia/samplecode/SampleSubpixelTranslate.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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 "samplecode/Sample.h"
-
-#include "include/core/SkCanvas.h"
-#include "include/core/SkColorPriv.h"
-#include "include/core/SkFont.h"
-#include "include/core/SkStream.h"
-#include "include/effects/SkBlurMaskFilter.h"
-#include "include/utils/SkRandom.h"
-#include "samplecode/DecodeFile.h"
-#include "tools/Resources.h"
-
-// Intended to exercise pixel snapping observed with scaled images (and
-// with non-scaled images, but for a different reason): Bug 1145
-
-class SubpixelTranslateView : public Sample {
-public:
- SubpixelTranslateView(const char imageFilename[],
- float horizontalVelocity,
- float verticalVelocity)
- : fHorizontalVelocity(horizontalVelocity)
- , fVerticalVelocity(verticalVelocity)
- {
- if (!DecodeDataToBitmap(GetResourceAsData(imageFilename), &fBM)) {
- fBM.allocN32Pixels(1, 1);
- *(fBM.getAddr32(0,0)) = 0xFF0000FF; // red == bad
- }
- fCurPos = SkPoint::Make(0,0);
- fSize = 200;
- }
-
-protected:
- SkBitmap fBM;
- SkScalar fSize;
- float fHorizontalVelocity, fVerticalVelocity;
-
- SkPoint fCurPos;
-
- SkString name() override { return SkString("SubpixelTranslate"); }
-
- void onDrawContent(SkCanvas* canvas) override {
-
- static const SkFilterQuality gQualitys[] = {
- kNone_SkFilterQuality,
- kLow_SkFilterQuality,
- kMedium_SkFilterQuality,
- kHigh_SkFilterQuality
- };
-
- SkPaint paint;
- SkFont font(nullptr, 48);
- font.setSubpixel(true);
-
- paint.setAntiAlias(true);
- for (size_t i = 0; i < SK_ARRAY_COUNT(gQualitys); ++i) {
- paint.setFilterQuality(gQualitys[i]);
- SkRect r = SkRect::MakeXYWH( fCurPos.fX + i * (fSize + 10), fCurPos.fY, fSize, fSize );
- canvas->drawBitmapRect( fBM, r, &paint );
- }
-
- canvas->drawString("AA Scaled", fCurPos.fX + SK_ARRAY_COUNT(gQualitys) * (fSize + 10),
- fCurPos.fY + fSize/2, font, paint);
-
- paint.setAntiAlias(false);
- font.setEdging(SkFont::Edging::kAlias);
- for (size_t i = 0; i < SK_ARRAY_COUNT(gQualitys); ++i) {
- paint.setFilterQuality(gQualitys[i]);
- SkRect r = SkRect::MakeXYWH( fCurPos.fX + i * (fSize + 10), fCurPos.fY + fSize + 10, fSize, fSize );
- canvas->drawBitmapRect( fBM, r, &paint );
- }
- canvas->drawString("Scaled", fCurPos.fX + SK_ARRAY_COUNT(gQualitys) * (fSize + 10),
- fCurPos.fY + fSize + 10 + fSize/2, font, paint);
-
- paint.setAntiAlias(true);
- font.setEdging(SkFont::Edging::kAntiAlias);
- for (size_t i = 0; i < SK_ARRAY_COUNT(gQualitys); ++i) {
- paint.setFilterQuality(gQualitys[i]);
- canvas->drawBitmap( fBM, fCurPos.fX + i * (fBM.width() + 10), fCurPos.fY + 2*(fSize + 10), &paint );
- }
-
- canvas->drawString("AA No Scale",
- fCurPos.fX + SK_ARRAY_COUNT(gQualitys) * (fBM.width() + 10),
- fCurPos.fY + 2*(fSize + 10) + fSize/2, font, paint);
-
- paint.setAntiAlias(false);
- font.setEdging(SkFont::Edging::kAlias);
- for (size_t i = 0; i < SK_ARRAY_COUNT(gQualitys); ++i) {
- paint.setFilterQuality(gQualitys[i]);
- canvas->drawBitmap( fBM, fCurPos.fX + i * (fBM.width() + 10), fCurPos.fY + 2*(fSize + 10) + fBM.height() + 10, &paint );
- }
-
- canvas->drawString("No Scale", fCurPos.fX + SK_ARRAY_COUNT(gQualitys) * (fBM.width() + 10),
- fCurPos.fY + 2*(fSize + 10) + fBM.height() + 10 + fSize/2, font, paint);
-
-
- fCurPos.fX += fHorizontalVelocity;
- fCurPos.fY += fVerticalVelocity;
- }
-
-private:
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new SubpixelTranslateView("images/mandrill_256.png", .05f, .05f); )
diff --git a/third_party/skia/samplecode/SampleTextBox.cpp b/third_party/skia/samplecode/SampleTextBox.cpp
index 7aa1598..d929cad 100644
--- a/third_party/skia/samplecode/SampleTextBox.cpp
+++ b/third_party/skia/samplecode/SampleTextBox.cpp
@@ -17,7 +17,6 @@
#include "include/core/SkTextBlob.h"
#include "include/core/SkTime.h"
#include "include/core/SkTypeface.h"
-#include "include/effects/SkBlurMaskFilter.h"
#include "include/effects/SkGradientShader.h"
#include "include/utils/SkRandom.h"
#include "modules/skshaper/include/SkShaper.h"
@@ -25,6 +24,8 @@
#include "src/shaders/SkColorShader.h"
#include "src/utils/SkUTF.h"
+typedef std::unique_ptr<SkShaper> (*ShaperFactory)();
+
static const char gText[] =
"When in the Course of human events it becomes necessary for one people "
"to dissolve the political bands which have connected them with another "
@@ -34,11 +35,14 @@
"declare the causes which impel them to the separation.";
class TextBoxView : public Sample {
+ SkString fName;
public:
- TextBoxView() : fShaper(SkShaper::Make()) {}
+ TextBoxView(ShaperFactory fact, const char suffix[]) : fShaper(fact()) {
+ fName.printf("TextBox_%s", suffix);
+ }
protected:
- SkString name() override { return SkString("TextBox"); }
+ SkString name() override { return fName; }
void drawTest(SkCanvas* canvas, SkScalar w, SkScalar h, SkColor fg, SkColor bg) {
SkAutoCanvasRestore acr(canvas, true);
@@ -52,9 +56,11 @@
paint.setColor(fg);
for (int i = 9; i < 24; i += 2) {
+ SkShaper::PurgeCaches();
SkTextBlobBuilderRunHandler builder(gText, { margin, margin });
SkFont srcFont(nullptr, SkIntToScalar(i));
srcFont.setEdging(SkFont::Edging::kSubpixelAntiAlias);
+ srcFont.setSubpixel(true);
const char* utf8 = gText;
size_t utf8Bytes = sizeof(gText) - 1;
@@ -105,9 +111,80 @@
private:
std::unique_ptr<SkShaper> fShaper;
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
-//////////////////////////////////////////////////////////////////////////////
+DEF_SAMPLE( return new TextBoxView([](){ return SkShaper::Make(); }, "default"); );
+#ifdef SK_SHAPER_CORETEXT_AVAILABLE
+DEF_SAMPLE( return new TextBoxView(SkShaper::MakeCoreText, "coretext"); );
+#endif
-DEF_SAMPLE( return new TextBoxView(); )
+class SampleShaper : public Sample {
+public:
+ SampleShaper() {}
+
+protected:
+ SkString name() override { return SkString("shaper"); }
+
+ void drawTest(SkCanvas* canvas, const char str[], SkScalar size,
+ std::unique_ptr<SkShaper> shaper) {
+ if (!shaper) return;
+
+ SkTextBlobBuilderRunHandler builder(str, {0, 0});
+ SkFont srcFont;
+ srcFont.setSize(size);
+ srcFont.setEdging(SkFont::Edging::kSubpixelAntiAlias);
+ srcFont.setSubpixel(true);
+
+ size_t len = strlen(str);
+
+ std::unique_ptr<SkShaper::BiDiRunIterator> bidi(
+ SkShaper::MakeBiDiRunIterator(str, len, 0xfe));
+ if (!bidi) {
+ return;
+ }
+
+ std::unique_ptr<SkShaper::LanguageRunIterator> language(
+ SkShaper::MakeStdLanguageRunIterator(str, len));
+ if (!language) {
+ return;
+ }
+
+ SkFourByteTag undeterminedScript = SkSetFourByteTag('Z','y','y','y');
+ std::unique_ptr<SkShaper::ScriptRunIterator> script(
+ SkShaper::MakeScriptRunIterator(str, len, undeterminedScript));
+ if (!script) {
+ return;
+ }
+
+ std::unique_ptr<SkShaper::FontRunIterator> font(
+ SkShaper::MakeFontMgrRunIterator(str, len, srcFont, SkFontMgr::RefDefault(),
+ "Arial", SkFontStyle::Bold(), &*language));
+ if (!font) {
+ return;
+ }
+
+ shaper->shape(str, len, *font, *bidi, *script, *language, 2000, &builder);
+
+ canvas->drawTextBlob(builder.makeBlob(), 0, 0, SkPaint());
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ canvas->translate(10, 30);
+
+ const char text[] = "world";
+
+ for (SkScalar size = 30; size <= 30; size += 10) {
+ this->drawTest(canvas, text, size, SkShaper::Make());
+ canvas->translate(0, size + 5);
+ #ifdef SK_SHAPER_CORETEXT_AVAILABLE
+ this->drawTest(canvas, text, size, SkShaper::MakeCoreText());
+ #endif
+ canvas->translate(0, size*2);
+ }
+ }
+
+private:
+ using INHERITED = Sample;
+};
+DEF_SAMPLE( return new SampleShaper; );
diff --git a/third_party/skia/samplecode/SampleTextEffects.cpp b/third_party/skia/samplecode/SampleTextEffects.cpp
deleted file mode 100644
index 8e57750..0000000
--- a/third_party/skia/samplecode/SampleTextEffects.cpp
+++ /dev/null
@@ -1,173 +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/SkBlurMaskFilter.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);
- }
-
- virtual 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;
-
- typedef Sk2DPathEffect INHERITED;
-};
-
-// Register this path effect as deserializable before main().
-namespace {
- static struct Initializer {
- Initializer() {
- SK_REGISTER_FLATTENABLE(Dot2DPathEffect);
- }
- } initializer;
-}
-
-
-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() {}
- virtual 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)
-
- typedef SkPathEffect INHERITED;
-};
-
-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:
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new TextEffectsView(); )
diff --git a/third_party/skia/samplecode/SampleTextureDomain.cpp b/third_party/skia/samplecode/SampleTextureDomain.cpp
deleted file mode 100644
index 3bac799..0000000
--- a/third_party/skia/samplecode/SampleTextureDomain.cpp
+++ /dev/null
@@ -1,95 +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/SkSurface.h"
-#include "include/effects/SkBlurMaskFilter.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkBlurMask.h"
-
-static SkBitmap make_bitmap() {
- SkBitmap bm;
- bm.allocN32Pixels(5, 5);
-
- for (int y = 0; y < bm.height(); y++) {
- uint32_t* p = bm.getAddr32(0, y);
- for (int x = 0; x < bm.width(); x++) {
- p[x] = ((x + y) & 1) ? SK_ColorWHITE : SK_ColorBLACK;
- }
- }
- return bm;
-}
-
-class TextureDomainView : public Sample {
- SkBitmap fBM;
-
-public:
- TextureDomainView(){
- fBM = make_bitmap();
- }
-
-protected:
- virtual SkString name() { return SkString("Texture Domain"); }
-
- virtual void onDrawContent(SkCanvas* canvas) {
- SkRect srcRect;
- SkRect dstRect;
- SkPaint paint;
- paint.setFilterQuality(kLow_SkFilterQuality);
-
- // Test that bitmap draws from malloc-backed bitmaps respect
- // the constrained texture domain.
- srcRect.setXYWH(1, 1, 3, 3);
- dstRect.setXYWH(5, 5, 305, 305);
- canvas->drawBitmapRect(fBM, srcRect, dstRect, &paint, SkCanvas::kStrict_SrcRectConstraint);
-
- // Test that bitmap draws across separate devices also respect
- // the constrainted texture domain.
- // Note: GPU-backed bitmaps follow a different rendering path
- // when copying from one GPU device to another.
- SkImageInfo info = SkImageInfo::MakeN32(5, 5, kOpaque_SkAlphaType);
- auto surface(canvas->makeSurface(info));
-
- srcRect.setXYWH(1, 1, 3, 3);
- dstRect.setXYWH(1, 1, 3, 3);
- surface->getCanvas()->drawBitmapRect(fBM, srcRect, dstRect, &paint,
- SkCanvas::kStrict_SrcRectConstraint);
-
- sk_sp<SkImage> image(surface->makeImageSnapshot());
-
- srcRect.setXYWH(1, 1, 3, 3);
- dstRect.setXYWH(405, 5, 305, 305);
- canvas->drawImageRect(image, srcRect, dstRect, &paint);
-
- // Test that bitmap blurring using a subrect
- // renders correctly
- srcRect.setXYWH(1, 1, 3, 3);
- dstRect.setXYWH(5, 405, 305, 305);
- paint.setMaskFilter(SkMaskFilter::MakeBlur(
- kNormal_SkBlurStyle, SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5)), false));
- canvas->drawImageRect(image, srcRect, dstRect, &paint);
-
- // Blur and a rotation + nullptr src rect
- // This should not trigger the texture domain code
- // but it will test a code path in SkGpuDevice::drawBitmap
- // that handles blurs with rects transformed to non-
- // orthogonal rects. It also tests the nullptr src rect handling
- paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
- SkBlurMask::ConvertRadiusToSigma(5)));
-
- dstRect.setXYWH(-150, -150, 300, 300);
- canvas->translate(550, 550);
- canvas->rotate(45);
- canvas->drawBitmapRect(fBM, dstRect, &paint);
- }
-private:
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new TextureDomainView(); )
diff --git a/third_party/skia/samplecode/SampleTextureUpload.cpp b/third_party/skia/samplecode/SampleTextureUpload.cpp
index a33d1d9..933748c 100644
--- a/third_party/skia/samplecode/SampleTextureUpload.cpp
+++ b/third_party/skia/samplecode/SampleTextureUpload.cpp
@@ -9,7 +9,7 @@
#include "include/core/SkPaint.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTypes.h"
-#include "include/gpu/GrContext.h"
+#include "include/gpu/GrDirectContext.h"
#include "samplecode/Sample.h"
#include "tools/timer/TimeUtils.h"
@@ -17,9 +17,9 @@
* This sample exercises heavy texture updates and uploads.
*/
class TextureUploadSample : public Sample {
- static constexpr int kMinTileSize = 128;
- static constexpr int kMaxTileSize = 2048;
- static constexpr float kGridScale = 0.25f;
+ inline static constexpr int kMinTileSize = 128;
+ inline static constexpr int kMaxTileSize = 2048;
+ inline static constexpr float kGridScale = 0.25f;
bool fDrawTexturesToScreen = true;
int fTileSize = 256;
@@ -31,11 +31,11 @@
class RenderTargetTexture : public SkRefCnt {
public:
- RenderTargetTexture(GrContext* context, int size) {
- SkSurfaceProps surfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
+ RenderTargetTexture(GrDirectContext* direct, int size) {
+ SkSurfaceProps surfaceProps(0, kRGB_H_SkPixelGeometry);
SkImageInfo imageInfo = SkImageInfo::Make(size, size, kRGBA_8888_SkColorType,
kPremul_SkAlphaType);
- fSurface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, imageInfo, 0,
+ fSurface = SkSurface::MakeRenderTarget(direct, SkBudgeted::kNo, imageInfo, 0,
&surfaceProps);
}
@@ -55,7 +55,7 @@
};
SkTArray<sk_sp<RenderTargetTexture>> fTextures;
- GrContext* fCachedContext = nullptr;
+ GrDirectContext* fCachedContext = nullptr;
SkScalar fActiveTileIndex = 0;
SkString name() override {
@@ -67,12 +67,12 @@
fDrawTexturesToScreen = !fDrawTexturesToScreen;
return true;
} else if ('>' == uni) {
- fTileSize = SkTMin(kMaxTileSize, 2*fTileSize);
+ fTileSize = std::min(kMaxTileSize, 2*fTileSize);
fTileRows = kMaxTileSize/fTileSize;
fTileCols = kMaxTileSize/fTileSize;
fCachedContext = nullptr;
} else if ('<' == uni) {
- fTileSize = SkTMax(kMinTileSize, fTileSize/2);
+ fTileSize = std::max(kMinTileSize, fTileSize/2);
fTileRows = kMaxTileSize/fTileSize;
fTileCols = kMaxTileSize/fTileSize;
fCachedContext = nullptr;
@@ -92,11 +92,11 @@
this->setSize(1024, 1024);
}
- void initializeTextures(GrContext* context) {
+ void initializeTextures(GrDirectContext* direct) {
fTextures.reset();
int textureCount = fTileRows * fTileCols;
for (int i = 0; i < textureCount; i++) {
- fTextures.emplace_back(new RenderTargetTexture(context, fTileSize));
+ fTextures.emplace_back(new RenderTargetTexture(direct, fTileSize));
}
// Construct two simple rasters of differing colors to serve
@@ -107,14 +107,12 @@
void onDrawContent(SkCanvas* canvas) override {
#if SK_SUPPORT_GPU
- SkPaint paint;
-
- GrContext* context = canvas->getGrContext();
- if (context) {
+ auto direct = GrAsDirectContext(canvas->recordingContext());
+ if (direct) {
// One-time context-specific setup.
- if (context != fCachedContext) {
- fCachedContext = context;
- this->initializeTextures(context);
+ if (direct != fCachedContext) {
+ fCachedContext = direct;
+ this->initializeTextures(direct);
}
// Upload new texture data for all textures, simulating a full page of tiles
@@ -133,7 +131,7 @@
for (int x = 0; x < fTileCols; x++) {
int currentIndex = y * fTileCols + x;
canvas->drawImage(fTextures[currentIndex]->getImage(),
- x * fTileSize, y * fTileSize, &paint);
+ x * fTileSize, y * fTileSize);
}
}
}
@@ -150,8 +148,6 @@
}
};
-const int TextureUploadSample::kMinTileSize;
-const int TextureUploadSample::kMaxTileSize;
DEF_SAMPLE( return new TextureUploadSample(); )
diff --git a/third_party/skia/samplecode/SampleThinAA.cpp b/third_party/skia/samplecode/SampleThinAA.cpp
index 92aa202..5989deb 100644
--- a/third_party/skia/samplecode/SampleThinAA.cpp
+++ b/third_party/skia/samplecode/SampleThinAA.cpp
@@ -18,10 +18,8 @@
class ShapeRenderer : public SkRefCntBase {
public:
- static constexpr SkScalar kTileWidth = 20.f;
- static constexpr SkScalar kTileHeight = 20.f;
-
- virtual ~ShapeRenderer() {}
+ inline static constexpr SkScalar kTileWidth = 20.f;
+ inline static constexpr SkScalar kTileHeight = 20.f;
// Draw the shape, limited to kTileWidth x kTileHeight. It must apply the local subpixel (tx,
// ty) translation and rotation by angle. Prior to these transform adjustments, the SkCanvas
@@ -66,7 +64,7 @@
private:
RectRenderer() {}
- typedef ShapeRenderer INHERITED;
+ using INHERITED = ShapeRenderer;
};
class PathRenderer : public ShapeRenderer {
@@ -133,7 +131,7 @@
// Adding round caps forces Ganesh to use the path renderer for lines instead of converting
// them to rectangles (which are already explicitly tested). However, when not curved, the
- // GrShape will still find a way to turn it into a rrect draw so it doesn't hit the
+ // GrStyledShape will still find a way to turn it into a rrect draw so it doesn't hit the
// path renderer in that condition.
paint->setStrokeCap(SkPaint::kRound_Cap);
paint->setStrokeJoin(SkPaint::kMiter_Join);
@@ -151,7 +149,7 @@
: fDepth(depth)
, fHairline(hairline) {}
- typedef ShapeRenderer INHERITED;
+ using INHERITED = ShapeRenderer;
};
class OffscreenShapeRenderer : public ShapeRenderer {
@@ -210,7 +208,6 @@
// Use medium quality filter to get mipmaps when drawing smaller, or use nearest filtering
// when upscaling
SkPaint blit;
- blit.setFilterQuality(scale > 1.f ? kNone_SkFilterQuality : kMedium_SkFilterQuality);
if (debugMode) {
// Makes anything that's > 1/255 alpha fully opaque and sets color to medium green.
static constexpr float kFilter[] = {
@@ -223,8 +220,15 @@
blit.setColorFilter(SkColorFilters::Matrix(kFilter));
}
+ auto sampling = scale > 1 ? SkSamplingOptions(SkFilterMode::kNearest)
+ : SkSamplingOptions(SkFilterMode::kLinear,
+ SkMipmapMode::kLinear);
+
canvas->scale(scale, scale);
- canvas->drawImageRect(fLastRendered, SkRect::MakeWH(kTileWidth, kTileHeight), &blit);
+ canvas->drawImageRect(fLastRendered.get(),
+ SkRect::MakeWH(kTileWidth, kTileHeight),
+ SkRect::MakeWH(kTileWidth, kTileHeight),
+ sampling, &blit, SkCanvas::kFast_SrcRectConstraint);
}
private:
@@ -239,7 +243,7 @@
, fRenderer(std::move(renderer))
, fSupersampleFactor(supersample) { }
- typedef ShapeRenderer INHERITED;
+ using INHERITED = ShapeRenderer;
};
class ThinAASample : public Sample {
@@ -403,8 +407,8 @@
case 'u': fAngle = 0.f; return true;
case 'y': fAngle = 90.f; return true;
case ' ': fAngle = SkScalarMod(fAngle + 15.f, 360.f); return true;
- case '-': fStrokeWidth = SkMaxScalar(0.1f, fStrokeWidth - 0.05f); return true;
- case '=': fStrokeWidth = SkMinScalar(1.f, fStrokeWidth + 0.05f); return true;
+ case '-': fStrokeWidth = std::max(0.1f, fStrokeWidth - 0.05f); return true;
+ case '=': fStrokeWidth = std::min(1.f, fStrokeWidth + 0.05f); return true;
}
return false;
}
@@ -480,8 +484,7 @@
SkFont font(nullptr, 12);
if (gridX == 0) {
- SkString name = shape->name();
- SkScalar centering = name.size() * 4.f; // ad-hoc
+ SkScalar centering = shape->name().size() * 4.f; // ad-hoc
canvas->save();
canvas->translate(-10.f, 4 * ShapeRenderer::kTileHeight + centering);
@@ -537,11 +540,11 @@
canvas->translate(0.f, 8.f * ShapeRenderer::kTileHeight + 20.f);
}
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
DEF_SAMPLE( return new ThinAASample; )
-}
+} // namespace skiagm
diff --git a/third_party/skia/samplecode/SampleTiming.cpp b/third_party/skia/samplecode/SampleTiming.cpp
new file mode 100644
index 0000000..d8e3216
--- /dev/null
+++ b/third_party/skia/samplecode/SampleTiming.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 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/SkFont.h"
+#include "include/core/SkSurface.h"
+#include "samplecode/Sample.h"
+#include <chrono>
+
+struct TimingSample : public Sample {
+ inline static constexpr int W = 24,
+ H = 16;
+ sk_sp<SkImage> fImg;
+
+ SkString name() override { return SkString("Timing"); }
+
+ void onOnceBeforeDraw() override {
+ sk_sp<SkSurface> surf = SkSurface::MakeRasterN32Premul(W,H);
+ surf->getCanvas()->drawString("abc", 2,H-4, SkFont{}, SkPaint{});
+ fImg = surf->makeImageSnapshot();
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ canvas->scale(8,8);
+
+ // Draw normally.
+ canvas->drawImage(fImg, 0,0);
+
+ canvas->translate(0,H);
+
+ // Draw one pixel at a time with drawImageRect(),
+ // timing how long each drawImageRect() call takes.
+ double cost[H][W];
+ double min = +INFINITY,
+ max = -INFINITY;
+ for (int y = 0; y < H; y++)
+ for (int x = 0; x < W; x++) {
+ auto start = std::chrono::steady_clock::now();
+ canvas->drawImageRect(fImg.get(),
+ SkRect::MakeXYWH(x,y,1,1), SkRect::MakeXYWH(x,y,1,1),
+ SkSamplingOptions(), /*paint=*/nullptr,
+ SkCanvas::kStrict_SrcRectConstraint);
+ auto elapsed = std::chrono::steady_clock::now() - start;
+
+ cost[y][x] = elapsed.count();
+ min = std::min(min, cost[y][x]);
+ max = std::max(max, cost[y][x]);
+ }
+
+ canvas->translate(0,H);
+
+ // Draw using those per-pixel timings,
+ // with the slowest pixel scaled to alpha=1, the fastest to alpha=0.
+ for (int y = 0; y < H; y++)
+ for (int x = 0; x < W; x++) {
+ SkPaint p;
+ p.setAlphaf( (cost[y][x] - min) / (max - min) );
+ canvas->drawRect(SkRect::MakeXYWH(x,y,1,1), p);
+ }
+
+ canvas->translate(0,H);
+
+ // Draw each pixel into offscreen, timing each draw.
+ SkImageInfo info = canvas->imageInfo().makeWH(1024,1024);
+ if (sk_sp<SkSurface> offscreen = canvas->makeSurface(info)) {
+ min = +INFINITY;
+ max = -INFINITY;
+ for (int y = 0; y < H; y++)
+ for (int x = 0; x < W; x++) {
+ auto start = std::chrono::steady_clock::now();
+ offscreen->getCanvas()->drawImageRect(fImg,
+ SkRect::MakeXYWH(x,y,1,1),
+ SkRect::MakeXYWH(0,0,1024,1024),
+ SkSamplingOptions(),
+ /*paint=*/nullptr,
+ SkCanvas::kStrict_SrcRectConstraint);
+ auto elapsed = std::chrono::steady_clock::now() - start;
+
+ cost[y][x] = elapsed.count();
+ min = std::min(min, cost[y][x]);
+ max = std::max(max, cost[y][x]);
+ }
+ for (int y = 0; y < H; y++)
+ for (int x = 0; x < W; x++) {
+ SkPaint p;
+ p.setAlphaf( (cost[y][x] - min) / (max - min) );
+ canvas->drawRect(SkRect::MakeXYWH(x,y,1,1), p);
+ }
+ }
+ }
+};
+DEF_SAMPLE( return new TimingSample; )
diff --git a/third_party/skia/samplecode/SampleUnpremul.cpp b/third_party/skia/samplecode/SampleUnpremul.cpp
deleted file mode 100644
index 9c606bd..0000000
--- a/third_party/skia/samplecode/SampleUnpremul.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2013 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/SkColorPriv.h"
-#include "include/core/SkStream.h"
-#include "include/core/SkString.h"
-#include "include/core/SkTypes.h"
-#include "samplecode/DecodeFile.h"
-#include "samplecode/Sample.h"
-#include "src/core/SkBlurMask.h"
-#include "src/core/SkOSFile.h"
-#include "src/utils/SkOSPath.h"
-#include "src/utils/SkUTF.h"
-#include "tools/Resources.h"
-#include "tools/ToolUtils.h"
-
-/**
- * Interprets c as an unpremultiplied color, and returns the
- * premultiplied equivalent.
- */
-static SkPMColor premultiply_unpmcolor(SkPMColor c) {
- U8CPU a = SkGetPackedA32(c);
- U8CPU r = SkGetPackedR32(c);
- U8CPU g = SkGetPackedG32(c);
- U8CPU b = SkGetPackedB32(c);
- return SkPreMultiplyARGB(a, r, g, b);
-}
-
-class UnpremulView : public Sample {
-public:
- UnpremulView(SkString res)
- : fResPath(res)
- , fPremul(true)
- , fDecodeSucceeded(false) {
- this->nextImage();
- }
-
-protected:
- SkString name() override { return SkString("unpremul"); }
-
- bool onChar(SkUnichar uni) override {
- char utf8[SkUTF::kMaxBytesInUTF8Sequence];
- size_t size = SkUTF::ToUTF8(uni, utf8);
- // Only consider events for single char keys
- if (1 == size) {
- switch (utf8[0]) {
- case fNextImageChar:
- this->nextImage();
- return true;
- case fTogglePremulChar:
- this->togglePremul();
- return true;
- default:
- break;
- }
- }
- return false;
- }
-
- void onDrawBackground(SkCanvas* canvas) override {
- ToolUtils::draw_checkerboard(canvas, 0xFFCCCCCC, 0xFFFFFFFF, 12);
- }
-
- void onDrawContent(SkCanvas* canvas) override {
- SkPaint paint;
- paint.setAntiAlias(true);
-
- SkFont font;
- font.setSize(24);
- SkScalar height = font.getMetrics(nullptr);
- if (!fDecodeSucceeded) {
- SkString failure;
- if (fResPath.size() == 0) {
- failure.printf("resource path is required!");
- } else {
- failure.printf("Failed to decode %s", fCurrFile.c_str());
- }
- canvas->drawString(failure, 0, height, font, paint);
- return;
- }
-
- // Name, size of the file, and whether or not it is premultiplied.
- SkString header(SkOSPath::Basename(fCurrFile.c_str()));
- header.appendf(" [%dx%d] %s", fBitmap.width(), fBitmap.height(),
- (fPremul ? "premultiplied" : "unpremultiplied"));
- canvas->drawString(header, 0, height, font, paint);
- canvas->translate(0, height);
-
- // Help messages
- header.printf("Press '%c' to move to the next image.'", fNextImageChar);
- canvas->drawString(header, 0, height, font, paint);
- canvas->translate(0, height);
-
- header.printf("Press '%c' to toggle premultiplied decode.", fTogglePremulChar);
- canvas->drawString(header, 0, height, font, paint);
-
- // Now draw the image itself.
- canvas->translate(height * 2, height * 2);
- if (!fPremul) {
- // A premultiplied bitmap cannot currently be drawn.
- // Copy it to a bitmap which can be drawn, converting
- // to premultiplied:
- SkBitmap bm;
- bm.allocN32Pixels(fBitmap.width(), fBitmap.height());
- for (int i = 0; i < fBitmap.width(); ++i) {
- for (int j = 0; j < fBitmap.height(); ++j) {
- *bm.getAddr32(i, j) = premultiply_unpmcolor(*fBitmap.getAddr32(i, j));
- }
- }
- canvas->drawBitmap(bm, 0, 0);
- } else {
- canvas->drawBitmap(fBitmap, 0, 0);
- }
- }
-
-private:
- const SkString fResPath;
- SkString fCurrFile;
- bool fPremul;
- bool fDecodeSucceeded;
- SkBitmap fBitmap;
- SkOSFile::Iter fFileIter;
-
- static const char fNextImageChar = 'j';
- static const char fTogglePremulChar = 'h';
-
- void nextImage() {
- if (fResPath.size() == 0) {
- return;
- }
- SkString basename;
- if (!fFileIter.next(&basename)) {
- fFileIter.reset(fResPath.c_str());
- if (!fFileIter.next(&basename)) {
- // Perhaps this should draw some error message?
- return;
- }
- }
- fCurrFile = SkOSPath::Join(fResPath.c_str(), basename.c_str());
- this->decodeCurrFile();
- }
-
- void decodeCurrFile() {
- if (fCurrFile.size() == 0) {
- fDecodeSucceeded = false;
- return;
- }
- fDecodeSucceeded = decode_file(fCurrFile.c_str(), &fBitmap, kN32_SkColorType, !fPremul);
- }
-
- void togglePremul() {
- fPremul = !fPremul;
- this->decodeCurrFile();
- }
-
- typedef Sample INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-DEF_SAMPLE( return new UnpremulView(GetResourcePath("images")); )
diff --git a/third_party/skia/samplecode/SampleVariableWidthStroker.cpp b/third_party/skia/samplecode/SampleVariableWidthStroker.cpp
new file mode 100644
index 0000000..65efa11
--- /dev/null
+++ b/third_party/skia/samplecode/SampleVariableWidthStroker.cpp
@@ -0,0 +1,1391 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "imgui.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkPath.h"
+#include "include/core/SkPathMeasure.h"
+#include "include/utils/SkParsePath.h"
+#include "samplecode/Sample.h"
+
+#include "src/core/SkGeometry.h"
+
+#include <stack>
+
+namespace {
+
+//////////////////////////////////////////////////////////////////////////////
+
+constexpr inline SkPoint rotate90(const SkPoint& p) { return {p.fY, -p.fX}; }
+inline SkPoint rotate180(const SkPoint& p) { return p * -1; }
+inline bool isClockwise(const SkPoint& a, const SkPoint& b) { return a.cross(b) > 0; }
+
+static SkPoint checkSetLength(SkPoint p, float len, const char* file, int line) {
+ if (!p.setLength(len)) {
+ SkDebugf("%s:%d: Failed to set point length\n", file, line);
+ }
+ return p;
+}
+
+/** Version of setLength that prints debug msg on failure to help catch edge cases */
+#define setLength(p, len) checkSetLength(p, len, __FILE__, __LINE__)
+
+constexpr uint64_t choose(uint64_t n, uint64_t k) {
+ SkASSERT(n >= k);
+ uint64_t result = 1;
+ for (uint64_t i = 1; i <= k; i++) {
+ result *= (n + 1 - i);
+ result /= i;
+ }
+ return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A scalar (float-valued weights) Bezier curve of arbitrary degree.
+ */
+class ScalarBezCurve {
+public:
+ inline static constexpr int kDegreeInvalid = -1;
+
+ /** Creates an empty curve with invalid degree. */
+ ScalarBezCurve() : fDegree(kDegreeInvalid) {}
+
+ /** Creates a curve of the specified degree with weights initialized to 0. */
+ explicit ScalarBezCurve(int degree) : fDegree(degree) {
+ SkASSERT(degree >= 0);
+ fWeights.resize(degree + 1, {0});
+ }
+
+ /** Creates a curve of specified degree with the given weights. */
+ ScalarBezCurve(int degree, const std::vector<float>& weights) : ScalarBezCurve(degree) {
+ SkASSERT(degree >= 0);
+ SkASSERT(weights.size() == (size_t)degree + 1);
+ fWeights.insert(fWeights.begin(), weights.begin(), weights.end());
+ }
+
+ /** Returns the extreme-valued weight */
+ float extremumWeight() const {
+ float f = 0;
+ int sign = 1;
+ for (float w : fWeights) {
+ if (std::abs(w) > f) {
+ f = std::abs(w);
+ sign = w >= 0 ? 1 : -1;
+ }
+ }
+ return sign * f;
+ }
+
+ /** Evaluates the curve at t */
+ float eval(float t) const { return Eval(*this, t); }
+
+ /** Evaluates the curve at t */
+ static float Eval(const ScalarBezCurve& curve, float t) {
+ // Set up starting point of recursion (k=0)
+ ScalarBezCurve result = curve;
+
+ for (int k = 1; k <= curve.fDegree; k++) {
+ // k is level of recursion, k-1 has previous level's values.
+ for (int i = curve.fDegree; i >= k; i--) {
+ result.fWeights[i] = result.fWeights[i - 1] * (1 - t) + result.fWeights[i] * t;
+ }
+ }
+
+ return result.fWeights[curve.fDegree];
+ }
+
+ /** Splits this curve at t into two halves (of the same degree) */
+ void split(float t, ScalarBezCurve* left, ScalarBezCurve* right) const {
+ Split(*this, t, left, right);
+ }
+
+ /** Splits this curve into the subinterval [tmin,tmax]. */
+ void split(float tmin, float tmax, ScalarBezCurve* result) const {
+ // TODO: I believe there's a more efficient algorithm for this
+ const float tRel = tmin / tmax;
+ ScalarBezCurve ll, rl, rr;
+ this->split(tmax, &rl, &rr);
+ rl.split(tRel, &ll, result);
+ }
+
+ /** Splits the curve at t into two halves (of the same degree) */
+ static void Split(const ScalarBezCurve& curve,
+ float t,
+ ScalarBezCurve* left,
+ ScalarBezCurve* right) {
+ // Set up starting point of recursion (k=0)
+ const int degree = curve.fDegree;
+ ScalarBezCurve result = curve;
+ *left = ScalarBezCurve(degree);
+ *right = ScalarBezCurve(degree);
+ left->fWeights[0] = curve.fWeights[0];
+ right->fWeights[degree] = curve.fWeights[degree];
+
+ for (int k = 1; k <= degree; k++) {
+ // k is level of recursion, k-1 has previous level's values.
+ for (int i = degree; i >= k; i--) {
+ result.fWeights[i] = result.fWeights[i - 1] * (1 - t) + result.fWeights[i] * t;
+ }
+
+ left->fWeights[k] = result.fWeights[k];
+ right->fWeights[degree - k] = result.fWeights[degree];
+ }
+ }
+
+ /**
+ * Increases the degree of the curve to the given degree. Has no effect if the
+ * degree is already equal to the given degree.
+ *
+ * This process is always exact (NB the reverse, degree reduction, is not exact).
+ */
+ void elevateDegree(int newDegree) {
+ if (newDegree == fDegree) {
+ return;
+ }
+
+ fWeights = ElevateDegree(*this, newDegree).fWeights;
+ fDegree = newDegree;
+ }
+
+ /**
+ * Increases the degree of the curve to the given degree. Has no effect if the
+ * degree is already equal to the given degree.
+ *
+ * This process is always exact (NB the reverse, degree reduction, is not exact).
+ */
+ static ScalarBezCurve ElevateDegree(const ScalarBezCurve& curve, int newDegree) {
+ SkASSERT(newDegree >= curve.degree());
+ if (newDegree == curve.degree()) {
+ return curve;
+ }
+
+ // From Farouki, Rajan, "Algorithms for polynomials in Bernstein form" 1988.
+ ScalarBezCurve elevated(newDegree);
+ const int r = newDegree - curve.fDegree;
+ const int n = curve.fDegree;
+
+ for (int i = 0; i <= n + r; i++) {
+ elevated.fWeights[i] = 0;
+ for (int j = std::max(0, i - r); j <= std::min(n, i); j++) {
+ const float f =
+ (choose(n, j) * choose(r, i - j)) / static_cast<float>(choose(n + r, i));
+ elevated.fWeights[i] += curve.fWeights[j] * f;
+ }
+ }
+
+ return elevated;
+ }
+
+ /**
+ * Returns the zero-set of this curve, which is a list of t values where the curve crosses 0.
+ */
+ std::vector<float> zeroSet() const { return ZeroSet(*this); }
+
+ /**
+ * Returns the zero-set of the curve, which is a list of t values where the curve crosses 0.
+ */
+ static std::vector<float> ZeroSet(const ScalarBezCurve& curve) {
+ constexpr float kTol = 0.001f;
+ std::vector<float> result;
+ ZeroSetRec(curve, 0, 1, kTol, &result);
+ return result;
+ }
+
+ /** Multiplies the curve's weights by a constant value */
+ static ScalarBezCurve Mul(const ScalarBezCurve& curve, float f) {
+ ScalarBezCurve result = curve;
+ for (int k = 0; k <= curve.fDegree; k++) {
+ result.fWeights[k] *= f;
+ }
+ return result;
+ }
+
+ /**
+ * Multiplies the two curves and returns the result.
+ *
+ * Degree of resulting curve is the sum of the degrees of the input curves.
+ */
+ static ScalarBezCurve Mul(const ScalarBezCurve& a, const ScalarBezCurve& b) {
+ // From G. Elber, "Free form surface analysis using a hybrid of symbolic and numeric
+ // computation". PhD thesis, 1992. p.11.
+ const int n = a.degree(), m = b.degree();
+ const int newDegree = n + m;
+ ScalarBezCurve result(newDegree);
+
+ for (int k = 0; k <= newDegree; k++) {
+ result.fWeights[k] = 0;
+ for (int i = std::max(0, k - n); i <= std::min(k, m); i++) {
+ const float f =
+ (choose(m, i) * choose(n, k - i)) / static_cast<float>(choose(m + n, k));
+ result.fWeights[k] += a.fWeights[i] * b.fWeights[k - i] * f;
+ }
+ }
+
+ return result;
+ }
+
+ /** Returns a^2 + b^2. This is a specialized method because the loops are easily fused. */
+ static ScalarBezCurve AddSquares(const ScalarBezCurve& a, const ScalarBezCurve& b) {
+ const int n = a.degree(), m = b.degree();
+ const int newDegree = n + m;
+ ScalarBezCurve result(newDegree);
+
+ for (int k = 0; k <= newDegree; k++) {
+ float aSq = 0, bSq = 0;
+ for (int i = std::max(0, k - n); i <= std::min(k, m); i++) {
+ const float f =
+ (choose(m, i) * choose(n, k - i)) / static_cast<float>(choose(m + n, k));
+ aSq += a.fWeights[i] * a.fWeights[k - i] * f;
+ bSq += b.fWeights[i] * b.fWeights[k - i] * f;
+ }
+ result.fWeights[k] = aSq + bSq;
+ }
+
+ return result;
+ }
+
+ /** Returns a - b. */
+ static ScalarBezCurve Sub(const ScalarBezCurve& a, const ScalarBezCurve& b) {
+ ScalarBezCurve result = a;
+ result.sub(b);
+ return result;
+ }
+
+ /** Subtracts the other curve from this curve */
+ void sub(const ScalarBezCurve& other) {
+ SkASSERT(other.fDegree == fDegree);
+ for (int k = 0; k <= fDegree; k++) {
+ fWeights[k] -= other.fWeights[k];
+ }
+ }
+
+ /** Subtracts a constant from this curve */
+ void sub(float f) {
+ for (int k = 0; k <= fDegree; k++) {
+ fWeights[k] -= f;
+ }
+ }
+
+ /** Returns the curve degree */
+ int degree() const { return fDegree; }
+
+ /** Returns the curve weights */
+ const std::vector<float>& weights() const { return fWeights; }
+
+ float operator[](size_t i) const { return fWeights[i]; }
+ float& operator[](size_t i) { return fWeights[i]; }
+
+private:
+ /** Recursive helper for ZeroSet */
+ static void ZeroSetRec(const ScalarBezCurve& curve,
+ float tmin,
+ float tmax,
+ float tol,
+ std::vector<float>* result) {
+ float lenP = 0;
+ bool allPos = curve.fWeights[0] >= 0, allNeg = curve.fWeights[0] < 0;
+ for (int i = 1; i <= curve.fDegree; i++) {
+ lenP += std::abs(curve.fWeights[i] - curve.fWeights[i - 1]);
+ allPos &= curve.fWeights[i] >= 0;
+ allNeg &= curve.fWeights[i] < 0;
+ }
+ if (lenP <= tol) {
+ result->push_back((tmin + tmax) * 0.5);
+ return;
+ } else if (allPos || allNeg) {
+ // No zero crossings possible if the coefficients don't change sign (convex hull
+ // property)
+ return;
+ } else if (SkScalarNearlyZero(tmax - tmin)) {
+ return;
+ } else {
+ ScalarBezCurve left(curve.fDegree), right(curve.fDegree);
+ Split(curve, 0.5f, &left, &right);
+
+ const float tmid = (tmin + tmax) * 0.5;
+ ZeroSetRec(left, tmin, tmid, tol, result);
+ ZeroSetRec(right, tmid, tmax, tol, result);
+ }
+ }
+
+ int fDegree;
+ std::vector<float> fWeights;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+/** Helper class that measures per-verb path lengths. */
+class PathVerbMeasure {
+public:
+ explicit PathVerbMeasure(const SkPath& path) : fPath(path), fIter(path, false) { nextVerb(); }
+
+ SkScalar totalLength() const;
+
+ SkScalar currentVerbLength() { return fMeas.getLength(); }
+
+ void nextVerb();
+
+private:
+ const SkPath& fPath;
+ SkPoint fFirstPointInContour;
+ SkPoint fPreviousPoint;
+ SkPath fCurrVerb;
+ SkPath::Iter fIter;
+ SkPathMeasure fMeas;
+};
+
+SkScalar PathVerbMeasure::totalLength() const {
+ SkPathMeasure meas(fPath, false);
+ return meas.getLength();
+}
+
+void PathVerbMeasure::nextVerb() {
+ SkPoint pts[4];
+ SkPath::Verb verb = fIter.next(pts);
+
+ while (verb == SkPath::kMove_Verb || verb == SkPath::kClose_Verb) {
+ if (verb == SkPath::kMove_Verb) {
+ fFirstPointInContour = pts[0];
+ fPreviousPoint = fFirstPointInContour;
+ }
+ verb = fIter.next(pts);
+ }
+
+ fCurrVerb.rewind();
+ fCurrVerb.moveTo(fPreviousPoint);
+ switch (verb) {
+ case SkPath::kLine_Verb:
+ fCurrVerb.lineTo(pts[1]);
+ break;
+ case SkPath::kQuad_Verb:
+ fCurrVerb.quadTo(pts[1], pts[2]);
+ break;
+ case SkPath::kCubic_Verb:
+ fCurrVerb.cubicTo(pts[1], pts[2], pts[3]);
+ break;
+ case SkPath::kConic_Verb:
+ fCurrVerb.conicTo(pts[1], pts[2], fIter.conicWeight());
+ break;
+ case SkPath::kDone_Verb:
+ break;
+ case SkPath::kClose_Verb:
+ case SkPath::kMove_Verb:
+ SkASSERT(false);
+ break;
+ }
+
+ fCurrVerb.getLastPt(&fPreviousPoint);
+ fMeas.setPath(&fCurrVerb, false);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Several debug-only visualization helpers
+namespace viz {
+std::unique_ptr<ScalarBezCurve> outerErr;
+SkPath outerFirstApprox;
+} // namespace viz
+
+/**
+ * Prototype variable-width path stroker.
+ *
+ * Takes as input a path to be stroked, and two distance functions (inside and outside).
+ * Produces a fill path with the stroked path geometry.
+ *
+ * The algorithms in use here are from:
+ *
+ * G. Elber, E. Cohen. "Error bounded variable distance offset operator for free form curves and
+ * surfaces." International Journal of Computational Geometry & Applications 1, no. 01 (1991)
+ *
+ * G. Elber. "Free form surface analysis using a hybrid of symbolic and numeric computation."
+ * PhD diss., Dept. of Computer Science, University of Utah, 1992.
+ */
+class SkVarWidthStroker {
+public:
+ /** Metric to use for interpolation of distance function across path segments. */
+ enum class LengthMetric {
+ /** Each path segment gets an equal interval of t in [0,1] */
+ kNumSegments,
+ /** Each path segment gets t interval equal to its percent of the total path length */
+ kPathLength,
+ };
+
+ /**
+ * Strokes the path with a fixed-width distance function. This produces a traditional stroked
+ * path.
+ */
+ SkPath getFillPath(const SkPath& path, const SkPaint& paint) {
+ return getFillPath(path, paint, identityVarWidth(paint.getStrokeWidth()),
+ identityVarWidth(paint.getStrokeWidth()));
+ }
+
+ /**
+ * Strokes the given path using the two given distance functions for inner and outer offsets.
+ */
+ SkPath getFillPath(const SkPath& path,
+ const SkPaint& paint,
+ const ScalarBezCurve& varWidth,
+ const ScalarBezCurve& varWidthInner,
+ LengthMetric lengthMetric = LengthMetric::kNumSegments);
+
+private:
+ /** Helper struct referring to a single segment of an SkPath */
+ struct PathSegment {
+ SkPath::Verb fVerb;
+ std::array<SkPoint, 4> fPoints;
+ };
+
+ struct OffsetSegments {
+ std::vector<PathSegment> fInner;
+ std::vector<PathSegment> fOuter;
+ };
+
+ /** Initialize stroker state */
+ void initForPath(const SkPath& path, const SkPaint& paint);
+
+ /** Strokes a path segment */
+ OffsetSegments strokeSegment(const PathSegment& segment,
+ const ScalarBezCurve& varWidth,
+ const ScalarBezCurve& varWidthInner,
+ bool needsMove);
+
+ /**
+ * Strokes the given segment using the given distance function.
+ *
+ * Returns a list of quad segments that approximate the offset curve.
+ * TODO: no reason this needs to return a vector of quads, can just append to the path
+ */
+ std::vector<PathSegment> strokeSegment(const PathSegment& seg,
+ const ScalarBezCurve& distanceFunc) const;
+
+ /** Adds an endcap to fOuter */
+ enum class CapLocation { Start, End };
+ void endcap(CapLocation loc);
+
+ /** Adds a join between the two segments */
+ void join(const SkPoint& common,
+ float innerRadius,
+ float outerRadius,
+ const OffsetSegments& prev,
+ const OffsetSegments& curr);
+
+ /** Appends path in reverse to result */
+ static void appendPathReversed(const SkPath& path, SkPath* result);
+
+ /** Returns the segment unit normal and unit tangent if not nullptr */
+ static SkPoint unitNormal(const PathSegment& seg, float t, SkPoint* tangentOut);
+
+ /** Returns the degree of a segment curve */
+ static int segmentDegree(const PathSegment& seg);
+
+ /** Splits a path segment at t */
+ static void splitSegment(const PathSegment& seg, float t, PathSegment* segA, PathSegment* segB);
+
+ /**
+ * Returns a quadratic segment that approximates the given segment using the given distance
+ * function.
+ */
+ static void approximateSegment(const PathSegment& seg,
+ const ScalarBezCurve& distFnc,
+ PathSegment* approxQuad);
+
+ /** Returns a constant (deg 0) distance function for the given stroke width */
+ static ScalarBezCurve identityVarWidth(float strokeWidth) {
+ return ScalarBezCurve(0, {strokeWidth / 2.0f});
+ }
+
+ float fRadius;
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ SkPath fInner, fOuter;
+ ScalarBezCurve fVarWidth, fVarWidthInner;
+ float fCurrT;
+};
+
+void SkVarWidthStroker::initForPath(const SkPath& path, const SkPaint& paint) {
+ fRadius = paint.getStrokeWidth() / 2;
+ fCap = paint.getStrokeCap();
+ fJoin = paint.getStrokeJoin();
+ fInner.rewind();
+ fOuter.rewind();
+ fCurrT = 0;
+}
+
+SkPath SkVarWidthStroker::getFillPath(const SkPath& path,
+ const SkPaint& paint,
+ const ScalarBezCurve& varWidth,
+ const ScalarBezCurve& varWidthInner,
+ LengthMetric lengthMetric) {
+ const auto appendStrokes = [this](const OffsetSegments& strokes, bool needsMove) {
+ if (needsMove) {
+ fOuter.moveTo(strokes.fOuter.front().fPoints[0]);
+ fInner.moveTo(strokes.fInner.front().fPoints[0]);
+ }
+
+ for (const PathSegment& seg : strokes.fOuter) {
+ fOuter.quadTo(seg.fPoints[1], seg.fPoints[2]);
+ }
+
+ for (const PathSegment& seg : strokes.fInner) {
+ fInner.quadTo(seg.fPoints[1], seg.fPoints[2]);
+ }
+ };
+
+ initForPath(path, paint);
+ fVarWidth = varWidth;
+ fVarWidthInner = varWidthInner;
+
+ // TODO: this assumes one contour:
+ PathVerbMeasure meas(path);
+ const float totalPathLength = lengthMetric == LengthMetric::kPathLength
+ ? meas.totalLength()
+ : (path.countVerbs() - 1);
+
+ // Trace the inner and outer paths simultaneously. Inner will therefore be
+ // recorded in reverse from how we trace the outline.
+ SkPath::Iter it(path, false);
+ PathSegment segment, prevSegment;
+ OffsetSegments offsetSegs, prevOffsetSegs;
+ bool firstSegment = true, prevWasFirst = false;
+
+ float lenTraveled = 0;
+ while ((segment.fVerb = it.next(&segment.fPoints[0])) != SkPath::kDone_Verb) {
+ const float verbLength = lengthMetric == LengthMetric::kPathLength
+ ? (meas.currentVerbLength() / totalPathLength)
+ : (1.0f / totalPathLength);
+ const float tmin = lenTraveled;
+ const float tmax = lenTraveled + verbLength;
+
+ // Subset the distance function for the current interval.
+ ScalarBezCurve partVarWidth, partVarWidthInner;
+ fVarWidth.split(tmin, tmax, &partVarWidth);
+ fVarWidthInner.split(tmin, tmax, &partVarWidthInner);
+ partVarWidthInner = ScalarBezCurve::Mul(partVarWidthInner, -1);
+
+ // Stroke the current segment
+ switch (segment.fVerb) {
+ case SkPath::kLine_Verb:
+ case SkPath::kQuad_Verb:
+ case SkPath::kCubic_Verb:
+ offsetSegs = strokeSegment(segment, partVarWidth, partVarWidthInner, firstSegment);
+ break;
+ case SkPath::kMove_Verb:
+ // Don't care about multiple contours currently
+ continue;
+ default:
+ SkDebugf("Unhandled path verb %d\n", segment.fVerb);
+ SkASSERT(false);
+ break;
+ }
+
+ // Join to the previous segment
+ if (!firstSegment) {
+ // Append prev inner and outer strokes
+ appendStrokes(prevOffsetSegs, prevWasFirst);
+
+ // Append the join
+ const float innerRadius = varWidthInner.eval(tmin);
+ const float outerRadius = varWidth.eval(tmin);
+ join(segment.fPoints[0], innerRadius, outerRadius, prevOffsetSegs, offsetSegs);
+ }
+
+ std::swap(segment, prevSegment);
+ std::swap(offsetSegs, prevOffsetSegs);
+ prevWasFirst = firstSegment;
+ firstSegment = false;
+ lenTraveled += verbLength;
+ meas.nextVerb();
+ }
+
+ // Finish appending final offset segments
+ appendStrokes(prevOffsetSegs, prevWasFirst);
+
+ // Open contour => endcap at the end
+ const bool isClosed = path.isLastContourClosed();
+ if (isClosed) {
+ SkDebugf("Unhandled closed contour\n");
+ SkASSERT(false);
+ } else {
+ endcap(CapLocation::End);
+ }
+
+ // Walk inner path in reverse, appending to result
+ appendPathReversed(fInner, &fOuter);
+ endcap(CapLocation::Start);
+
+ return fOuter;
+}
+
+SkVarWidthStroker::OffsetSegments SkVarWidthStroker::strokeSegment(
+ const PathSegment& segment,
+ const ScalarBezCurve& varWidth,
+ const ScalarBezCurve& varWidthInner,
+ bool needsMove) {
+ viz::outerErr.reset(nullptr);
+
+ std::vector<PathSegment> outer = strokeSegment(segment, varWidth);
+ std::vector<PathSegment> inner = strokeSegment(segment, varWidthInner);
+ return {inner, outer};
+}
+
+std::vector<SkVarWidthStroker::PathSegment> SkVarWidthStroker::strokeSegment(
+ const PathSegment& seg, const ScalarBezCurve& distanceFunc) const {
+ // Work item for the recursive splitting stack.
+ struct Item {
+ PathSegment fSeg;
+ ScalarBezCurve fDistFnc, fDistFncSqd;
+ ScalarBezCurve fSegX, fSegY;
+
+ Item(const PathSegment& seg,
+ const ScalarBezCurve& distFnc,
+ const ScalarBezCurve& distFncSqd)
+ : fSeg(seg), fDistFnc(distFnc), fDistFncSqd(distFncSqd) {
+ const int segDegree = segmentDegree(seg);
+ fSegX = ScalarBezCurve(segDegree);
+ fSegY = ScalarBezCurve(segDegree);
+ for (int i = 0; i <= segDegree; i++) {
+ fSegX[i] = seg.fPoints[i].fX;
+ fSegY[i] = seg.fPoints[i].fY;
+ }
+ }
+ };
+
+ // Push the initial segment and distance function
+ std::stack<Item> stack;
+ stack.push(Item(seg, distanceFunc, ScalarBezCurve::Mul(distanceFunc, distanceFunc)));
+
+ std::vector<PathSegment> result;
+ constexpr int kMaxIters = 5000; /** TODO: this is completely arbitrary */
+ int iter = 0;
+ while (!stack.empty()) {
+ if (iter++ >= kMaxIters) break;
+ const Item item = stack.top();
+ stack.pop();
+
+ const ScalarBezCurve& distFnc = item.fDistFnc;
+ ScalarBezCurve distFncSqd = item.fDistFncSqd;
+ const float kTol = std::abs(0.5f * distFnc.extremumWeight());
+
+ // Compute a quad that approximates stroke outline
+ PathSegment quadApprox;
+ approximateSegment(item.fSeg, distFnc, &quadApprox);
+ ScalarBezCurve quadApproxX(2), quadApproxY(2);
+ for (int i = 0; i < 3; i++) {
+ quadApproxX[i] = quadApprox.fPoints[i].fX;
+ quadApproxY[i] = quadApprox.fPoints[i].fY;
+ }
+
+ // Compute control polygon for the delta(t) curve. First must elevate to a common degree.
+ const int deltaDegree = std::max(quadApproxX.degree(), item.fSegX.degree());
+ ScalarBezCurve segX = item.fSegX, segY = item.fSegY;
+ segX.elevateDegree(deltaDegree);
+ segY.elevateDegree(deltaDegree);
+ quadApproxX.elevateDegree(deltaDegree);
+ quadApproxY.elevateDegree(deltaDegree);
+
+ ScalarBezCurve deltaX = ScalarBezCurve::Sub(quadApproxX, segX);
+ ScalarBezCurve deltaY = ScalarBezCurve::Sub(quadApproxY, segY);
+
+ // Compute psi(t) = delta_x(t)^2 + delta_y(t)^2.
+ ScalarBezCurve E = ScalarBezCurve::AddSquares(deltaX, deltaY);
+
+ // Promote E and d(t)^2 to a common degree.
+ const int commonDeg = std::max(distFncSqd.degree(), E.degree());
+ distFncSqd.elevateDegree(commonDeg);
+ E.elevateDegree(commonDeg);
+
+ // Subtract dist squared curve from E, resulting in:
+ // eps(t) = delta_x(t)^2 + delta_y(t)^2 - d(t)^2
+ E.sub(distFncSqd);
+
+ // Purely for debugging/testing, save the first approximation and error function:
+ if (viz::outerErr == nullptr) {
+ using namespace viz;
+ outerErr = std::make_unique<ScalarBezCurve>(E);
+ outerFirstApprox.rewind();
+ outerFirstApprox.moveTo(quadApprox.fPoints[0]);
+ outerFirstApprox.quadTo(quadApprox.fPoints[1], quadApprox.fPoints[2]);
+ }
+
+ // Compute maxErr, which is just the max coefficient of eps (using convex hull property
+ // of bez curves)
+ float maxAbsErr = std::abs(E.extremumWeight());
+
+ if (maxAbsErr > kTol) {
+ PathSegment left, right;
+ splitSegment(item.fSeg, 0.5f, &left, &right);
+
+ ScalarBezCurve distFncL, distFncR;
+ distFnc.split(0.5f, &distFncL, &distFncR);
+
+ ScalarBezCurve distFncSqdL, distFncSqdR;
+ distFncSqd.split(0.5f, &distFncSqdL, &distFncSqdR);
+
+ stack.push(Item(right, distFncR, distFncSqdR));
+ stack.push(Item(left, distFncL, distFncSqdL));
+ } else {
+ // Approximation is good enough.
+ quadApprox.fVerb = SkPath::kQuad_Verb;
+ result.push_back(quadApprox);
+ }
+ }
+ SkASSERT(!result.empty());
+ return result;
+}
+
+void SkVarWidthStroker::endcap(CapLocation loc) {
+ const auto buttCap = [this](CapLocation loc) {
+ if (loc == CapLocation::Start) {
+ // Back at the start of the path: just close the stroked outline
+ fOuter.close();
+ } else {
+ // Inner last pt == first pt when appending in reverse
+ SkPoint innerLastPt;
+ fInner.getLastPt(&innerLastPt);
+ fOuter.lineTo(innerLastPt);
+ }
+ };
+
+ switch (fCap) {
+ case SkPaint::kButt_Cap:
+ buttCap(loc);
+ break;
+ default:
+ SkDebugf("Unhandled endcap %d\n", fCap);
+ buttCap(loc);
+ break;
+ }
+}
+
+void SkVarWidthStroker::join(const SkPoint& common,
+ float innerRadius,
+ float outerRadius,
+ const OffsetSegments& prev,
+ const OffsetSegments& curr) {
+ const auto miterJoin = [this](const SkPoint& common,
+ float leftRadius,
+ float rightRadius,
+ const OffsetSegments& prev,
+ const OffsetSegments& curr) {
+ // With variable-width stroke you can actually have a situation where both sides
+ // need an "inner" or an "outer" join. So we call the two sides "left" and
+ // "right" and they can each independently get an inner or outer join.
+ const auto makeJoin = [this, &common, &prev, &curr](bool left, float radius) {
+ SkPath* path = left ? &fOuter : &fInner;
+ const auto& prevSegs = left ? prev.fOuter : prev.fInner;
+ const auto& currSegs = left ? curr.fOuter : curr.fInner;
+ SkASSERT(!prevSegs.empty());
+ SkASSERT(!currSegs.empty());
+ const SkPoint afterEndpt = currSegs.front().fPoints[0];
+ SkPoint before = unitNormal(prevSegs.back(), 1, nullptr);
+ SkPoint after = unitNormal(currSegs.front(), 0, nullptr);
+
+ // Don't create any join geometry if the normals are nearly identical.
+ const float cosTheta = before.dot(after);
+ if (!SkScalarNearlyZero(1 - cosTheta)) {
+ bool outerJoin;
+ if (left) {
+ outerJoin = isClockwise(before, after);
+ } else {
+ before = rotate180(before);
+ after = rotate180(after);
+ outerJoin = !isClockwise(before, after);
+ }
+
+ if (outerJoin) {
+ // Before and after have the same origin and magnitude, so before+after is the
+ // diagonal of their rhombus. Origin of this vector is the midpoint of the miter
+ // line.
+ SkPoint miterVec = before + after;
+
+ // Note the relationship (draw a right triangle with the miter line as its
+ // hypoteneuse):
+ // sin(theta/2) = strokeWidth / miterLength
+ // so miterLength = strokeWidth / sin(theta/2)
+ // where miterLength is the length of the miter from outer point to inner
+ // corner. miterVec's origin is the midpoint of the miter line, so we use
+ // strokeWidth/2. Sqrt is just an application of half-angle identities.
+ const float sinHalfTheta = sqrtf(0.5 * (1 + cosTheta));
+ const float halfMiterLength = radius / sinHalfTheta;
+ // TODO: miter length limit
+ miterVec = setLength(miterVec, halfMiterLength);
+
+ // Outer join: connect to the miter point, and then to t=0 of next segment.
+ path->lineTo(common + miterVec);
+ path->lineTo(afterEndpt);
+ } else {
+ // Connect to the miter midpoint (common path endpoint of the two segments),
+ // and then to t=0 of the next segment. This adds an interior "loop"
+ // of geometry that handles edge cases where segment lengths are shorter than
+ // the stroke width.
+ path->lineTo(common);
+ path->lineTo(afterEndpt);
+ }
+ }
+ };
+
+ makeJoin(true, leftRadius);
+ makeJoin(false, rightRadius);
+ };
+
+ switch (fJoin) {
+ case SkPaint::kMiter_Join:
+ miterJoin(common, innerRadius, outerRadius, prev, curr);
+ break;
+ default:
+ SkDebugf("Unhandled join %d\n", fJoin);
+ miterJoin(common, innerRadius, outerRadius, prev, curr);
+ break;
+ }
+}
+
+void SkVarWidthStroker::appendPathReversed(const SkPath& path, SkPath* result) {
+ const int numVerbs = path.countVerbs();
+ const int numPoints = path.countPoints();
+ std::vector<uint8_t> verbs;
+ std::vector<SkPoint> points;
+ verbs.resize(numVerbs);
+ points.resize(numPoints);
+ path.getVerbs(verbs.data(), numVerbs);
+ path.getPoints(points.data(), numPoints);
+
+ for (int i = numVerbs - 1, j = numPoints; i >= 0; i--) {
+ auto verb = static_cast<SkPath::Verb>(verbs[i]);
+ switch (verb) {
+ case SkPath::kLine_Verb: {
+ j -= 1;
+ SkASSERT(j >= 1);
+ result->lineTo(points[j - 1]);
+ break;
+ }
+ case SkPath::kQuad_Verb: {
+ j -= 1;
+ SkASSERT(j >= 2);
+ result->quadTo(points[j - 1], points[j - 2]);
+ j -= 1;
+ break;
+ }
+ case SkPath::kMove_Verb:
+ // Ignore
+ break;
+ default:
+ SkASSERT(false);
+ break;
+ }
+ }
+}
+
+int SkVarWidthStroker::segmentDegree(const PathSegment& seg) {
+ static constexpr int lut[] = {
+ -1, // move,
+ 1, // line
+ 2, // quad
+ -1, // conic
+ 3, // cubic
+ -1 // done
+ };
+ const int deg = lut[static_cast<uint8_t>(seg.fVerb)];
+ SkASSERT(deg > 0);
+ return deg;
+}
+
+void SkVarWidthStroker::splitSegment(const PathSegment& seg,
+ float t,
+ PathSegment* segA,
+ PathSegment* segB) {
+ // TODO: although general, this is a pretty slow way to do this
+ const int degree = segmentDegree(seg);
+ ScalarBezCurve x(degree), y(degree);
+ for (int i = 0; i <= degree; i++) {
+ x[i] = seg.fPoints[i].fX;
+ y[i] = seg.fPoints[i].fY;
+ }
+
+ ScalarBezCurve leftX(degree), rightX(degree), leftY(degree), rightY(degree);
+ x.split(t, &leftX, &rightX);
+ y.split(t, &leftY, &rightY);
+
+ segA->fVerb = segB->fVerb = seg.fVerb;
+ for (int i = 0; i <= degree; i++) {
+ segA->fPoints[i] = {leftX[i], leftY[i]};
+ segB->fPoints[i] = {rightX[i], rightY[i]};
+ }
+}
+
+void SkVarWidthStroker::approximateSegment(const PathSegment& seg,
+ const ScalarBezCurve& distFnc,
+ PathSegment* approxQuad) {
+ // This is a simple control polygon transformation.
+ // From F. Yzerman. "Precise offsetting of quadratic Bezier curves". 2019.
+ // TODO: detect and handle more degenerate cases (e.g. linear)
+ // TODO: Tiller-Hanson works better in many cases but does not generalize well
+ SkPoint tangentStart, tangentEnd;
+ SkPoint offsetStart = unitNormal(seg, 0, &tangentStart);
+ SkPoint offsetEnd = unitNormal(seg, 1, &tangentEnd);
+ SkPoint offsetMid = offsetStart + offsetEnd;
+
+ const float radiusStart = distFnc.eval(0);
+ const float radiusMid = distFnc.eval(0.5f);
+ const float radiusEnd = distFnc.eval(1);
+
+ offsetStart = radiusStart == 0 ? SkPoint::Make(0, 0) : setLength(offsetStart, radiusStart);
+ offsetMid = radiusMid == 0 ? SkPoint::Make(0, 0) : setLength(offsetMid, radiusMid);
+ offsetEnd = radiusEnd == 0 ? SkPoint::Make(0, 0) : setLength(offsetEnd, radiusEnd);
+
+ SkPoint start, mid, end;
+ switch (segmentDegree(seg)) {
+ case 1:
+ start = seg.fPoints[0];
+ end = seg.fPoints[1];
+ mid = (start + end) * 0.5f;
+ break;
+ case 2:
+ start = seg.fPoints[0];
+ mid = seg.fPoints[1];
+ end = seg.fPoints[2];
+ break;
+ case 3:
+ start = seg.fPoints[0];
+ mid = (seg.fPoints[1] + seg.fPoints[2]) * 0.5f;
+ end = seg.fPoints[3];
+ break;
+ default:
+ SkDebugf("Unhandled degree for segment approximation");
+ SkASSERT(false);
+ break;
+ }
+
+ approxQuad->fPoints[0] = start + offsetStart;
+ approxQuad->fPoints[1] = mid + offsetMid;
+ approxQuad->fPoints[2] = end + offsetEnd;
+}
+
+SkPoint SkVarWidthStroker::unitNormal(const PathSegment& seg, float t, SkPoint* tangentOut) {
+ switch (seg.fVerb) {
+ case SkPath::kLine_Verb: {
+ const SkPoint tangent = setLength(seg.fPoints[1] - seg.fPoints[0], 1);
+ const SkPoint normal = rotate90(tangent);
+ if (tangentOut) {
+ *tangentOut = tangent;
+ }
+ return normal;
+ }
+ case SkPath::kQuad_Verb: {
+ SkPoint tangent;
+ if (t == 0) {
+ tangent = seg.fPoints[1] - seg.fPoints[0];
+ } else if (t == 1) {
+ tangent = seg.fPoints[2] - seg.fPoints[1];
+ } else {
+ tangent = ((seg.fPoints[1] - seg.fPoints[0]) * (1 - t) +
+ (seg.fPoints[2] - seg.fPoints[1]) * t) *
+ 2;
+ }
+ if (!tangent.normalize()) {
+ SkDebugf("Failed to normalize quad tangent\n");
+ SkASSERT(false);
+ }
+ if (tangentOut) {
+ *tangentOut = tangent;
+ }
+ return rotate90(tangent);
+ }
+ case SkPath::kCubic_Verb: {
+ SkPoint tangent;
+ SkEvalCubicAt(seg.fPoints.data(), t, nullptr, &tangent, nullptr);
+ if (!tangent.normalize()) {
+ SkDebugf("Failed to normalize cubic tangent\n");
+ SkASSERT(false);
+ }
+ if (tangentOut) {
+ *tangentOut = tangent;
+ }
+ return rotate90(tangent);
+ }
+ default:
+ SkDebugf("Unhandled verb for unit normal %d\n", seg.fVerb);
+ SkASSERT(false);
+ return {};
+ }
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+class VariableWidthStroker : public Sample {
+public:
+ VariableWidthStroker()
+ : fShowHidden(true)
+ , fShowSkeleton(true)
+ , fShowStrokePoints(false)
+ , fShowUI(false)
+ , fDifferentInnerFunc(false)
+ , fShowErrorCurve(false) {
+ resetToDefaults();
+
+ fPtsPaint.setAntiAlias(true);
+ fPtsPaint.setStrokeWidth(10);
+ fPtsPaint.setStrokeCap(SkPaint::kRound_Cap);
+
+ fStrokePointsPaint.setAntiAlias(true);
+ fStrokePointsPaint.setStrokeWidth(5);
+ fStrokePointsPaint.setStrokeCap(SkPaint::kRound_Cap);
+
+ fStrokePaint.setAntiAlias(true);
+ fStrokePaint.setStyle(SkPaint::kStroke_Style);
+ fStrokePaint.setColor(0x80FF0000);
+
+ fNewFillPaint.setAntiAlias(true);
+ fNewFillPaint.setColor(0x8000FF00);
+
+ fHiddenPaint.setAntiAlias(true);
+ fHiddenPaint.setStyle(SkPaint::kStroke_Style);
+ fHiddenPaint.setColor(0xFF0000FF);
+
+ fSkeletonPaint.setAntiAlias(true);
+ fSkeletonPaint.setStyle(SkPaint::kStroke_Style);
+ fSkeletonPaint.setColor(SK_ColorRED);
+ }
+
+private:
+ /** Selectable menu item for choosing distance functions */
+ struct DistFncMenuItem {
+ std::string fName;
+ int fDegree;
+ bool fSelected;
+ std::vector<float> fWeights;
+
+ DistFncMenuItem(const std::string& name, int degree, bool selected) {
+ fName = name;
+ fDegree = degree;
+ fSelected = selected;
+ fWeights.resize(degree + 1, 1.0f);
+ }
+ };
+
+ SkString name() override { return SkString("VariableWidthStroker"); }
+
+ void onSizeChange() override {
+ fWinSize = SkSize::Make(this->width(), this->height());
+ INHERITED::onSizeChange();
+ }
+
+ bool onChar(SkUnichar uni) override {
+ switch (uni) {
+ case '0':
+ this->toggle(fShowUI);
+ return true;
+ case '1':
+ this->toggle(fShowSkeleton);
+ return true;
+ case '2':
+ this->toggle(fShowHidden);
+ return true;
+ case '3':
+ this->toggle(fShowStrokePoints);
+ return true;
+ case '4':
+ this->toggle(fShowErrorCurve);
+ return true;
+ case '5':
+ this->toggle(fLengthMetric);
+ return true;
+ case 'x':
+ resetToDefaults();
+ return true;
+ case '-':
+ fWidth -= 5;
+ return true;
+ case '=':
+ fWidth += 5;
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ void toggle(bool& value) { value = !value; }
+ void toggle(SkVarWidthStroker::LengthMetric& value) {
+ value = value == SkVarWidthStroker::LengthMetric::kPathLength
+ ? SkVarWidthStroker::LengthMetric::kNumSegments
+ : SkVarWidthStroker::LengthMetric::kPathLength;
+ }
+
+ void resetToDefaults() {
+ fPathPts[0] = {300, 400};
+ fPathPts[1] = {500, 400};
+ fPathPts[2] = {700, 400};
+ fPathPts[3] = {900, 400};
+ fPathPts[4] = {1100, 400};
+
+ fWidth = 175;
+
+ fLengthMetric = SkVarWidthStroker::LengthMetric::kPathLength;
+ fDistFncs = fDefaultsDistFncs;
+ fDistFncsInner = fDefaultsDistFncs;
+ }
+
+ void makePath(SkPath* path) {
+ path->moveTo(fPathPts[0]);
+ path->quadTo(fPathPts[1], fPathPts[2]);
+ path->quadTo(fPathPts[3], fPathPts[4]);
+ }
+
+ static ScalarBezCurve makeDistFnc(const std::vector<DistFncMenuItem>& fncs, float strokeWidth) {
+ const float radius = strokeWidth / 2;
+ for (const auto& df : fncs) {
+ if (df.fSelected) {
+ return ScalarBezCurve::Mul(ScalarBezCurve(df.fDegree, df.fWeights), radius);
+ }
+ }
+ SkASSERT(false);
+ return ScalarBezCurve(0, {radius});
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ canvas->drawColor(0xFFEEEEEE);
+
+ SkPath path;
+ this->makePath(&path);
+
+ fStrokePaint.setStrokeWidth(fWidth);
+
+ // Elber-Cohen stroker result
+ ScalarBezCurve distFnc = makeDistFnc(fDistFncs, fWidth);
+ ScalarBezCurve distFncInner =
+ fDifferentInnerFunc ? makeDistFnc(fDistFncsInner, fWidth) : distFnc;
+ SkVarWidthStroker stroker;
+ SkPath fillPath =
+ stroker.getFillPath(path, fStrokePaint, distFnc, distFncInner, fLengthMetric);
+ fillPath.setFillType(SkPathFillType::kWinding);
+ canvas->drawPath(fillPath, fNewFillPaint);
+
+ if (fShowHidden) {
+ canvas->drawPath(fillPath, fHiddenPaint);
+ }
+
+ if (fShowSkeleton) {
+ canvas->drawPath(path, fSkeletonPaint);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, fPathPts.size(), fPathPts.data(),
+ fPtsPaint);
+ }
+
+ if (fShowStrokePoints) {
+ drawStrokePoints(canvas, fillPath);
+ }
+
+ if (fShowUI) {
+ drawUI();
+ }
+
+ if (fShowErrorCurve && viz::outerErr != nullptr) {
+ SkPaint firstApproxPaint;
+ firstApproxPaint.setStrokeWidth(4);
+ firstApproxPaint.setStyle(SkPaint::kStroke_Style);
+ firstApproxPaint.setColor(SK_ColorRED);
+ canvas->drawPath(viz::outerFirstApprox, firstApproxPaint);
+ drawErrorCurve(canvas, *viz::outerErr);
+ }
+ }
+
+ Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
+ const SkScalar tol = 4;
+ const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
+ for (size_t i = 0; i < fPathPts.size(); ++i) {
+ if (r.intersects(SkRect::MakeXYWH(fPathPts[i].fX, fPathPts[i].fY, 1, 1))) {
+ return new Click([this, i](Click* c) {
+ fPathPts[i] = c->fCurr;
+ return true;
+ });
+ }
+ }
+ return nullptr;
+ }
+
+ void drawStrokePoints(SkCanvas* canvas, const SkPath& fillPath) {
+ SkPath::Iter it(fillPath, false);
+ SkPoint points[4];
+ SkPath::Verb verb;
+ std::vector<SkPoint> pointsVec, ctrlPts;
+ while ((verb = it.next(&points[0])) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kLine_Verb:
+ pointsVec.push_back(points[1]);
+ break;
+ case SkPath::kQuad_Verb:
+ ctrlPts.push_back(points[1]);
+ pointsVec.push_back(points[2]);
+ break;
+ case SkPath::kMove_Verb:
+ pointsVec.push_back(points[0]);
+ break;
+ case SkPath::kClose_Verb:
+ break;
+ default:
+ SkDebugf("Unhandled path verb %d for stroke points\n", verb);
+ SkASSERT(false);
+ break;
+ }
+ }
+
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, pointsVec.size(), pointsVec.data(),
+ fStrokePointsPaint);
+ fStrokePointsPaint.setColor(SK_ColorBLUE);
+ fStrokePointsPaint.setStrokeWidth(3);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, ctrlPts.size(), ctrlPts.data(),
+ fStrokePointsPaint);
+ fStrokePointsPaint.setColor(SK_ColorBLACK);
+ fStrokePointsPaint.setStrokeWidth(5);
+ }
+
+ void drawErrorCurve(SkCanvas* canvas, const ScalarBezCurve& E) {
+ const float winW = fWinSize.width() * 0.75f, winH = fWinSize.height() * 0.25f;
+ const float padding = 25;
+ const SkRect box = SkRect::MakeXYWH(padding, fWinSize.height() - winH - padding,
+ winW - 2 * padding, winH);
+ constexpr int nsegs = 100;
+ constexpr float dt = 1.0f / nsegs;
+ constexpr float dx = 10.0f;
+ const int deg = E.degree();
+ SkPath path;
+ for (int i = 0; i < nsegs; i++) {
+ const float tmin = i * dt, tmax = (i + 1) * dt;
+ ScalarBezCurve left(deg), right(deg);
+ E.split(tmax, &left, &right);
+ const float tRel = tmin / tmax;
+ ScalarBezCurve rl(deg), rr(deg);
+ left.split(tRel, &rl, &rr);
+
+ const float x = i * dx;
+ if (i == 0) {
+ path.moveTo(x, -rr[0]);
+ }
+ path.lineTo(x + dx, -rr[deg]);
+ }
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setAntiAlias(true);
+ paint.setStrokeWidth(0);
+ paint.setColor(SK_ColorRED);
+ const SkRect pathBounds = path.computeTightBounds();
+ constexpr float yAxisMax = 8000;
+ const float sx = box.width() / pathBounds.width();
+ const float sy = box.height() / (2 * yAxisMax);
+ canvas->save();
+ canvas->translate(box.left(), box.top() + box.height() / 2);
+ canvas->scale(sx, sy);
+ canvas->drawPath(path, paint);
+
+ SkPath axes;
+ axes.moveTo(0, 0);
+ axes.lineTo(pathBounds.width(), 0);
+ axes.moveTo(0, -yAxisMax);
+ axes.lineTo(0, yAxisMax);
+ paint.setColor(SK_ColorBLACK);
+ paint.setAntiAlias(false);
+ canvas->drawPath(axes, paint);
+
+ canvas->restore();
+ }
+
+ void drawUI() {
+ static constexpr auto kUIOpacity = 0.35f;
+ static constexpr float kUIWidth = 200.0f, kUIHeight = 400.0f;
+ ImGui::SetNextWindowBgAlpha(kUIOpacity);
+ if (ImGui::Begin("E-C Controls", nullptr,
+ ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize |
+ ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
+ ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) {
+ const SkRect uiArea = SkRect::MakeXYWH(10, 10, kUIWidth, kUIHeight);
+ ImGui::SetWindowPos(ImVec2(uiArea.x(), uiArea.y()));
+ ImGui::SetWindowSize(ImVec2(uiArea.width(), uiArea.height()));
+
+ const auto drawControls = [](std::vector<DistFncMenuItem>& distFncs,
+ const std::string& menuPfx,
+ const std::string& ptPfx) {
+ std::string degreeMenuLabel = menuPfx + ": ";
+ for (const auto& df : distFncs) {
+ if (df.fSelected) {
+ degreeMenuLabel += df.fName;
+ break;
+ }
+ }
+ if (ImGui::BeginMenu(degreeMenuLabel.c_str())) {
+ for (size_t i = 0; i < distFncs.size(); i++) {
+ if (ImGui::MenuItem(distFncs[i].fName.c_str(), nullptr,
+ distFncs[i].fSelected)) {
+ for (size_t j = 0; j < distFncs.size(); j++) {
+ distFncs[j].fSelected = j == i;
+ }
+ }
+ }
+ ImGui::EndMenu();
+ }
+
+ for (auto& df : distFncs) {
+ if (df.fSelected) {
+ for (int i = 0; i <= df.fDegree; i++) {
+ const std::string label = ptPfx + std::to_string(i);
+ ImGui::SliderFloat(label.c_str(), &(df.fWeights[i]), 0, 1);
+ }
+ }
+ }
+ };
+
+ const std::array<std::pair<std::string, SkVarWidthStroker::LengthMetric>, 2> metrics = {
+ std::make_pair("% path length", SkVarWidthStroker::LengthMetric::kPathLength),
+ std::make_pair("% segment count",
+ SkVarWidthStroker::LengthMetric::kNumSegments),
+ };
+ if (ImGui::BeginMenu("Interpolation metric:")) {
+ for (const auto& metric : metrics) {
+ if (ImGui::MenuItem(metric.first.c_str(), nullptr,
+ fLengthMetric == metric.second)) {
+ fLengthMetric = metric.second;
+ }
+ }
+ ImGui::EndMenu();
+ }
+
+ drawControls(fDistFncs, "Degree", "P");
+
+ if (ImGui::CollapsingHeader("Inner stroke", true)) {
+ fDifferentInnerFunc = true;
+ drawControls(fDistFncsInner, "Degree (inner)", "Q");
+ } else {
+ fDifferentInnerFunc = false;
+ }
+ }
+ ImGui::End();
+ }
+
+ bool fShowHidden, fShowSkeleton, fShowStrokePoints, fShowUI, fDifferentInnerFunc,
+ fShowErrorCurve;
+ float fWidth = 175;
+ SkPaint fPtsPaint, fStrokePaint, fNewFillPaint, fHiddenPaint, fSkeletonPaint,
+ fStrokePointsPaint;
+ inline static constexpr int kNPts = 5;
+ std::array<SkPoint, kNPts> fPathPts;
+ SkSize fWinSize;
+ SkVarWidthStroker::LengthMetric fLengthMetric;
+ const std::vector<DistFncMenuItem> fDefaultsDistFncs = {
+ DistFncMenuItem("Linear", 1, true), DistFncMenuItem("Quadratic", 2, false),
+ DistFncMenuItem("Cubic", 3, false), DistFncMenuItem("One Louder (11)", 11, false),
+ DistFncMenuItem("30?!", 30, false)};
+ std::vector<DistFncMenuItem> fDistFncs = fDefaultsDistFncs;
+ std::vector<DistFncMenuItem> fDistFncsInner = fDefaultsDistFncs;
+
+ using INHERITED = Sample;
+};
+
+DEF_SAMPLE(return new VariableWidthStroker;)
diff --git a/third_party/skia/samplecode/SampleVertices.cpp b/third_party/skia/samplecode/SampleVertices.cpp
index 25afd41..d2c7fea 100644
--- a/third_party/skia/samplecode/SampleVertices.cpp
+++ b/third_party/skia/samplecode/SampleVertices.cpp
@@ -34,7 +34,8 @@
pixels[0] = pixels[2] = color0;
pixels[1] = pixels[3] = color1;
- return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat);
+ return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
+ SkSamplingOptions(SkFilterMode::kLinear));
}
static sk_sp<SkShader> make_shader1(const SkIPoint& size) {
@@ -73,7 +74,6 @@
void onDrawContent(SkCanvas* canvas) override {
SkPaint paint;
paint.setDither(true);
- paint.setFilterQuality(kLow_SkFilterQuality);
for (size_t i = 0; i < SK_ARRAY_COUNT(fRecs); i++) {
auto verts = SkVertices::MakeCopy(fRecs[i].fMode, fRecs[i].fCount,
@@ -204,7 +204,7 @@
Rec fRecs[3];
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleWritePixels.cpp b/third_party/skia/samplecode/SampleWritePixels.cpp
index f6d31e5..eeed376 100644
--- a/third_party/skia/samplecode/SampleWritePixels.cpp
+++ b/third_party/skia/samplecode/SampleWritePixels.cpp
@@ -32,9 +32,9 @@
WritePixelsView() {}
protected:
- virtual SkString name() { return SkString("WritePixels"); }
+ SkString name() override { return SkString("WritePixels"); }
- virtual void onDrawContent(SkCanvas* canvas) {
+ void onDrawContent(SkCanvas* canvas) override {
SkBitmap bitmap;
create_bitmap(&bitmap);
int x = bitmap.width() / 2;
@@ -50,7 +50,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/skia/samplecode/SampleXfer.cpp b/third_party/skia/samplecode/SampleXfer.cpp
index ba0a939..68b179e 100644
--- a/third_party/skia/samplecode/SampleXfer.cpp
+++ b/third_party/skia/samplecode/SampleXfer.cpp
@@ -193,9 +193,114 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
+DEF_SAMPLE( return new XferDemo; )
//////////////////////////////////////////////////////////////////////////////
-DEF_SAMPLE( return new XferDemo; )
+#include "tools/Resources.h"
+
+class CubicResamplerDemo : public Sample {
+ struct Rec {
+ sk_sp<SkImage> fImage;
+ SkRect fBounds;
+
+ void draw(SkCanvas* canvas, SkCubicResampler cubic) const {
+ SkRect r = fBounds;
+ SkPaint paint;
+
+ SkMatrix lm = SkMatrix::Translate(r.x(), r.y())
+ * SkMatrix::Scale(10, 10);
+ paint.setShader(fImage->makeShader(SkSamplingOptions(), lm));
+ canvas->drawRect(r, paint);
+
+ r.offset(r.width() + 10, 0);
+ lm.postTranslate(r.width() + 10, 0);
+
+ paint.setShader(fImage->makeShader(SkSamplingOptions(SkFilterMode::kLinear), lm));
+ canvas->drawRect(r, paint);
+
+ r.offset(r.width() + 10, 0);
+ lm.postTranslate(r.width() + 10, 0);
+
+ paint.setShader(fImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
+ SkSamplingOptions(cubic), &lm));
+ canvas->drawRect(r, paint);
+ }
+ };
+ std::vector<Rec> fRecs;
+
+public:
+ CubicResamplerDemo() {
+ const char* names[] = {
+ "images/mandrill_128.png",
+ "images/rle.bmp",
+ "images/example_4.png",
+ };
+ SkRect r = {10, 10, 200, 200};
+ for (auto name : names) {
+ fRecs.push_back({GetResourceAsImage(name), r});
+ r.offset(0, r.height() + 10);
+ }
+
+ fDomain.setXYWH(r.fLeft + 3*r.width() + 40, 50, 200, 200);
+ fCubic = {.3f, .5f};
+ }
+
+protected:
+ SkString name() override { return SkString("CubicResampler"); }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ for (const auto& rec : fRecs) {
+ rec.draw(canvas, fCubic);
+ }
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStroke(true);
+ canvas->drawRect(fDomain, paint);
+
+ paint.setColor(SK_ColorRED);
+ paint.setStroke(false);
+ SkPoint loc = SkMatrix::RectToRect({0,0,1,1}, fDomain).mapXY(fCubic.B, fCubic.C);
+ canvas->drawCircle(loc.fX, loc.fY, 8, paint);
+
+ SkString str;
+ str.printf("B=%4.2f C=%4.2f", fCubic.B, fCubic.C);
+ SkFont font;
+ font.setSize(25);
+ font.setEdging(SkFont::Edging::kAntiAlias);
+ paint.setColor(SK_ColorBLACK);
+ canvas->drawSimpleText(str.c_str(), str.size(), SkTextEncoding::kUTF8,
+ fDomain.fLeft + 10, fDomain.fBottom + 40, font, paint);
+ }
+
+ static float pin_unitize(float min, float max, float value) {
+ return (std::min(std::max(value, min), max) - min) / (max - min);
+ }
+ static SkPoint pin_unitize(const SkRect& r, SkPoint p) {
+ return {
+ pin_unitize(r.fLeft, r.fRight, p.fX),
+ pin_unitize(r.fTop, r.fBottom, p.fY),
+ };
+ }
+
+ Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
+ if (fDomain.contains(x, y)) {
+ return new Click([this](Click* click) {
+ auto [B, C] = pin_unitize(fDomain, click->fCurr);
+ fCubic = {B, C};
+ return true;
+ });
+ }
+ return nullptr;
+ }
+
+private:
+ SkRect fDomain;
+ SkImage::CubicResampler fCubic;
+
+ using INHERITED = Sample;
+};
+DEF_SAMPLE( return new CubicResamplerDemo; )
diff --git a/third_party/skia/samplecode/SampleXfermodesBlur.cpp b/third_party/skia/samplecode/SampleXfermodesBlur.cpp
index 9ec35dc..bd603d5 100644
--- a/third_party/skia/samplecode/SampleXfermodesBlur.cpp
+++ b/third_party/skia/samplecode/SampleXfermodesBlur.cpp
@@ -25,8 +25,8 @@
#include "src/utils/SkUTF.h"
#include "include/core/SkColorPriv.h"
+#include "include/core/SkMaskFilter.h"
#include "include/core/SkStream.h"
-#include "include/effects/SkBlurMaskFilter.h"
static void setNamedTypeface(SkFont* font, const char name[]) {
font->setTypeface(SkTypeface::MakeFromName(name, SkFontStyle()));
@@ -73,9 +73,9 @@
}
protected:
- virtual SkString name() { return SkString("XfermodesBlur"); }
+ SkString name() override { return SkString("XfermodesBlur"); }
- virtual void onDrawContent(SkCanvas* canvas) {
+ void onDrawContent(SkCanvas* canvas) override {
canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
const SkBlendMode gModes[] = {
@@ -98,13 +98,13 @@
const SkScalar h = SkIntToScalar(H);
SkMatrix m;
m.setScale(SkIntToScalar(6), SkIntToScalar(6));
- auto s = fBG.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, &m);
+ auto s = fBG.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions(), m);
SkFont font;
font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
setNamedTypeface(&font, "Menlo Regular");
- const int W = 5;
+ const int kWrap = 5;
SkScalar x0 = 0;
for (int twice = 0; twice < 2; twice++) {
@@ -131,7 +131,7 @@
SkTextUtils::DrawString(canvas, label, x + w/2, y - font.getSize()/2, font, SkPaint(),
SkTextUtils::kCenter_Align);
x += w + SkIntToScalar(10);
- if ((i % W) == W - 1) {
+ if ((i % kWrap) == kWrap - 1) {
x = x0;
y += h + SkIntToScalar(30);
}
@@ -141,7 +141,7 @@
}
private:
- typedef Sample INHERITED;
+ using INHERITED = Sample;
};
//////////////////////////////////////////////////////////////////////////////