From 3b526b05d652ad6c310d9c636187b20b51c7648c Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Fri, 25 May 2018 12:43:51 -0400 Subject: "Modularize" SkSG * relocate all SkSG-related files under modules/sksg/ * fix various tidbits to make non-sksg builds possible * drop obsolete SampleSGInval.cpp Change-Id: I54e6c5bb1a09f45030fa8d607b3eb3f7cba78957 Reviewed-on: https://skia-review.googlesource.com/130025 Commit-Queue: Florin Malita Reviewed-by: Mike Klein --- BUILD.gn | 52 +--- experimental/sksg/SkSGDraw.cpp | 50 ---- experimental/sksg/SkSGDraw.h | 48 ---- experimental/sksg/SkSGEffectNode.cpp | 31 --- experimental/sksg/SkSGEffectNode.h | 38 --- experimental/sksg/SkSGGeometryNode.cpp | 32 --- experimental/sksg/SkSGGeometryNode.h | 49 ---- experimental/sksg/SkSGGroup.cpp | 66 ----- experimental/sksg/SkSGGroup.h | 47 ---- experimental/sksg/SkSGImage.cpp | 29 -- experimental/sksg/SkSGImage.h | 49 ---- experimental/sksg/SkSGInvalidationController.cpp | 32 --- experimental/sksg/SkSGInvalidationController.h | 43 --- experimental/sksg/SkSGNode.cpp | 152 ----------- experimental/sksg/SkSGNode.h | 107 -------- experimental/sksg/SkSGPaintNode.cpp | 41 --- experimental/sksg/SkSGPaintNode.h | 60 ----- experimental/sksg/SkSGRenderNode.cpp | 19 -- experimental/sksg/SkSGRenderNode.h | 36 --- experimental/sksg/SkSGScene.cpp | 70 ----- experimental/sksg/SkSGScene.h | 85 ------ experimental/sksg/effects/SkSGClipEffect.cpp | 50 ---- experimental/sksg/effects/SkSGClipEffect.h | 50 ---- experimental/sksg/effects/SkSGMaskEffect.cpp | 54 ---- experimental/sksg/effects/SkSGMaskEffect.h | 51 ---- experimental/sksg/effects/SkSGOpacityEffect.cpp | 42 --- experimental/sksg/effects/SkSGOpacityEffect.h | 42 --- experimental/sksg/effects/SkSGTransform.cpp | 70 ----- experimental/sksg/effects/SkSGTransform.h | 81 ------ .../sksg/geometry/SkSGGeometryTransform.cpp | 53 ---- experimental/sksg/geometry/SkSGGeometryTransform.h | 58 ---- experimental/sksg/geometry/SkSGMerge.cpp | 84 ------ experimental/sksg/geometry/SkSGMerge.h | 64 ----- experimental/sksg/geometry/SkSGPath.cpp | 41 --- experimental/sksg/geometry/SkSGPath.h | 48 ---- experimental/sksg/geometry/SkSGPlane.cpp | 36 --- experimental/sksg/geometry/SkSGPlane.h | 40 --- experimental/sksg/geometry/SkSGRect.cpp | 60 ----- experimental/sksg/geometry/SkSGRect.h | 76 ------ experimental/sksg/geometry/SkSGRoundEffect.cpp | 56 ---- experimental/sksg/geometry/SkSGRoundEffect.h | 50 ---- experimental/sksg/geometry/SkSGText.cpp | 77 ------ experimental/sksg/geometry/SkSGText.h | 69 ----- experimental/sksg/geometry/SkSGTrimEffect.cpp | 56 ---- experimental/sksg/geometry/SkSGTrimEffect.h | 58 ---- experimental/sksg/paint/SkSGColor.cpp | 18 -- experimental/sksg/paint/SkSGColor.h | 37 --- experimental/sksg/paint/SkSGGradient.cpp | 60 ----- experimental/sksg/paint/SkSGGradient.h | 105 -------- gn/samples.gni | 2 - gn/tests.gni | 1 - modules/sksg/BUILD.gn | 90 +++++++ modules/sksg/include/SkSGClipEffect.h | 50 ++++ modules/sksg/include/SkSGColor.h | 37 +++ modules/sksg/include/SkSGDraw.h | 48 ++++ modules/sksg/include/SkSGEffectNode.h | 38 +++ modules/sksg/include/SkSGGeometryNode.h | 49 ++++ modules/sksg/include/SkSGGeometryTransform.h | 58 ++++ modules/sksg/include/SkSGGradient.h | 105 ++++++++ modules/sksg/include/SkSGGroup.h | 47 ++++ modules/sksg/include/SkSGImage.h | 49 ++++ modules/sksg/include/SkSGInvalidationController.h | 43 +++ modules/sksg/include/SkSGMaskEffect.h | 51 ++++ modules/sksg/include/SkSGMerge.h | 64 +++++ modules/sksg/include/SkSGNode.h | 107 ++++++++ modules/sksg/include/SkSGOpacityEffect.h | 42 +++ modules/sksg/include/SkSGPaintNode.h | 60 +++++ modules/sksg/include/SkSGPath.h | 48 ++++ modules/sksg/include/SkSGPlane.h | 40 +++ modules/sksg/include/SkSGRect.h | 76 ++++++ modules/sksg/include/SkSGRenderNode.h | 36 +++ modules/sksg/include/SkSGRoundEffect.h | 50 ++++ modules/sksg/include/SkSGScene.h | 85 ++++++ modules/sksg/include/SkSGText.h | 69 +++++ modules/sksg/include/SkSGTransform.h | 81 ++++++ modules/sksg/include/SkSGTrimEffect.h | 58 ++++ modules/sksg/samples/SampleSVGPong.cpp | 299 +++++++++++++++++++++ modules/sksg/src/SkSGClipEffect.cpp | 50 ++++ modules/sksg/src/SkSGColor.cpp | 18 ++ modules/sksg/src/SkSGDraw.cpp | 50 ++++ modules/sksg/src/SkSGEffectNode.cpp | 31 +++ modules/sksg/src/SkSGGeometryNode.cpp | 32 +++ modules/sksg/src/SkSGGeometryTransform.cpp | 53 ++++ modules/sksg/src/SkSGGradient.cpp | 60 +++++ modules/sksg/src/SkSGGroup.cpp | 66 +++++ modules/sksg/src/SkSGImage.cpp | 29 ++ modules/sksg/src/SkSGInvalidationController.cpp | 32 +++ modules/sksg/src/SkSGMaskEffect.cpp | 54 ++++ modules/sksg/src/SkSGMerge.cpp | 84 ++++++ modules/sksg/src/SkSGNode.cpp | 152 +++++++++++ modules/sksg/src/SkSGOpacityEffect.cpp | 42 +++ modules/sksg/src/SkSGPaintNode.cpp | 41 +++ modules/sksg/src/SkSGPath.cpp | 41 +++ modules/sksg/src/SkSGPlane.cpp | 36 +++ modules/sksg/src/SkSGRect.cpp | 60 +++++ modules/sksg/src/SkSGRenderNode.cpp | 19 ++ modules/sksg/src/SkSGRoundEffect.cpp | 56 ++++ modules/sksg/src/SkSGScene.cpp | 70 +++++ modules/sksg/src/SkSGText.cpp | 77 ++++++ modules/sksg/src/SkSGTransform.cpp | 70 +++++ modules/sksg/src/SkSGTrimEffect.cpp | 56 ++++ modules/sksg/tests/SGTest.cpp | 197 ++++++++++++++ samplecode/SampleSGInval.cpp | 94 ------- samplecode/SampleSVGPong.cpp | 299 --------------------- tests/SGTest.cpp | 197 -------------- tools/viewer/SlideDir.cpp | 4 + tools/viewer/Viewer.cpp | 8 +- 107 files changed, 3273 insertions(+), 3310 deletions(-) delete mode 100644 experimental/sksg/SkSGDraw.cpp delete mode 100644 experimental/sksg/SkSGDraw.h delete mode 100644 experimental/sksg/SkSGEffectNode.cpp delete mode 100644 experimental/sksg/SkSGEffectNode.h delete mode 100644 experimental/sksg/SkSGGeometryNode.cpp delete mode 100644 experimental/sksg/SkSGGeometryNode.h delete mode 100644 experimental/sksg/SkSGGroup.cpp delete mode 100644 experimental/sksg/SkSGGroup.h delete mode 100644 experimental/sksg/SkSGImage.cpp delete mode 100644 experimental/sksg/SkSGImage.h delete mode 100644 experimental/sksg/SkSGInvalidationController.cpp delete mode 100644 experimental/sksg/SkSGInvalidationController.h delete mode 100644 experimental/sksg/SkSGNode.cpp delete mode 100644 experimental/sksg/SkSGNode.h delete mode 100644 experimental/sksg/SkSGPaintNode.cpp delete mode 100644 experimental/sksg/SkSGPaintNode.h delete mode 100644 experimental/sksg/SkSGRenderNode.cpp delete mode 100644 experimental/sksg/SkSGRenderNode.h delete mode 100644 experimental/sksg/SkSGScene.cpp delete mode 100644 experimental/sksg/SkSGScene.h delete mode 100644 experimental/sksg/effects/SkSGClipEffect.cpp delete mode 100644 experimental/sksg/effects/SkSGClipEffect.h delete mode 100644 experimental/sksg/effects/SkSGMaskEffect.cpp delete mode 100644 experimental/sksg/effects/SkSGMaskEffect.h delete mode 100644 experimental/sksg/effects/SkSGOpacityEffect.cpp delete mode 100644 experimental/sksg/effects/SkSGOpacityEffect.h delete mode 100644 experimental/sksg/effects/SkSGTransform.cpp delete mode 100644 experimental/sksg/effects/SkSGTransform.h delete mode 100644 experimental/sksg/geometry/SkSGGeometryTransform.cpp delete mode 100644 experimental/sksg/geometry/SkSGGeometryTransform.h delete mode 100644 experimental/sksg/geometry/SkSGMerge.cpp delete mode 100644 experimental/sksg/geometry/SkSGMerge.h delete mode 100644 experimental/sksg/geometry/SkSGPath.cpp delete mode 100644 experimental/sksg/geometry/SkSGPath.h delete mode 100644 experimental/sksg/geometry/SkSGPlane.cpp delete mode 100644 experimental/sksg/geometry/SkSGPlane.h delete mode 100644 experimental/sksg/geometry/SkSGRect.cpp delete mode 100644 experimental/sksg/geometry/SkSGRect.h delete mode 100644 experimental/sksg/geometry/SkSGRoundEffect.cpp delete mode 100644 experimental/sksg/geometry/SkSGRoundEffect.h delete mode 100644 experimental/sksg/geometry/SkSGText.cpp delete mode 100644 experimental/sksg/geometry/SkSGText.h delete mode 100644 experimental/sksg/geometry/SkSGTrimEffect.cpp delete mode 100644 experimental/sksg/geometry/SkSGTrimEffect.h delete mode 100644 experimental/sksg/paint/SkSGColor.cpp delete mode 100644 experimental/sksg/paint/SkSGColor.h delete mode 100644 experimental/sksg/paint/SkSGGradient.cpp delete mode 100644 experimental/sksg/paint/SkSGGradient.h create mode 100644 modules/sksg/BUILD.gn create mode 100644 modules/sksg/include/SkSGClipEffect.h create mode 100644 modules/sksg/include/SkSGColor.h create mode 100644 modules/sksg/include/SkSGDraw.h create mode 100644 modules/sksg/include/SkSGEffectNode.h create mode 100644 modules/sksg/include/SkSGGeometryNode.h create mode 100644 modules/sksg/include/SkSGGeometryTransform.h create mode 100644 modules/sksg/include/SkSGGradient.h create mode 100644 modules/sksg/include/SkSGGroup.h create mode 100644 modules/sksg/include/SkSGImage.h create mode 100644 modules/sksg/include/SkSGInvalidationController.h create mode 100644 modules/sksg/include/SkSGMaskEffect.h create mode 100644 modules/sksg/include/SkSGMerge.h create mode 100644 modules/sksg/include/SkSGNode.h create mode 100644 modules/sksg/include/SkSGOpacityEffect.h create mode 100644 modules/sksg/include/SkSGPaintNode.h create mode 100644 modules/sksg/include/SkSGPath.h create mode 100644 modules/sksg/include/SkSGPlane.h create mode 100644 modules/sksg/include/SkSGRect.h create mode 100644 modules/sksg/include/SkSGRenderNode.h create mode 100644 modules/sksg/include/SkSGRoundEffect.h create mode 100644 modules/sksg/include/SkSGScene.h create mode 100644 modules/sksg/include/SkSGText.h create mode 100644 modules/sksg/include/SkSGTransform.h create mode 100644 modules/sksg/include/SkSGTrimEffect.h create mode 100644 modules/sksg/samples/SampleSVGPong.cpp create mode 100644 modules/sksg/src/SkSGClipEffect.cpp create mode 100644 modules/sksg/src/SkSGColor.cpp create mode 100644 modules/sksg/src/SkSGDraw.cpp create mode 100644 modules/sksg/src/SkSGEffectNode.cpp create mode 100644 modules/sksg/src/SkSGGeometryNode.cpp create mode 100644 modules/sksg/src/SkSGGeometryTransform.cpp create mode 100644 modules/sksg/src/SkSGGradient.cpp create mode 100644 modules/sksg/src/SkSGGroup.cpp create mode 100644 modules/sksg/src/SkSGImage.cpp create mode 100644 modules/sksg/src/SkSGInvalidationController.cpp create mode 100644 modules/sksg/src/SkSGMaskEffect.cpp create mode 100644 modules/sksg/src/SkSGMerge.cpp create mode 100644 modules/sksg/src/SkSGNode.cpp create mode 100644 modules/sksg/src/SkSGOpacityEffect.cpp create mode 100644 modules/sksg/src/SkSGPaintNode.cpp create mode 100644 modules/sksg/src/SkSGPath.cpp create mode 100644 modules/sksg/src/SkSGPlane.cpp create mode 100644 modules/sksg/src/SkSGRect.cpp create mode 100644 modules/sksg/src/SkSGRenderNode.cpp create mode 100644 modules/sksg/src/SkSGRoundEffect.cpp create mode 100644 modules/sksg/src/SkSGScene.cpp create mode 100644 modules/sksg/src/SkSGText.cpp create mode 100644 modules/sksg/src/SkSGTransform.cpp create mode 100644 modules/sksg/src/SkSGTrimEffect.cpp create mode 100644 modules/sksg/tests/SGTest.cpp delete mode 100644 samplecode/SampleSGInval.cpp delete mode 100644 samplecode/SampleSVGPong.cpp delete mode 100644 tests/SGTest.cpp diff --git a/BUILD.gn b/BUILD.gn index 1f515667e5..c9eb170559 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1376,11 +1376,11 @@ if (skia_enable_tools) { public_include_dirs = [ "gm" ] sources = gm_sources deps = [ - ":experimental_sksg", ":flags", ":gpu_tool_utils", ":skia", ":tool_utils", + "modules/sksg", ] } @@ -1392,12 +1392,12 @@ if (skia_enable_tools) { sources -= [ "//tests/FontMgrAndroidParserTest.cpp" ] } deps = [ - ":experimental_sksg", ":experimental_svg_model", ":flags", ":skia", ":third_party_skcms", ":tool_utils", + "modules/sksg:tests", "//third_party/libpng", "//third_party/zlib", ] @@ -1432,8 +1432,8 @@ if (skia_enable_tools) { "experimental/skottie/SkottieValue.cpp", ] deps = [ - ":experimental_sksg", ":skia", + "modules/sksg", "//third_party/rapidjson", ] } @@ -1475,44 +1475,6 @@ if (skia_enable_tools) { } } - test_lib("experimental_sksg") { - public_include_dirs = [ - "experimental/sksg", - "experimental/sksg/effects", - "experimental/sksg/geometry", - "experimental/sksg/paint", - ] - sources = [ - "experimental/sksg/SkSGDraw.cpp", - "experimental/sksg/SkSGEffectNode.cpp", - "experimental/sksg/SkSGGeometryNode.cpp", - "experimental/sksg/SkSGGroup.cpp", - "experimental/sksg/SkSGImage.cpp", - "experimental/sksg/SkSGInvalidationController.cpp", - "experimental/sksg/SkSGNode.cpp", - "experimental/sksg/SkSGPaintNode.cpp", - "experimental/sksg/SkSGRenderNode.cpp", - "experimental/sksg/SkSGScene.cpp", - "experimental/sksg/effects/SkSGClipEffect.cpp", - "experimental/sksg/effects/SkSGMaskEffect.cpp", - "experimental/sksg/effects/SkSGOpacityEffect.cpp", - "experimental/sksg/effects/SkSGTransform.cpp", - "experimental/sksg/geometry/SkSGGeometryTransform.cpp", - "experimental/sksg/geometry/SkSGMerge.cpp", - "experimental/sksg/geometry/SkSGPath.cpp", - "experimental/sksg/geometry/SkSGPlane.cpp", - "experimental/sksg/geometry/SkSGRect.cpp", - "experimental/sksg/geometry/SkSGRoundEffect.cpp", - "experimental/sksg/geometry/SkSGText.cpp", - "experimental/sksg/geometry/SkSGTrimEffect.cpp", - "experimental/sksg/paint/SkSGColor.cpp", - "experimental/sksg/paint/SkSGGradient.cpp", - ] - deps = [ - ":skia", - ] - } - if (target_cpu != "wasm") { test_lib("views") { public_include_dirs = [ "include/views" ] @@ -1591,7 +1553,6 @@ if (skia_enable_tools) { include_dirs = [ "experimental" ] sources = samples_sources deps = [ - ":experimental_sksg", ":experimental_svg_model", ":flags", ":gm", @@ -1599,6 +1560,7 @@ if (skia_enable_tools) { ":tool_utils", ":views", ":xml", + "modules/sksg:samples", ] if (skia_use_lua) { @@ -1620,7 +1582,6 @@ if (skia_enable_tools) { deps = [ ":common_flags", ":experimental_skottie", - ":experimental_sksg", ":experimental_svg_model", ":flags", ":gm", @@ -1629,6 +1590,7 @@ if (skia_enable_tools) { ":tests", ":third_party_skcms", ":tool_utils", + "modules/sksg", "//third_party/jsoncpp", "//third_party/libpng", ] @@ -1653,13 +1615,13 @@ if (skia_enable_tools) { deps = [ ":bench", ":common_flags", - ":experimental_sksg", ":experimental_svg_model", ":flags", ":gm", ":gpu_tool_utils", ":skia", ":tool_utils", + "modules/sksg", "//third_party/jsoncpp", ] } @@ -2069,7 +2031,6 @@ if (skia_enable_tools) { include_dirs = [] deps = [ - ":experimental_sksg", ":experimental_svg_model", ":flags", ":gm", @@ -2079,6 +2040,7 @@ if (skia_enable_tools) { ":skia", ":tool_utils", ":views", + "modules/sksg", "//third_party/imgui", "//third_party/jsoncpp", ] diff --git a/experimental/sksg/SkSGDraw.cpp b/experimental/sksg/SkSGDraw.cpp deleted file mode 100644 index b73bf3b577..0000000000 --- a/experimental/sksg/SkSGDraw.cpp +++ /dev/null @@ -1,50 +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 "SkSGDraw.h" - -#include "SkSGGeometryNode.h" -#include "SkSGInvalidationController.h" -#include "SkSGPaintNode.h" - -namespace sksg { - -Draw::Draw(sk_sp geometry, sk_sp paint) - : fGeometry(std::move(geometry)) - , fPaint(std::move(paint)) { - this->observeInval(fGeometry); - this->observeInval(fPaint); -} - -Draw::~Draw() { - this->unobserveInval(fGeometry); - this->unobserveInval(fPaint); -} - -void Draw::onRender(SkCanvas* canvas) const { - const auto& paint = fPaint->makePaint(); - const auto skipDraw = paint.nothingToDraw() || - (paint.getStyle() == SkPaint::kStroke_Style && paint.getStrokeWidth() <= 0); - - if (!skipDraw) { - fGeometry->draw(canvas, paint); - } -} - -SkRect Draw::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - auto bounds = fGeometry->revalidate(ic, ctm); - fPaint->revalidate(ic, ctm); - - const auto& paint = fPaint->makePaint(); - SkASSERT(paint.canComputeFastBounds()); - - return paint.computeFastBounds(bounds, &bounds); -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGDraw.h b/experimental/sksg/SkSGDraw.h deleted file mode 100644 index 20ead3d5f6..0000000000 --- a/experimental/sksg/SkSGDraw.h +++ /dev/null @@ -1,48 +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. - */ - -#ifndef SkSGDraw_DEFINED -#define SkSGDraw_DEFINED - -#include "SkSGRenderNode.h" - -namespace sksg { - -class GeometryNode; -class PaintNode; - -/** - * Concrete rendering node. - * - * Wraps and draws a [geometry, paint] tuple. - * - * Think Skia SkCanvas::drawFoo(foo, paint) calls. - */ -class Draw : public RenderNode { -public: - static sk_sp Make(sk_sp geo, sk_sp paint) { - return (geo && paint) ? sk_sp(new Draw(std::move(geo), std::move(paint))) : nullptr; - } - -protected: - Draw(sk_sp, sk_sp paint); - ~Draw() override; - - void onRender(SkCanvas*) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - sk_sp fGeometry; - sk_sp fPaint; - - typedef RenderNode INHERITED; -}; - -} // namespace sksg - -#endif // SkSGDraw_DEFINED diff --git a/experimental/sksg/SkSGEffectNode.cpp b/experimental/sksg/SkSGEffectNode.cpp deleted file mode 100644 index 70050ccb70..0000000000 --- a/experimental/sksg/SkSGEffectNode.cpp +++ /dev/null @@ -1,31 +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 "SkSGEffectNode.h" - -namespace sksg { - -EffectNode::EffectNode(sk_sp child) - : fChild(std::move(child)) { - this->observeInval(fChild); -} - -EffectNode::~EffectNode() { - this->unobserveInval(fChild); -} - -void EffectNode::onRender(SkCanvas* canvas) const { - fChild->render(canvas); -} - -SkRect EffectNode::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - return fChild->revalidate(ic, ctm); -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGEffectNode.h b/experimental/sksg/SkSGEffectNode.h deleted file mode 100644 index ab0968e96c..0000000000 --- a/experimental/sksg/SkSGEffectNode.h +++ /dev/null @@ -1,38 +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. - */ - -#ifndef SkSGEffectNode_DEFINED -#define SkSGEffectNode_DEFINED - -#include "SkSGRenderNode.h" - -namespace sksg { - -/** - * Base class for nodes which apply some transformation when rendering - * their descendants. - * - * This includes transforms, clipping, filters, etc. - */ -class EffectNode : public RenderNode { -protected: - explicit EffectNode(sk_sp); - ~EffectNode() override; - - void onRender(SkCanvas*) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - sk_sp fChild; - - typedef RenderNode INHERITED; -}; - -} // namespace sksg - -#endif // SkSGEffectNode_DEFINED diff --git a/experimental/sksg/SkSGGeometryNode.cpp b/experimental/sksg/SkSGGeometryNode.cpp deleted file mode 100644 index 6b78c488b7..0000000000 --- a/experimental/sksg/SkSGGeometryNode.cpp +++ /dev/null @@ -1,32 +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 "SkSGGeometryNode.h" - -#include "SkPath.h" - -namespace sksg { - -// Geometry nodes don't generate damage on their own, but via their aggregation ancestor Draw nodes. -GeometryNode::GeometryNode() : INHERITED(kBubbleDamage_Trait) {} - -void GeometryNode::clip(SkCanvas* canvas, bool aa) const { - SkASSERT(!this->hasInval()); - this->onClip(canvas, aa); -} - -void GeometryNode::draw(SkCanvas* canvas, const SkPaint& paint) const { - SkASSERT(!this->hasInval()); - this->onDraw(canvas, paint); -} - -SkPath GeometryNode::asPath() const { - SkASSERT(!this->hasInval()); - return this->onAsPath(); -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGGeometryNode.h b/experimental/sksg/SkSGGeometryNode.h deleted file mode 100644 index 7ce3aa9b79..0000000000 --- a/experimental/sksg/SkSGGeometryNode.h +++ /dev/null @@ -1,49 +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. - */ - -#ifndef SkSGGeometryNode_DEFINED -#define SkSGGeometryNode_DEFINED - -#include "SkSGNode.h" - -class SkCanvas; -class SkPaint; -class SkPath; - -namespace sksg { - -/** - * Base class for nodes which provide 'geometry' (as opposed to paint) - * for drawing. - * - * Think SkRect, SkPath, etc. - */ -class GeometryNode : public Node { -public: - void clip(SkCanvas*, bool antiAlias) const; - void draw(SkCanvas*, const SkPaint&) const; - - SkPath asPath() const; - -protected: - GeometryNode(); - - virtual void onClip(SkCanvas*, bool antiAlias) const = 0; - - virtual void onDraw(SkCanvas*, const SkPaint&) const = 0; - - virtual SkPath onAsPath() const = 0; - -private: - friend class Draw; // wants to know the cached bounds. - - typedef Node INHERITED; -}; - -} // namespace sksg - -#endif // SkSGGeometryNode_DEFINED diff --git a/experimental/sksg/SkSGGroup.cpp b/experimental/sksg/SkSGGroup.cpp deleted file mode 100644 index aeccf233f7..0000000000 --- a/experimental/sksg/SkSGGroup.cpp +++ /dev/null @@ -1,66 +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 "SkSGGroup.h" - -namespace sksg { - -Group::Group() {} - -Group::~Group() { - for (const auto& child : fChildren) { - this->unobserveInval(child); - } -} - -void Group::addChild(sk_sp node) { - // should we allow duplicates? - for (const auto& child : fChildren) { - if (child == node) { - return; - } - } - - this->observeInval(node); - fChildren.push_back(std::move(node)); - - this->invalidate(); -} - -void Group::removeChild(const sk_sp& node) { - int origCount = fChildren.count(); - for (int i = 0; i < origCount; ++i) { - if (fChildren[i] == node) { - fChildren.removeShuffle(i); - this->unobserveInval(node); - break; - } - } - SkASSERT(fChildren.count() == origCount - 1); - - this->invalidate(); -} - -void Group::onRender(SkCanvas* canvas) const { - for (const auto& child : fChildren) { - child->render(canvas); - } -} - -SkRect Group::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - SkRect bounds = SkRect::MakeEmpty(); - - for (const auto& child : fChildren) { - bounds.join(child->revalidate(ic, ctm)); - } - - return bounds; -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGGroup.h b/experimental/sksg/SkSGGroup.h deleted file mode 100644 index 482f10db8c..0000000000 --- a/experimental/sksg/SkSGGroup.h +++ /dev/null @@ -1,47 +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. - */ - -#ifndef SkSGGroup_DEFINED -#define SkSGGroup_DEFINED - -#include "SkSGRenderNode.h" - -#include "SkTArray.h" - -namespace sksg { - -/** - * Concrete node, grouping together multiple descendants. - */ -class Group : public RenderNode { -public: - static sk_sp Make() { - return sk_sp(new Group()); - } - - void addChild(sk_sp); - void removeChild(const sk_sp&); - - size_t size() const { return SkTo(fChildren.count()); } - bool empty() const { return fChildren.empty(); } - -protected: - Group(); - ~Group() override; - - void onRender(SkCanvas*) const override; - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - SkTArray, true> fChildren; - - typedef RenderNode INHERITED; -}; - -} // namespace sksg - -#endif // SkSGGroup_DEFINED diff --git a/experimental/sksg/SkSGImage.cpp b/experimental/sksg/SkSGImage.cpp deleted file mode 100644 index a0c3a759dc..0000000000 --- a/experimental/sksg/SkSGImage.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGImage.h" - -#include "SkCanvas.h" -#include "SkImage.h" - -namespace sksg { - -Image::Image(sk_sp image) : fImage(std::move(image)) {} - -void Image::onRender(SkCanvas* canvas) const { - SkPaint paint; - paint.setAntiAlias(fAntiAlias); - paint.setFilterQuality(fQuality); - - canvas->drawImage(fImage, 0, 0); -} - -SkRect Image::onRevalidate(InvalidationController*, const SkMatrix& ctm) { - return SkRect::Make(fImage->bounds()); -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGImage.h b/experimental/sksg/SkSGImage.h deleted file mode 100644 index 7d17a50aaa..0000000000 --- a/experimental/sksg/SkSGImage.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGImage_DEFINED -#define SkSGImage_DEFINED - -#include "SkSGRenderNode.h" - -#include "SkFilterQuality.h" - -class SkImage; - -namespace sksg { - -/** - * Concrete rendering node, wrapping an SkImage. - * - */ -class Image final : public RenderNode { -public: - static sk_sp Make(sk_sp image) { - return image ? sk_sp(new Image(std::move(image))) : nullptr; - } - - SG_ATTRIBUTE(Quality , SkFilterQuality, fQuality ) - SG_ATTRIBUTE(AntiAlias, bool , fAntiAlias) - -protected: - explicit Image(sk_sp); - - void onRender(SkCanvas*) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - const sk_sp fImage; - SkFilterQuality fQuality = kLow_SkFilterQuality; - bool fAntiAlias = true; - - typedef RenderNode INHERITED; -}; - -} // namespace sksg - -#endif // SkSGImage_DEFINED diff --git a/experimental/sksg/SkSGInvalidationController.cpp b/experimental/sksg/SkSGInvalidationController.cpp deleted file mode 100644 index 81a3376bf6..0000000000 --- a/experimental/sksg/SkSGInvalidationController.cpp +++ /dev/null @@ -1,32 +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 "SkSGInvalidationController.h" - -#include "SkRect.h" -#include "SkTLazy.h" - -namespace sksg { - -InvalidationController::InvalidationController() : fBounds(SkRect::MakeEmpty()) {} - -void InvalidationController::inval(const SkRect& r, const SkMatrix& ctm) { - if (r.isEmpty()) { - return; - } - - SkTCopyOnFirstWrite rect(r); - - if (!ctm.isIdentity()) { - ctm.mapRect(rect.writable()); - } - - fRects.push(*rect); - fBounds.join(*rect); -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGInvalidationController.h b/experimental/sksg/SkSGInvalidationController.h deleted file mode 100644 index df3857c1fe..0000000000 --- a/experimental/sksg/SkSGInvalidationController.h +++ /dev/null @@ -1,43 +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. - */ - -#ifndef SkSGInvalidationController_DEFINED -#define SkSGInvalidationController_DEFINED - -#include "SkMatrix.h" -#include "SkTDArray.h" -#include "SkTypes.h" - -struct SkRect; - -namespace sksg { - -/** - * Receiver for invalidation events. - * - * Tracks dirty regions for repaint. - */ -class InvalidationController : public SkNoncopyable { -public: - InvalidationController(); - - void inval(const SkRect&, const SkMatrix& ctm = SkMatrix::I()); - - const SkRect& bounds() const { return fBounds; } - const SkRect* begin() const { return fRects.begin(); } - const SkRect* end() const { return fRects.end(); } - -private: - SkTDArray fRects; - SkRect fBounds; - - typedef SkNoncopyable INHERITED; -}; - -} // namespace sksg - -#endif // SkSGInvalidationController_DEFINED diff --git a/experimental/sksg/SkSGNode.cpp b/experimental/sksg/SkSGNode.cpp deleted file mode 100644 index 35b2640dbb..0000000000 --- a/experimental/sksg/SkSGNode.cpp +++ /dev/null @@ -1,152 +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 "SkRectPriv.h" -#include "SkSGNode.h" -#include "SkSGInvalidationController.h" - -namespace sksg { - -class Node::ScopedFlag { -public: - ScopedFlag(Node* node, uint32_t flag) - : fNode(node) - , fFlag(flag) - , fWasSet(node->fFlags & flag) { - node->fFlags |= flag; - } - ~ScopedFlag() { - if (!fWasSet) { - fNode->fFlags &= ~fFlag;; - } - } - - bool wasSet() const { return fWasSet; } - -private: - Node* fNode; - uint32_t fFlag; - bool fWasSet; -}; - -#define TRAVERSAL_GUARD \ - ScopedFlag traversal_guard(this, kInTraversal_Flag); \ - if (traversal_guard.wasSet()) \ - return - -Node::Node(uint32_t invalTraits) - : fInvalObserver(nullptr) - , fBounds(SkRectPriv::MakeLargeS32()) - , fInvalTraits(invalTraits) - , fFlags(kInvalidated_Flag) {} - -Node::~Node() { - if (fFlags & kObserverArray_Flag) { - SkASSERT(fInvalObserverArray->isEmpty()); - delete fInvalObserverArray; - } else { - SkASSERT(!fInvalObserver); - } -} - -void Node::observeInval(const sk_sp& node) { - SkASSERT(node); - if (!(node->fFlags & kObserverArray_Flag)) { - if (!node->fInvalObserver) { - node->fInvalObserver = this; - return; - } - - auto observers = new SkTDArray(); - observers->setReserve(2); - observers->push(node->fInvalObserver); - - node->fInvalObserverArray = observers; - node->fFlags |= kObserverArray_Flag; - } - - // No duplicate observers. - SkASSERT(node->fInvalObserverArray->find(this) < 0); - - node->fInvalObserverArray->push(this); -} - -void Node::unobserveInval(const sk_sp& node) { - SkASSERT(node); - if (!(node->fFlags & kObserverArray_Flag)) { - SkASSERT(node->fInvalObserver == this); - node->fInvalObserver = nullptr; - return; - } - - const auto idx = node->fInvalObserverArray->find(this); - SkASSERT(idx >= 0); - node->fInvalObserverArray->remove(idx); -} - -template -void Node::forEachInvalObserver(Func&& func) const { - if (fFlags & kObserverArray_Flag) { - for (const auto& parent : *fInvalObserverArray) { - func(parent); - } - return; - } - - if (fInvalObserver) { - func(fInvalObserver); - } -} - -void Node::invalidate(bool damageBubbling) { - TRAVERSAL_GUARD; - - if (this->hasInval() && (!damageBubbling || (fFlags & kDamage_Flag))) { - // All done. - return; - } - - if (damageBubbling && !(fInvalTraits & kBubbleDamage_Trait)) { - // Found a damage observer. - fFlags |= kDamage_Flag; - damageBubbling = false; - } - - fFlags |= kInvalidated_Flag; - - forEachInvalObserver([&](Node* observer) { - observer->invalidate(damageBubbling); - }); -} - -const SkRect& Node::revalidate(InvalidationController* ic, const SkMatrix& ctm) { - TRAVERSAL_GUARD fBounds; - - if (!this->hasInval()) { - return fBounds; - } - - SkRect prevBounds; - if (fFlags & kDamage_Flag) { - prevBounds = fBounds; - } - - fBounds = this->onRevalidate(ic, ctm); - - if (fFlags & kDamage_Flag) { - ic->inval(prevBounds, ctm); - if (fBounds != prevBounds) { - ic->inval(fBounds, ctm); - } - } - - fFlags &= ~(kInvalidated_Flag | kDamage_Flag); - - return fBounds; -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGNode.h b/experimental/sksg/SkSGNode.h deleted file mode 100644 index 17619de485..0000000000 --- a/experimental/sksg/SkSGNode.h +++ /dev/null @@ -1,107 +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. - */ - -#ifndef SkSGNode_DEFINED -#define SkSGNode_DEFINED - -#include "SkRect.h" -#include "SkRefCnt.h" -#include "SkTDArray.h" - -class SkCanvas; -class SkMatrix; - -namespace sksg { - -class InvalidationController; - -/** - * Base class for all scene graph nodes. - * - * Handles ingress edge management for the DAG (i.e. node -> "parent" node mapping), - * and invalidation. - * - * Note: egress edges are only implemented/supported in container subclasses - * (e.g. Group, Effect, Draw). - */ -class Node : public SkRefCnt { -public: - // Traverse the DAG and revalidate any dependant/invalidated nodes. - // Returns the bounding box for the DAG fragment. - const SkRect& revalidate(InvalidationController*, const SkMatrix&); - -protected: - enum InvalTraits { - // Nodes with this trait never generate direct damage -- instead, - // the damage bubbles up to ancestors. - kBubbleDamage_Trait = 1 << 0, - }; - - explicit Node(uint32_t invalTraits); - ~Node() override; - - const SkRect& bounds() const { - SkASSERT(!this->hasInval()); - return fBounds; - } - - // Tag this node for invalidation and optional damage. - void invalidate(bool damage = true); - bool hasInval() const { return fFlags & kInvalidated_Flag; } - - // Dispatched on revalidation. Subclasses are expected to recompute/cache their properties - // and return their bounding box in local coordinates. - virtual SkRect onRevalidate(InvalidationController*, const SkMatrix& ctm) = 0; - - // Register/unregister |this| to receive invalidation events from a descendant. - void observeInval(const sk_sp&); - void unobserveInval(const sk_sp&); - -private: - enum Flags { - kInvalidated_Flag = 1 << 0, // the node or its descendants require revalidation - kDamage_Flag = 1 << 1, // the node contributes damage during revalidation - kObserverArray_Flag = 1 << 2, // the node has more than one inval observer - kInTraversal_Flag = 1 << 3, // the node is part of a traversal (cycle detection) - }; - - template - void forEachInvalObserver(Func&&) const; - - class ScopedFlag; - - union { - Node* fInvalObserver; - SkTDArray* fInvalObserverArray; - }; - SkRect fBounds; - const uint32_t fInvalTraits : 16; - uint32_t fFlags : 16; - - typedef SkRefCnt INHERITED; -}; - -// Helper for defining attribute getters/setters in subclasses. -#define SG_ATTRIBUTE(attr_name, attr_type, attr_container) \ - const attr_type& get##attr_name() const { return attr_container; } \ - void set##attr_name(const attr_type& v) { \ - if (attr_container == v) return; \ - attr_container = v; \ - this->invalidate(); \ - } - -#define SG_MAPPED_ATTRIBUTE(attr_name, attr_type, attr_container) \ - attr_type get##attr_name() const { return attr_container.get##attr_name(); } \ - void set##attr_name(const attr_type& v) { \ - if (attr_container.get##attr_name() == v) return; \ - attr_container.set##attr_name(v); \ - this->invalidate(); \ - } - -} // namespace sksg - -#endif // SkSGNode_DEFINED diff --git a/experimental/sksg/SkSGPaintNode.cpp b/experimental/sksg/SkSGPaintNode.cpp deleted file mode 100644 index 9220b0f0af..0000000000 --- a/experimental/sksg/SkSGPaintNode.cpp +++ /dev/null @@ -1,41 +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 "SkSGPaintNode.h" - -namespace sksg { - -// Paint nodes don't generate damage on their own, but via their aggregation ancestor Draw nodes. -PaintNode::PaintNode() : INHERITED(kBubbleDamage_Trait) {} - -const SkPaint& PaintNode::makePaint() { - SkASSERT(!this->hasInval()); - - return fPaint; -} - -SkRect PaintNode::onRevalidate(InvalidationController*, const SkMatrix&) { - SkASSERT(this->hasInval()); - - fPaint.reset(); - fPaint.setAntiAlias(fAntiAlias); - fPaint.setBlendMode(fBlendMode); - fPaint.setStyle(fStyle); - fPaint.setStrokeWidth(fStrokeWidth); - fPaint.setStrokeMiter(fStrokeMiter); - fPaint.setStrokeJoin(fStrokeJoin); - fPaint.setStrokeCap(fStrokeCap); - - this->onApplyToPaint(&fPaint); - - // Compose opacity on top of the subclass value. - fPaint.setAlpha(SkScalarRoundToInt(fPaint.getAlpha() * SkTPin(fOpacity, 0, 1))); - - return SkRect::MakeEmpty(); -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGPaintNode.h b/experimental/sksg/SkSGPaintNode.h deleted file mode 100644 index 5c9563b3a6..0000000000 --- a/experimental/sksg/SkSGPaintNode.h +++ /dev/null @@ -1,60 +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. - */ - -#ifndef SkSGPaintNode_DEFINED -#define SkSGPaintNode_DEFINED - -#include "SkSGNode.h" - -#include "SkPaint.h" - -namespace sksg { - -/** - * Base class for nodes which provide a 'paint' (as opposed to geometry) for - * drawing (e.g. colors, gradients, patterns). - * - * Roughly equivalent to Skia's SkPaint. - */ -class PaintNode : public Node { -public: - const SkPaint& makePaint(); - - SG_ATTRIBUTE(AntiAlias , bool , fAntiAlias ) - SG_ATTRIBUTE(Opacity , SkScalar , fOpacity ) - SG_ATTRIBUTE(BlendMode , SkBlendMode , fBlendMode ) - SG_ATTRIBUTE(StrokeWidth, SkScalar , fStrokeWidth) - SG_ATTRIBUTE(StrokeMiter, SkScalar , fStrokeMiter) - SG_ATTRIBUTE(Style , SkPaint::Style, fStyle ) - SG_ATTRIBUTE(StrokeJoin , SkPaint::Join , fStrokeJoin ) - SG_ATTRIBUTE(StrokeCap , SkPaint::Cap , fStrokeCap ) - -protected: - PaintNode(); - - virtual void onApplyToPaint(SkPaint*) const = 0; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) final; - -private: - SkPaint fPaint; - - SkScalar fOpacity = 1, - fStrokeWidth = 1, - fStrokeMiter = 4; - bool fAntiAlias = false; - SkBlendMode fBlendMode = SkBlendMode::kSrcOver; - SkPaint::Style fStyle = SkPaint::kFill_Style; - SkPaint::Join fStrokeJoin = SkPaint::kMiter_Join; - SkPaint::Cap fStrokeCap = SkPaint::kButt_Cap; - - typedef Node INHERITED; -}; - -} // namespace sksg - -#endif // SkSGGeometryNode_DEFINED diff --git a/experimental/sksg/SkSGRenderNode.cpp b/experimental/sksg/SkSGRenderNode.cpp deleted file mode 100644 index e952c69f20..0000000000 --- a/experimental/sksg/SkSGRenderNode.cpp +++ /dev/null @@ -1,19 +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 "SkSGRenderNode.h" - -namespace sksg { - -RenderNode::RenderNode() : INHERITED(0) {} - -void RenderNode::render(SkCanvas* canvas) const { - SkASSERT(!this->hasInval()); - this->onRender(canvas); -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGRenderNode.h b/experimental/sksg/SkSGRenderNode.h deleted file mode 100644 index 4ca1aec616..0000000000 --- a/experimental/sksg/SkSGRenderNode.h +++ /dev/null @@ -1,36 +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. - */ - -#ifndef SkSGRenderNode_DEFINED -#define SkSGRenderNode_DEFINED - -#include "SkSGNode.h" - -class SkCanvas; - -namespace sksg { - -/** - * Base class for nodes which can render to a canvas. - */ -class RenderNode : public Node { -public: - // Render the node and its descendants to the canvas. - void render(SkCanvas*) const; - -protected: - RenderNode(); - - virtual void onRender(SkCanvas*) const = 0; - -private: - typedef Node INHERITED; -}; - -} // namespace sksg - -#endif // SkSGRenderNode_DEFINED diff --git a/experimental/sksg/SkSGScene.cpp b/experimental/sksg/SkSGScene.cpp deleted file mode 100644 index 8d7e0b369b..0000000000 --- a/experimental/sksg/SkSGScene.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGScene.h" - -#include "SkCanvas.h" -#include "SkMatrix.h" -#include "SkPaint.h" -#include "SkSGInvalidationController.h" -#include "SkSGRenderNode.h" - -namespace sksg { - -Animator::Animator() = default; -Animator::~Animator() = default; - -void Animator::tick(float t) { - this->onTick(t); -} - -GroupAnimator::GroupAnimator(AnimatorList&& animators) - : fAnimators(std::move(animators)) {} - -void GroupAnimator::onTick(float t) { - for (const auto& a : fAnimators) { - a->tick(t); - } -} - -std::unique_ptr Scene::Make(sk_sp root, AnimatorList&& anims) { - return root ? std::unique_ptr(new Scene(std::move(root), std::move(anims))) : nullptr; -} - -Scene::Scene(sk_sp root, AnimatorList&& animators) - : fRoot(std::move(root)) - , fAnimators(std::move(animators)) {} - -Scene::~Scene() = default; - -void Scene::render(SkCanvas* canvas) const { - InvalidationController ic; - fRoot->revalidate(&ic, SkMatrix::I()); - fRoot->render(canvas); - - if (fShowInval) { - SkPaint fill, stroke; - fill.setAntiAlias(true); - fill.setColor(0x40ff0000); - stroke.setAntiAlias(true); - stroke.setColor(0xffff0000); - stroke.setStyle(SkPaint::kStroke_Style); - - for (const auto& r : ic) { - canvas->drawRect(r, fill); - canvas->drawRect(r, stroke); - } - } -} - -void Scene::animate(float t) { - for (const auto& anim : fAnimators) { - anim->tick(t); - } -} - -} // namespace sksg diff --git a/experimental/sksg/SkSGScene.h b/experimental/sksg/SkSGScene.h deleted file mode 100644 index 2081c1d747..0000000000 --- a/experimental/sksg/SkSGScene.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGScene_DEFINED -#define SkSGScene_DEFINED - -#include "SkRefCnt.h" -#include "SkTypes.h" - -#include -#include - -class SkCanvas; - -namespace sksg { - -class RenderNode; - -/** - * Base class for animators. - * - */ -class Animator : public SkNoncopyable { -public: - virtual ~Animator(); - - void tick(float t); - -protected: - Animator(); - - virtual void onTick(float t) = 0; - -private: - using INHERITED = SkNoncopyable; -}; - -using AnimatorList = std::vector>; - -class GroupAnimator : public Animator { -protected: - explicit GroupAnimator(AnimatorList&&); - - void onTick(float t) override; - -private: - const AnimatorList fAnimators; - - using INHERITED = Animator; -}; - -/** - * Holds a scene root and a list of animators. - * - * Provides high-level mehods for driving rendering and animations. - * - */ -class Scene final : SkNoncopyable { -public: - static std::unique_ptr Make(sk_sp root, AnimatorList&& animators); - ~Scene(); - - void render(SkCanvas*) const; - void animate(float t); - - void setShowInval(bool show) { fShowInval = show; } - -private: - Scene(sk_sp root, AnimatorList&& animators); - - const sk_sp fRoot; - const AnimatorList fAnimators; - - bool fShowInval = false; - - using INHERITED = SkNoncopyable; -}; - -} // namespace sksg - -#endif // SkSGScene_DEFINED diff --git a/experimental/sksg/effects/SkSGClipEffect.cpp b/experimental/sksg/effects/SkSGClipEffect.cpp deleted file mode 100644 index b2d68fc8cf..0000000000 --- a/experimental/sksg/effects/SkSGClipEffect.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGClipEffect.h" - -#include "SkCanvas.h" -#include "SkPath.h" -#include "SkSGGeometryNode.h" - -namespace sksg { - -ClipEffect::ClipEffect(sk_sp child, sk_sp clip, bool aa) - : INHERITED(std::move(child)) - , fClipNode(std::move(clip)) - , fAntiAlias(aa) { - this->observeInval(fClipNode); -} - -ClipEffect::~ClipEffect() { - this->unobserveInval(fClipNode); -} - -void ClipEffect::onRender(SkCanvas* canvas) const { - if (this->bounds().isEmpty()) - return; - - SkAutoCanvasRestore acr(canvas, !fNoop); - if (!fNoop) { - fClipNode->clip(canvas, fAntiAlias); - } - - this->INHERITED::onRender(canvas); -} - -SkRect ClipEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - const auto clipBounds = fClipNode->revalidate(ic, ctm); - auto childBounds = this->INHERITED::onRevalidate(ic, ctm); - - fNoop = fClipNode->asPath().conservativelyContainsRect(childBounds); - - return childBounds.intersect(clipBounds) ? childBounds : SkRect::MakeEmpty(); -} - -} // namespace sksg diff --git a/experimental/sksg/effects/SkSGClipEffect.h b/experimental/sksg/effects/SkSGClipEffect.h deleted file mode 100644 index 674edb2b5c..0000000000 --- a/experimental/sksg/effects/SkSGClipEffect.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGClipEffect_DEFINED -#define SkSGClipEffect_DEFINED - -#include "SkSGEffectNode.h" - -namespace sksg { - -class GeometryNode; - -/** - * Concrete Effect node, applying a clip to its descendants. - * - */ -class ClipEffect final : public EffectNode { -public: - static sk_sp Make(sk_sp child, sk_sp clip, - bool aa = false) { - return (child && clip) - ? sk_sp(new ClipEffect(std::move(child), std::move(clip), aa)) - : nullptr; - } - - ~ClipEffect() override; - -protected: - ClipEffect(sk_sp, sk_sp, bool aa); - - void onRender(SkCanvas*) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - const sk_sp fClipNode; - const bool fAntiAlias; - - bool fNoop = false; - - typedef EffectNode INHERITED; -}; - -} // namespace sksg - -#endif // SkSGClipEffect_DEFINED diff --git a/experimental/sksg/effects/SkSGMaskEffect.cpp b/experimental/sksg/effects/SkSGMaskEffect.cpp deleted file mode 100644 index 16e4c0dd8d..0000000000 --- a/experimental/sksg/effects/SkSGMaskEffect.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGMaskEffect.h" - -#include "SkCanvas.h" - -namespace sksg { - -MaskEffect::MaskEffect(sk_sp child, sk_sp mask, Mode mode) - : INHERITED(std::move(child)) - , fMaskNode(std::move(mask)) - , fMaskMode(mode) { - this->observeInval(fMaskNode); -} - -MaskEffect::~MaskEffect() { - this->unobserveInval(fMaskNode); -} - -void MaskEffect::onRender(SkCanvas* canvas) const { - if (this->bounds().isEmpty()) - return; - - SkAutoCanvasRestore acr(canvas, false); - - canvas->saveLayer(this->bounds(), nullptr); - fMaskNode->render(canvas); - - - SkPaint p; - p.setBlendMode(fMaskMode == Mode::kNormal ? SkBlendMode::kSrcIn : SkBlendMode::kSrcOut); - canvas->saveLayer(this->bounds(), &p); - - this->INHERITED::onRender(canvas); -} - - -SkRect MaskEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - const auto maskBounds = fMaskNode->revalidate(ic, ctm); - auto childBounds = this->INHERITED::onRevalidate(ic, ctm); - - return (fMaskMode == Mode::kInvert || childBounds.intersect(maskBounds)) - ? childBounds - : SkRect::MakeEmpty(); -} - -} // namespace sksg diff --git a/experimental/sksg/effects/SkSGMaskEffect.h b/experimental/sksg/effects/SkSGMaskEffect.h deleted file mode 100644 index c4fd0120e5..0000000000 --- a/experimental/sksg/effects/SkSGMaskEffect.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGMaskEffect_DEFINED -#define SkSGMaskEffect_DEFINED - -#include "SkSGEffectNode.h" - -namespace sksg { - -/** - * Concrete Effect node, applying a mask to its descendants. - * - */ -class MaskEffect final : public EffectNode { -public: - enum class Mode { - kNormal, - kInvert - }; - - static sk_sp Make(sk_sp child, sk_sp mask, - Mode mode = Mode::kNormal) { - return (child && mask) - ? sk_sp(new MaskEffect(std::move(child), std::move(mask), mode)) - : nullptr; - } - - ~MaskEffect() override; - -protected: - MaskEffect(sk_sp, sk_sp mask, Mode); - - void onRender(SkCanvas*) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - const sk_sp fMaskNode; - const Mode fMaskMode; - - typedef EffectNode INHERITED; -}; - -} // namespace sksg - -#endif // SkSGMaskEffect_DEFINED diff --git a/experimental/sksg/effects/SkSGOpacityEffect.cpp b/experimental/sksg/effects/SkSGOpacityEffect.cpp deleted file mode 100644 index b1ff10d217..0000000000 --- a/experimental/sksg/effects/SkSGOpacityEffect.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGOpacityEffect.h" - -#include "SkCanvas.h" - -#include - -namespace sksg { - -OpacityEffect::OpacityEffect(sk_sp child, float opacity) - : INHERITED(std::move(child)) - , fOpacity(opacity) {} - -void OpacityEffect::onRender(SkCanvas* canvas) const { - // opacity <= 0 disables rendering - if (fOpacity <= 0) - return; - - // TODO: we could avoid savelayer if there is no more than one drawing primitive - // in the sub-DAG. - SkAutoCanvasRestore acr(canvas, false); - if (fOpacity < 1) { - canvas->saveLayerAlpha(&this->bounds(), roundf(fOpacity * 255)); - } - - this->INHERITED::onRender(canvas); -} - -SkRect OpacityEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - // opacity <= 0 disables rendering AND revalidation for the sub-DAG - return fOpacity > 0 ? this->INHERITED::onRevalidate(ic, ctm) : SkRect::MakeEmpty(); -} - -} // namespace sksg diff --git a/experimental/sksg/effects/SkSGOpacityEffect.h b/experimental/sksg/effects/SkSGOpacityEffect.h deleted file mode 100644 index d906775b44..0000000000 --- a/experimental/sksg/effects/SkSGOpacityEffect.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGOpacityEffect_DEFINED -#define SkSGOpacityEffect_DEFINED - -#include "SkSGEffectNode.h" - -namespace sksg { - -/** - * Concrete Effect node, applying opacity to its descendants. - * - */ -class OpacityEffect final : public EffectNode { -public: - static sk_sp Make(sk_sp child, float opacity = 1) { - return child ? sk_sp(new OpacityEffect(std::move(child), opacity)) : nullptr; - } - - SG_ATTRIBUTE(Opacity, float, fOpacity) - -protected: - OpacityEffect(sk_sp, float); - - void onRender(SkCanvas*) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - float fOpacity; - - typedef EffectNode INHERITED; -}; - -} // namespace sksg - -#endif // SkSGOpacityEffect_DEFINED diff --git a/experimental/sksg/effects/SkSGTransform.cpp b/experimental/sksg/effects/SkSGTransform.cpp deleted file mode 100644 index 6a985a971e..0000000000 --- a/experimental/sksg/effects/SkSGTransform.cpp +++ /dev/null @@ -1,70 +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 "SkSGTransform.h" - -#include "SkCanvas.h" - -namespace sksg { -// Matrix nodes don't generate damage on their own, but via aggregation ancestor Transform nodes. -Matrix::Matrix(const SkMatrix& m, sk_sp parent) - : INHERITED(kBubbleDamage_Trait) - , fParent(std::move(parent)) - , fLocalMatrix(m) { - if (fParent) { - this->observeInval(fParent); - } -} - -Matrix::~Matrix() { - if (fParent) { - this->unobserveInval(fParent); - } -} - -SkRect Matrix::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - fTotalMatrix = fLocalMatrix; - - if (fParent) { - fParent->revalidate(ic, ctm); - fTotalMatrix.postConcat(fParent->getTotalMatrix()); - } - - return SkRect::MakeEmpty(); -} - -Transform::Transform(sk_sp child, sk_sp matrix) - : INHERITED(std::move(child)) - , fMatrix(std::move(matrix)) { - this->observeInval(fMatrix); -} - -Transform::~Transform() { - this->unobserveInval(fMatrix); -} - -void Transform::onRender(SkCanvas* canvas) const { - const auto& m = fMatrix->getTotalMatrix(); - SkAutoCanvasRestore acr(canvas, !m.isIdentity()); - canvas->concat(m); - this->INHERITED::onRender(canvas); -} - -SkRect Transform::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - // We don't care about matrix reval results. - fMatrix->revalidate(ic, ctm); - - const auto& m = fMatrix->getTotalMatrix(); - auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m)); - m.mapRect(&bounds); - - return bounds; -} - -} // namespace sksg diff --git a/experimental/sksg/effects/SkSGTransform.h b/experimental/sksg/effects/SkSGTransform.h deleted file mode 100644 index 6b7fbc010b..0000000000 --- a/experimental/sksg/effects/SkSGTransform.h +++ /dev/null @@ -1,81 +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. - */ - -#ifndef SkSGTransform_DEFINED -#define SkSGTransform_DEFINED - -#include "SkSGEffectNode.h" - -#include "SkMatrix.h" - -namespace sksg { - -/** - * Concrete node, wrapping an SkMatrix, with an optional parent Matrix (to allow chaining): - * - * M' = parent x M - */ -class Matrix : public Node { -public: - static sk_sp Make(const SkMatrix& m, sk_sp parent = nullptr) { - return sk_sp(new Matrix(m, std::move(parent))); - } - - ~Matrix() override; - - SG_ATTRIBUTE(Matrix, SkMatrix, fLocalMatrix) - - const SkMatrix& getTotalMatrix() const { return fTotalMatrix; } - -protected: - Matrix(const SkMatrix&, sk_sp); - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - sk_sp fParent; - SkMatrix fLocalMatrix, - fTotalMatrix; // cached during revalidation - - typedef Node INHERITED; -}; - -/** - * Concrete Effect node, binding a Matrix to a RenderNode. - */ -class Transform final : public EffectNode { -public: - static sk_sp Make(sk_sp child, sk_sp matrix) { - return child && matrix - ? sk_sp(new Transform(std::move(child), std::move(matrix))) - : nullptr; - } - - static sk_sp Make(sk_sp child, const SkMatrix& m) { - return Make(std::move(child), Matrix::Make(m)); - } - - ~Transform() override; - - const sk_sp& getMatrix() const { return fMatrix; } - -protected: - void onRender(SkCanvas*) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - -private: - Transform(sk_sp, sk_sp); - - const sk_sp fMatrix; - - typedef EffectNode INHERITED; -}; - -} // namespace sksg - -#endif // SkSGTransform_DEFINED diff --git a/experimental/sksg/geometry/SkSGGeometryTransform.cpp b/experimental/sksg/geometry/SkSGGeometryTransform.cpp deleted file mode 100644 index 5b366b9620..0000000000 --- a/experimental/sksg/geometry/SkSGGeometryTransform.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGGeometryTransform.h" - -#include "SkCanvas.h" - -namespace sksg { - -GeometryTransform::GeometryTransform(sk_sp child, sk_sp matrix) - : fChild(std::move(child)) - , fMatrix(std::move(matrix)) { - this->observeInval(fChild); - this->observeInval(fMatrix); -} - -GeometryTransform::~GeometryTransform() { - this->unobserveInval(fChild); - this->unobserveInval(fMatrix); -} - -void GeometryTransform::onClip(SkCanvas* canvas, bool antiAlias) const { - canvas->clipPath(fTransformed, SkClipOp::kIntersect, antiAlias); -} - -void GeometryTransform::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - canvas->drawPath(fTransformed, paint); -} - -SkRect GeometryTransform::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - // We don't care about matrix reval results. - fMatrix->revalidate(ic, ctm); - const auto& m = fMatrix->getMatrix(); - - auto bounds = fChild->revalidate(ic, ctm); - fTransformed = fChild->asPath(); - fTransformed.transform(m); - - m.mapRect(&bounds); - return bounds; -} - -SkPath GeometryTransform::onAsPath() const { - return fTransformed; -} - -} // namespace sksg diff --git a/experimental/sksg/geometry/SkSGGeometryTransform.h b/experimental/sksg/geometry/SkSGGeometryTransform.h deleted file mode 100644 index fe7e026031..0000000000 --- a/experimental/sksg/geometry/SkSGGeometryTransform.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGGeometryTransform_DEFINED -#define SkSGGeometryTransform_DEFINED - -#include "SkSGGeometryNode.h" - -#include "SkPath.h" -#include "SkSGTransform.h" - -class SkMatrix; - -namespace sksg { - -/** - * Concrete Effect node, binding a Matrix to a GeometryNode. - */ -class GeometryTransform final : public GeometryNode { -public: - static sk_sp Make(sk_sp child, sk_sp matrix) { - return child && matrix - ? sk_sp(new GeometryTransform(std::move(child), std::move(matrix))) - : nullptr; - } - - static sk_sp Make(sk_sp child, const SkMatrix& m) { - return Make(std::move(child), Matrix::Make(m)); - } - - ~GeometryTransform() override; - - const sk_sp& getMatrix() const { return fMatrix; } - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - GeometryTransform(sk_sp, sk_sp); - - const sk_sp fChild; - const sk_sp fMatrix; - SkPath fTransformed; - - using INHERITED = GeometryNode; -}; - -} - -#endif // SkSGGeometryTransform_DEFINED diff --git a/experimental/sksg/geometry/SkSGMerge.cpp b/experimental/sksg/geometry/SkSGMerge.cpp deleted file mode 100644 index be1ff4123a..0000000000 --- a/experimental/sksg/geometry/SkSGMerge.cpp +++ /dev/null @@ -1,84 +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 "SkSGMerge.h" - -#include "SkCanvas.h" -#include "SkPathOps.h" - -namespace sksg { - -Merge::Merge(std::vector>&& geos, Mode mode) - : fGeos(std::move(geos)) - , fMode(mode) { - for (const auto& geo : fGeos) { - this->observeInval(geo); - } -} - -Merge::~Merge() { - for (const auto& geo : fGeos) { - this->unobserveInval(geo); - } -} - -void Merge::onClip(SkCanvas* canvas, bool antiAlias) const { - canvas->clipPath(fMerged, SkClipOp::kIntersect, antiAlias); -} - -void Merge::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - canvas->drawPath(fMerged, paint); -} - -SkPath Merge::onAsPath() const { - return fMerged; -} - -static SkPathOp mode_to_op(Merge::Mode mode) { - switch (mode) { - case Merge::Mode::kUnion: - return kUnion_SkPathOp; - case Merge::Mode::kIntersect: - return kIntersect_SkPathOp; - case Merge::Mode::kDifference: - return kDifference_SkPathOp; - case Merge::Mode::kReverseDifference: - return kReverseDifference_SkPathOp; - case Merge::Mode::kXOR: - return kXOR_SkPathOp; - default: - break; - } - - return kUnion_SkPathOp; -} - -SkRect Merge::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - const auto op = mode_to_op(fMode); - SkOpBuilder builder; - - fMerged.reset(); - - for (const auto& geo : fGeos) { - geo->revalidate(ic, ctm); - if (fMode == Mode::kMerge) { - fMerged.addPath(geo->asPath()); - } else { - builder.add(geo->asPath(), geo == fGeos.front() ? kUnion_SkPathOp : op); - } - } - - if (fMode != Mode::kMerge) { - builder.resolve(&fMerged); - } - - return fMerged.computeTightBounds(); -} - -} // namespace sksg diff --git a/experimental/sksg/geometry/SkSGMerge.h b/experimental/sksg/geometry/SkSGMerge.h deleted file mode 100644 index 54924d6475..0000000000 --- a/experimental/sksg/geometry/SkSGMerge.h +++ /dev/null @@ -1,64 +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. - */ - -#ifndef SkSGMerge_DEFINED -#define SkSGMerge_DEFINED - -#include "SkSGGeometryNode.h" - -#include "SkPath.h" - -#include - -class SkCanvas; -class SkPaint; - -namespace sksg { - -/** - * Concrete Geometry node, combining other geometries based on Mode. - */ -class Merge final : public GeometryNode { -public: - enum class Mode { - // Append path mode. - kMerge, - - // SkPathOp ops. - kUnion, - kIntersect, - kDifference, - kReverseDifference, - kXOR, - }; - - static sk_sp Make(std::vector>&& geos, Mode mode) { - return sk_sp(new Merge(std::move(geos), mode)); - } - - ~Merge() override; - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - Merge(std::vector>&& geos, Mode); - - std::vector> fGeos; - SkPath fMerged; - Mode fMode; - - using INHERITED = GeometryNode; -}; - -} // namespace sksg - -#endif // SkSGMerge_DEFINED diff --git a/experimental/sksg/geometry/SkSGPath.cpp b/experimental/sksg/geometry/SkSGPath.cpp deleted file mode 100644 index 230442d409..0000000000 --- a/experimental/sksg/geometry/SkSGPath.cpp +++ /dev/null @@ -1,41 +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 "SkSGPath.h" - -#include "SkCanvas.h" -#include "SkPaint.h" -#include "SkRectPriv.h" - -namespace sksg { - -Path::Path(const SkPath& path) : fPath(path) {} - -void Path::onClip(SkCanvas* canvas, bool antiAlias) const { - canvas->clipPath(fPath, SkClipOp::kIntersect, antiAlias); -} - -void Path::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - canvas->drawPath(fPath, paint); -} - -SkRect Path::onRevalidate(InvalidationController*, const SkMatrix&) { - SkASSERT(this->hasInval()); - - const auto ft = fPath.getFillType(); - return (ft == SkPath::kWinding_FillType || ft == SkPath::kEvenOdd_FillType) - // "Containing" fills have finite bounds. - ? fPath.computeTightBounds() - // Inverse fills are "infinite". - : SkRectPriv::MakeLargeS32(); -} - -SkPath Path::onAsPath() const { - return fPath; -} - -} // namespace sksg diff --git a/experimental/sksg/geometry/SkSGPath.h b/experimental/sksg/geometry/SkSGPath.h deleted file mode 100644 index 1a8718868d..0000000000 --- a/experimental/sksg/geometry/SkSGPath.h +++ /dev/null @@ -1,48 +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. - */ - -#ifndef SkSGPath_DEFINED -#define SkSGPath_DEFINED - -#include "SkSGGeometryNode.h" - -#include "SkPath.h" - -class SkCanvas; -class SkPaint; - -namespace sksg { - -/** - * Concrete Geometry node, wrapping an SkPath. - */ -class Path : public GeometryNode { -public: - static sk_sp Make() { return sk_sp(new Path(SkPath())); } - static sk_sp Make(const SkPath& r) { return sk_sp(new Path(r)); } - - SG_ATTRIBUTE(Path, SkPath, fPath) - SG_MAPPED_ATTRIBUTE(FillType, SkPath::FillType, fPath) - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - explicit Path(const SkPath&); - - SkPath fPath; - - using INHERITED = GeometryNode; -}; - -} // namespace sksg - -#endif // SkSGPath_DEFINED diff --git a/experimental/sksg/geometry/SkSGPlane.cpp b/experimental/sksg/geometry/SkSGPlane.cpp deleted file mode 100644 index 806fcc7d29..0000000000 --- a/experimental/sksg/geometry/SkSGPlane.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGPlane.h" - -#include "SkCanvas.h" -#include "SkPath.h" - -namespace sksg { - -Plane::Plane() = default; - -void Plane::onClip(SkCanvas*, bool) const {} - -void Plane::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - canvas->drawPaint(paint); -} - -SkRect Plane::onRevalidate(InvalidationController*, const SkMatrix&) { - SkASSERT(this->hasInval()); - - return SkRect::MakeLTRB(SK_ScalarMin, SK_ScalarMin, SK_ScalarMax, SK_ScalarMax); -} - -SkPath Plane::onAsPath() const { - SkPath path; - path.setFillType(SkPath::kInverseWinding_FillType); - - return path; -} - -} // namespace sksg diff --git a/experimental/sksg/geometry/SkSGPlane.h b/experimental/sksg/geometry/SkSGPlane.h deleted file mode 100644 index c0a26375b2..0000000000 --- a/experimental/sksg/geometry/SkSGPlane.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGPlane_DEFINED -#define SkSGPlane_DEFINED - -#include "SkSGGeometryNode.h" - -class SkCanvas; -class SkPaint; - -namespace sksg { - -/** - * Concrete Geometry node, representing the whole canvas. - */ -class Plane final : public GeometryNode { -public: - static sk_sp Make() { return sk_sp(new Plane()); } - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - Plane(); - - using INHERITED = GeometryNode; -}; - -} // namespace sksg - -#endif // SkSGPlane_DEFINED diff --git a/experimental/sksg/geometry/SkSGRect.cpp b/experimental/sksg/geometry/SkSGRect.cpp deleted file mode 100644 index 16f0a6f1e1..0000000000 --- a/experimental/sksg/geometry/SkSGRect.cpp +++ /dev/null @@ -1,60 +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 "SkSGRect.h" - -#include "SkCanvas.h" -#include "SkPaint.h" -#include "SkPath.h" - -namespace sksg { - -Rect::Rect(const SkRect& rect) : fRect(rect) {} - -void Rect::onClip(SkCanvas* canvas, bool antiAlias) const { - canvas->clipRect(fRect, SkClipOp::kIntersect, antiAlias); -} - -void Rect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - canvas->drawRect(fRect, paint); -} - -SkRect Rect::onRevalidate(InvalidationController*, const SkMatrix&) { - SkASSERT(this->hasInval()); - - return fRect; -} - -SkPath Rect::onAsPath() const { - SkPath path; - path.addRect(fRect); - return path; -} - -RRect::RRect(const SkRRect& rr) : fRRect(rr) {} - -void RRect::onClip(SkCanvas* canvas, bool antiAlias) const { - canvas->clipRRect(fRRect, SkClipOp::kIntersect, antiAlias); -} - -void RRect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - canvas->drawRRect(fRRect, paint); -} - -SkRect RRect::onRevalidate(InvalidationController*, const SkMatrix&) { - SkASSERT(this->hasInval()); - - return fRRect.getBounds(); -} - -SkPath RRect::onAsPath() const { - SkPath path; - path.addRRect(fRRect); - return path; -} - -} // namespace sksg diff --git a/experimental/sksg/geometry/SkSGRect.h b/experimental/sksg/geometry/SkSGRect.h deleted file mode 100644 index f5fcb962c6..0000000000 --- a/experimental/sksg/geometry/SkSGRect.h +++ /dev/null @@ -1,76 +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. - */ - -#ifndef SkSGRect_DEFINED -#define SkSGRect_DEFINED - -#include "SkSGGeometryNode.h" - -#include "SkRect.h" -#include "SkRRect.h" - -class SkCanvas; -class SkPaint; - -namespace sksg { - -/** - * Concrete Geometry node, wrapping an SkRect. - */ -class Rect final : public GeometryNode { -public: - static sk_sp Make() { return sk_sp(new Rect(SkRect::MakeEmpty())); } - static sk_sp Make(const SkRect& r) { return sk_sp(new Rect(r)); } - - SG_ATTRIBUTE(L, SkScalar, fRect.fLeft ) - SG_ATTRIBUTE(T, SkScalar, fRect.fTop ) - SG_ATTRIBUTE(R, SkScalar, fRect.fRight ) - SG_ATTRIBUTE(B, SkScalar, fRect.fBottom) - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - explicit Rect(const SkRect&); - - SkRect fRect; - - using INHERITED = GeometryNode; -}; - -/** - * Concrete Geometry node, wrapping an SkRRect. - */ -class RRect final : public GeometryNode { -public: - static sk_sp Make() { return sk_sp(new RRect(SkRRect())); } - static sk_sp Make(const SkRRect& rr) { return sk_sp(new RRect(rr)); } - - SG_ATTRIBUTE(RRect, SkRRect, fRRect) - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - explicit RRect(const SkRRect&); - - SkRRect fRRect; - - using INHERITED = GeometryNode; -}; - -} // namespace sksg - -#endif // SkSGRect_DEFINED diff --git a/experimental/sksg/geometry/SkSGRoundEffect.cpp b/experimental/sksg/geometry/SkSGRoundEffect.cpp deleted file mode 100644 index 8cf9068f65..0000000000 --- a/experimental/sksg/geometry/SkSGRoundEffect.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGRoundEffect.h" - -#include "SkCanvas.h" -#include "SkCornerPathEffect.h" -#include "SkStrokeRec.h" - -namespace sksg { - -RoundEffect::RoundEffect(sk_sp child) - : fChild(std::move(child)) { - this->observeInval(fChild); -} - -RoundEffect::~RoundEffect() { - this->unobserveInval(fChild); -} - -void RoundEffect::onClip(SkCanvas* canvas, bool antiAlias) const { - canvas->clipPath(fRoundedPath, SkClipOp::kIntersect, antiAlias); -} - -void RoundEffect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - SkASSERT(!paint.getPathEffect()); - - canvas->drawPath(fRoundedPath, paint); -} - -SkPath RoundEffect::onAsPath() const { - return fRoundedPath; -} - -SkRect RoundEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - const auto childbounds = fChild->revalidate(ic, ctm); - const auto path = fChild->asPath(); - - if (auto round = SkCornerPathEffect::Make(fRadius)) { - fRoundedPath.reset(); - SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle); - SkAssertResult(round->filterPath(&fRoundedPath, path, &rec, &childbounds)); - } else { - fRoundedPath = path; - } - - return fRoundedPath.computeTightBounds(); -} - -} // namespace sksg diff --git a/experimental/sksg/geometry/SkSGRoundEffect.h b/experimental/sksg/geometry/SkSGRoundEffect.h deleted file mode 100644 index 67124ca072..0000000000 --- a/experimental/sksg/geometry/SkSGRoundEffect.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGRoundEffect_DEFINED -#define SkSGRoundEffect_DEFINED - -#include "SkSGGeometryNode.h" - -#include "SkPath.h" - -namespace sksg { - -/** - * Concrete Geometry node, applying a rounded-corner effect to its child. - */ -class RoundEffect final : public GeometryNode { -public: - static sk_sp Make(sk_sp child) { - return child ? sk_sp(new RoundEffect(std::move(child))) : nullptr; - } - - ~RoundEffect() override; - - SG_ATTRIBUTE(Radius, SkScalar, fRadius) - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - explicit RoundEffect(sk_sp); - - const sk_sp fChild; - - SkPath fRoundedPath; - SkScalar fRadius = 0; - - using INHERITED = GeometryNode; -}; - -} // namespace sksg - -#endif // SkSGRoundEffect_DEFINED diff --git a/experimental/sksg/geometry/SkSGText.cpp b/experimental/sksg/geometry/SkSGText.cpp deleted file mode 100644 index c149390023..0000000000 --- a/experimental/sksg/geometry/SkSGText.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGText.h" - -#include "SkCanvas.h" -#include "SkPaint.h" -#include "SkPath.h" -#include "SkTArray.h" -#include "SkTextBlob.h" -#include "SkTypeface.h" - -namespace sksg { - -sk_sp Text::Make(sk_sp tf, const SkString& text) { - return sk_sp(new Text(std::move(tf), text)); -} - -Text::Text(sk_sp tf, const SkString& text) - : fTypeface(std::move(tf)) - , fText(text) {} - -Text::~Text() = default; - -SkRect Text::onRevalidate(InvalidationController*, const SkMatrix&) { - // TODO: we could potentially track invals which don't require rebuilding the blob. - - SkPaint font; - font.setFlags(fFlags); - font.setTypeface(fTypeface); - font.setTextSize(fSize); - font.setTextScaleX(fScaleX); - font.setTextSkewX(fSkewX); - font.setTextAlign(fAlign); - font.setHinting(fHinting); - - // First, convert to glyphIDs. - font.setTextEncoding(SkPaint::kUTF8_TextEncoding); - SkSTArray<256, SkGlyphID, true> glyphs; - glyphs.reset(font.textToGlyphs(fText.c_str(), fText.size(), nullptr)); - SkAssertResult(font.textToGlyphs(fText.c_str(), fText.size(), glyphs.begin()) == glyphs.count()); - font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - - // Next, build the cached blob. - SkTextBlobBuilder builder; - const auto& buf = builder.allocRun(font, glyphs.count(), 0, 0, nullptr); - if (!buf.glyphs) { - fBlob.reset(); - return SkRect::MakeEmpty(); - } - - memcpy(buf.glyphs, glyphs.begin(), glyphs.count() * sizeof(SkGlyphID)); - - fBlob = builder.make(); - return fBlob - ? fBlob->bounds().makeOffset(fPosition.x(), fPosition.y()) - : SkRect::MakeEmpty(); -} - -void Text::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - canvas->drawTextBlob(fBlob, fPosition.x(), fPosition.y(), paint); -} - -SkPath Text::onAsPath() const { - // TODO - return SkPath(); -} - -void Text::onClip(SkCanvas* canvas, bool antiAlias) const { - canvas->clipPath(this->asPath(), antiAlias); -} - -} // namespace sksg diff --git a/experimental/sksg/geometry/SkSGText.h b/experimental/sksg/geometry/SkSGText.h deleted file mode 100644 index eb43337a10..0000000000 --- a/experimental/sksg/geometry/SkSGText.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGText_DEFINED -#define SkSGText_DEFINED - -#include "SkSGGeometryNode.h" - -#include "SkPaintDefaults.h" -#include "SkPoint.h" -#include "SkString.h" - -class SkCanvas; -class SkPaint; -class SkTextBlob; -class SkTypeface; - -namespace sksg { - -/** - * Concrete Geometry node, wrapping a (shaped) SkTextBlob. - */ -class Text final : public GeometryNode { -public: - static sk_sp Make(sk_sp tf, const SkString& text); - ~Text() override; - - SG_ATTRIBUTE(Text , SkString , fText ) - SG_ATTRIBUTE(Flags , uint32_t , fFlags ) - SG_ATTRIBUTE(Position, SkPoint , fPosition) - SG_ATTRIBUTE(Size , SkScalar , fSize ) - SG_ATTRIBUTE(ScaleX , SkScalar , fScaleX ) - SG_ATTRIBUTE(SkewX , SkScalar , fSkewX ) - SG_ATTRIBUTE(Align , SkPaint::Align, fAlign ) - - // TODO: add shaping functionality. - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - explicit Text(sk_sp, const SkString&); - - const sk_sp fTypeface; - SkString fText; - uint32_t fFlags = SkPaintDefaults_Flags; - SkPoint fPosition = SkPoint::Make(0, 0); - SkScalar fSize = SkPaintDefaults_TextSize; - SkScalar fScaleX = 1; - SkScalar fSkewX = 0; - SkPaint::Align fAlign = SkPaint::kLeft_Align; - SkPaint::Hinting fHinting = SkPaintDefaults_Hinting; - - sk_sp fBlob; // cached text blob - - using INHERITED = GeometryNode; -}; - -} // namespace sksg - -#endif // SkSGText_DEFINED diff --git a/experimental/sksg/geometry/SkSGTrimEffect.cpp b/experimental/sksg/geometry/SkSGTrimEffect.cpp deleted file mode 100644 index b8c59bcfe8..0000000000 --- a/experimental/sksg/geometry/SkSGTrimEffect.cpp +++ /dev/null @@ -1,56 +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 "SkSGTrimEffect.h" - -#include "SkCanvas.h" -#include "SkStrokeRec.h" -#include "SkTrimPathEffect.h" - -namespace sksg { - -TrimEffect::TrimEffect(sk_sp child) - : fChild(std::move(child)) { - this->observeInval(fChild); -} - -TrimEffect::~TrimEffect() { - this->unobserveInval(fChild); -} - -void TrimEffect::onClip(SkCanvas* canvas, bool antiAlias) const { - canvas->clipPath(fTrimmedPath, SkClipOp::kIntersect, antiAlias); -} - -void TrimEffect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { - SkASSERT(!paint.getPathEffect()); - - canvas->drawPath(fTrimmedPath, paint); -} - -SkPath TrimEffect::onAsPath() const { - return fTrimmedPath; -} - -SkRect TrimEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { - SkASSERT(this->hasInval()); - - const auto childbounds = fChild->revalidate(ic, ctm); - const auto path = fChild->asPath(); - - if (auto trim = SkTrimPathEffect::Make(fStart, fStop, fMode)) { - fTrimmedPath.reset(); - SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle); - SkAssertResult(trim->filterPath(&fTrimmedPath, path, &rec, &childbounds)); - } else { - fTrimmedPath = path; - } - - return fTrimmedPath.computeTightBounds(); -} - -} // namespace sksg diff --git a/experimental/sksg/geometry/SkSGTrimEffect.h b/experimental/sksg/geometry/SkSGTrimEffect.h deleted file mode 100644 index 18f15921e7..0000000000 --- a/experimental/sksg/geometry/SkSGTrimEffect.h +++ /dev/null @@ -1,58 +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. - */ - -#ifndef SkSGTrimEffect_DEFINED -#define SkSGTrimEffect_DEFINED - -#include "SkSGGeometryNode.h" - -#include "SkPath.h" -#include "SkTrimPathEffect.h" - -class SkCanvas; -class SkPaint; - -namespace sksg { - -/** - * Concrete Geometry node, applying a trim effect to its child. - */ -class TrimEffect final : public GeometryNode { -public: - static sk_sp Make(sk_sp child) { - return child ? sk_sp(new TrimEffect(std::move(child))) : nullptr; - } - - ~TrimEffect() override; - - SG_ATTRIBUTE(Start , SkScalar , fStart ) - SG_ATTRIBUTE(Stop , SkScalar , fStop ) - SG_ATTRIBUTE(Mode , SkTrimPathEffect::Mode, fMode ) - -protected: - void onClip(SkCanvas*, bool antiAlias) const override; - void onDraw(SkCanvas*, const SkPaint&) const override; - - SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; - SkPath onAsPath() const override; - -private: - explicit TrimEffect(sk_sp); - - const sk_sp fChild; - - SkPath fTrimmedPath; - SkScalar fStart = 0, - fStop = 1; - SkTrimPathEffect::Mode fMode = SkTrimPathEffect::Mode::kNormal; - - using INHERITED = GeometryNode; -}; - -} // namespace sksg - -#endif // SkSGTrimEffect_DEFINED diff --git a/experimental/sksg/paint/SkSGColor.cpp b/experimental/sksg/paint/SkSGColor.cpp deleted file mode 100644 index d5d4d1ce62..0000000000 --- a/experimental/sksg/paint/SkSGColor.cpp +++ /dev/null @@ -1,18 +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 "SkSGColor.h" - -namespace sksg { - -Color::Color(SkColor c) : fColor(c) {} - -void Color::onApplyToPaint(SkPaint* paint) const { - paint->setColor(fColor); -} - -} // namespace sksg diff --git a/experimental/sksg/paint/SkSGColor.h b/experimental/sksg/paint/SkSGColor.h deleted file mode 100644 index a19921cfd3..0000000000 --- a/experimental/sksg/paint/SkSGColor.h +++ /dev/null @@ -1,37 +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. - */ - -#ifndef SkSGColor_DEFINED -#define SkSGColor_DEFINED - -#include "SkSGPaintNode.h" - -#include "SkColor.h" - -namespace sksg { - -/** - * Concrete Paint node, wrapping an SkColor. - */ -class Color : public PaintNode { -public: - static sk_sp Make(SkColor c) { return sk_sp(new Color(c)); } - - SG_ATTRIBUTE(Color, SkColor, fColor) - -protected: - void onApplyToPaint(SkPaint*) const override; - -private: - explicit Color(SkColor); - - SkColor fColor; -}; - -} // namespace sksg - -#endif // SkSGColor_DEFINED diff --git a/experimental/sksg/paint/SkSGGradient.cpp b/experimental/sksg/paint/SkSGGradient.cpp deleted file mode 100644 index 98e7f395f8..0000000000 --- a/experimental/sksg/paint/SkSGGradient.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkSGGradient.h" - -#include "SkGradientShader.h" -#include "SkPaint.h" - -namespace sksg { - -void Gradient::onApplyToPaint(SkPaint* paint) const { - if (fColorStops.empty()) { - paint->setShader(nullptr); - return; - } - - std::vector colors; - std::vector positions; - colors.reserve(fColorStops.size()); - positions.reserve(fColorStops.size()); - - SkScalar position = 0; - for (const auto& stop : fColorStops) { - colors.push_back(stop.fColor); - position = SkTPin(stop.fPosition, position, 1.0f); - positions.push_back(position); - } - - // TODO: detect even stop distributions, pass null for positions. - paint->setShader(this->onMakeShader(colors, positions)); -} - -sk_sp LinearGradient::onMakeShader(const std::vector& colors, - const std::vector& positions) const { - SkASSERT(colors.size() == positions.size()); - - const SkPoint pts[] = { fStartPoint, fEndPoint }; - return SkGradientShader::MakeLinear(pts, colors.data(), positions.data(), colors.size(), - this->getTileMode()); -} - -sk_sp RadialGradient::onMakeShader(const std::vector& colors, - const std::vector& positions) const { - SkASSERT(colors.size() == positions.size()); - - return (fStartRadius <= 0 && fStartCenter == fEndCenter) - ? SkGradientShader::MakeRadial(fEndCenter, fEndRadius, - colors.data(), positions.data(), colors.size(), - this->getTileMode()) - : SkGradientShader::MakeTwoPointConical(fStartCenter, fStartRadius, - fEndCenter, fEndRadius, - colors.data(), positions.data(), colors.size(), - this->getTileMode()); -} - -} //namespace sksg diff --git a/experimental/sksg/paint/SkSGGradient.h b/experimental/sksg/paint/SkSGGradient.h deleted file mode 100644 index d69cb1495c..0000000000 --- a/experimental/sksg/paint/SkSGGradient.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkSGGradient_DEFINED -#define SkSGGradient_DEFINED - -#include "SkSGPaintNode.h" - -#include "SkColor.h" -#include "SkPoint.h" -#include "SkScalar.h" -#include "SkShader.h" - -#include - -namespace sksg { - -/** - * Gradient base class. - */ -class Gradient : public PaintNode { -public: - struct ColorStop { - SkScalar fPosition; - SkColor fColor; - - bool operator==(const ColorStop& other) const { - return fPosition == other.fPosition && fColor == other.fColor; - } - }; - - SG_ATTRIBUTE(ColorStops, std::vector, fColorStops) - SG_ATTRIBUTE(TileMode , SkShader::TileMode , fTileMode ) - -protected: - void onApplyToPaint(SkPaint*) const final; - - virtual sk_sp onMakeShader(const std::vector& colors, - const std::vector& positions) const = 0; - -protected: - Gradient() = default; - -private: - std::vector fColorStops; - SkShader::TileMode fTileMode = SkShader::kClamp_TileMode; - - using INHERITED = PaintNode; -}; - -class LinearGradient final : public Gradient { -public: - static sk_sp Make() { - return sk_sp(new LinearGradient()); - } - - SG_ATTRIBUTE(StartPoint, SkPoint, fStartPoint) - SG_ATTRIBUTE(EndPoint , SkPoint, fEndPoint ) - -protected: - sk_sp onMakeShader(const std::vector& colors, - const std::vector& positions) const override; - -private: - LinearGradient() = default; - - SkPoint fStartPoint = SkPoint::Make(0, 0), - fEndPoint = SkPoint::Make(0, 0); - - using INHERITED = Gradient; -}; - -class RadialGradient final : public Gradient { -public: - static sk_sp Make() { - return sk_sp(new RadialGradient()); - } - - SG_ATTRIBUTE(StartCenter, SkPoint , fStartCenter) - SG_ATTRIBUTE(EndCenter , SkPoint , fEndCenter ) - SG_ATTRIBUTE(StartRadius, SkScalar, fStartRadius) - SG_ATTRIBUTE(EndRadius , SkScalar, fEndRadius ) - -protected: - sk_sp onMakeShader(const std::vector& colors, - const std::vector& positions) const override; - -private: - RadialGradient() = default; - - SkPoint fStartCenter = SkPoint::Make(0, 0), - fEndCenter = SkPoint::Make(0, 0); - SkScalar fStartRadius = 0, - fEndRadius = 0; - - using INHERITED = Gradient; -}; - -} // namespace sksg - -#endif // SkSGGradient_DEFINED diff --git a/gn/samples.gni b/gn/samples.gni index 135cf78013..b5728b3bfd 100644 --- a/gn/samples.gni +++ b/gn/samples.gni @@ -88,9 +88,7 @@ samples_sources = [ "$_samplecode/SampleStrokePath.cpp", "$_samplecode/SampleStrokeRect.cpp", "$_samplecode/SampleSubpixelTranslate.cpp", - "$_samplecode/SampleSGInval.cpp", "$_samplecode/SampleSVGFile.cpp", - "$_samplecode/SampleSVGPong.cpp", "$_samplecode/SampleText.cpp", "$_samplecode/SampleTextAlpha.cpp", "$_samplecode/SampleTextBox.cpp", diff --git a/gn/tests.gni b/gn/tests.gni index bbab21e76a..a40ce68bdb 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -205,7 +205,6 @@ tests_sources = [ "$_tests/ScaleToSidesTest.cpp", "$_tests/SerializationTest.cpp", "$_tests/SerialProcsTest.cpp", - "$_tests/SGTest.cpp", "$_tests/ShaderOpacityTest.cpp", "$_tests/ShaderTest.cpp", "$_tests/ShadowTest.cpp", diff --git a/modules/sksg/BUILD.gn b/modules/sksg/BUILD.gn new file mode 100644 index 0000000000..2809cf1876 --- /dev/null +++ b/modules/sksg/BUILD.gn @@ -0,0 +1,90 @@ +# Copyright 2018 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +declare_args() { + skia_enable_sksg = true +} + +config("public_config") { + if (skia_enable_sksg) { + defines = [ "SK_HAS_SKSG" ] + include_dirs = [ "include" ] + } +} + +source_set("sksg") { + if (skia_enable_sksg) { + public_configs = [ ":public_config" ] + sources = [ + "src/SkSGClipEffect.cpp", + "src/SkSGColor.cpp", + "src/SkSGDraw.cpp", + "src/SkSGEffectNode.cpp", + "src/SkSGGeometryNode.cpp", + "src/SkSGGeometryTransform.cpp", + "src/SkSGGradient.cpp", + "src/SkSGGroup.cpp", + "src/SkSGImage.cpp", + "src/SkSGInvalidationController.cpp", + "src/SkSGMaskEffect.cpp", + "src/SkSGMerge.cpp", + "src/SkSGNode.cpp", + "src/SkSGOpacityEffect.cpp", + "src/SkSGPaintNode.cpp", + "src/SkSGPath.cpp", + "src/SkSGPlane.cpp", + "src/SkSGRect.cpp", + "src/SkSGRenderNode.cpp", + "src/SkSGRoundEffect.cpp", + "src/SkSGScene.cpp", + "src/SkSGText.cpp", + "src/SkSGTransform.cpp", + "src/SkSGTrimEffect.cpp", + ] + configs += [ "../../:skia_private" ] + deps = [ + "../..:skia", + ] + } +} + +source_set("tests") { + if (skia_enable_sksg) { + testonly = true + + configs += [ + "../..:skia_private", + "../..:tests_config", # TODO: refactor to make this nicer + ] + sources = [ + "tests/SGTest.cpp", + ] + deps = [ + ":sksg", + "../..:gpu_tool_utils", # TODO: refactor to make this nicer + "../..:skia", + ] + } +} + +source_set("samples") { + if (skia_enable_sksg) { + testonly = true + + configs += [ + "../..:skia_private", + "../..:samples_config", # TODO: refactor to make this nicer + ] + sources = [ + "samples/SampleSVGPong.cpp", + ] + deps = [ + ":sksg", + "../..:gm", # TODO: refactor to make this nicer + "../..:skia", + "../..:views", # TODO: refactor to make this nicer + ] + } +} diff --git a/modules/sksg/include/SkSGClipEffect.h b/modules/sksg/include/SkSGClipEffect.h new file mode 100644 index 0000000000..674edb2b5c --- /dev/null +++ b/modules/sksg/include/SkSGClipEffect.h @@ -0,0 +1,50 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGClipEffect_DEFINED +#define SkSGClipEffect_DEFINED + +#include "SkSGEffectNode.h" + +namespace sksg { + +class GeometryNode; + +/** + * Concrete Effect node, applying a clip to its descendants. + * + */ +class ClipEffect final : public EffectNode { +public: + static sk_sp Make(sk_sp child, sk_sp clip, + bool aa = false) { + return (child && clip) + ? sk_sp(new ClipEffect(std::move(child), std::move(clip), aa)) + : nullptr; + } + + ~ClipEffect() override; + +protected: + ClipEffect(sk_sp, sk_sp, bool aa); + + void onRender(SkCanvas*) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + const sk_sp fClipNode; + const bool fAntiAlias; + + bool fNoop = false; + + typedef EffectNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGClipEffect_DEFINED diff --git a/modules/sksg/include/SkSGColor.h b/modules/sksg/include/SkSGColor.h new file mode 100644 index 0000000000..a19921cfd3 --- /dev/null +++ b/modules/sksg/include/SkSGColor.h @@ -0,0 +1,37 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGColor_DEFINED +#define SkSGColor_DEFINED + +#include "SkSGPaintNode.h" + +#include "SkColor.h" + +namespace sksg { + +/** + * Concrete Paint node, wrapping an SkColor. + */ +class Color : public PaintNode { +public: + static sk_sp Make(SkColor c) { return sk_sp(new Color(c)); } + + SG_ATTRIBUTE(Color, SkColor, fColor) + +protected: + void onApplyToPaint(SkPaint*) const override; + +private: + explicit Color(SkColor); + + SkColor fColor; +}; + +} // namespace sksg + +#endif // SkSGColor_DEFINED diff --git a/modules/sksg/include/SkSGDraw.h b/modules/sksg/include/SkSGDraw.h new file mode 100644 index 0000000000..20ead3d5f6 --- /dev/null +++ b/modules/sksg/include/SkSGDraw.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGDraw_DEFINED +#define SkSGDraw_DEFINED + +#include "SkSGRenderNode.h" + +namespace sksg { + +class GeometryNode; +class PaintNode; + +/** + * Concrete rendering node. + * + * Wraps and draws a [geometry, paint] tuple. + * + * Think Skia SkCanvas::drawFoo(foo, paint) calls. + */ +class Draw : public RenderNode { +public: + static sk_sp Make(sk_sp geo, sk_sp paint) { + return (geo && paint) ? sk_sp(new Draw(std::move(geo), std::move(paint))) : nullptr; + } + +protected: + Draw(sk_sp, sk_sp paint); + ~Draw() override; + + void onRender(SkCanvas*) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + sk_sp fGeometry; + sk_sp fPaint; + + typedef RenderNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGDraw_DEFINED diff --git a/modules/sksg/include/SkSGEffectNode.h b/modules/sksg/include/SkSGEffectNode.h new file mode 100644 index 0000000000..ab0968e96c --- /dev/null +++ b/modules/sksg/include/SkSGEffectNode.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGEffectNode_DEFINED +#define SkSGEffectNode_DEFINED + +#include "SkSGRenderNode.h" + +namespace sksg { + +/** + * Base class for nodes which apply some transformation when rendering + * their descendants. + * + * This includes transforms, clipping, filters, etc. + */ +class EffectNode : public RenderNode { +protected: + explicit EffectNode(sk_sp); + ~EffectNode() override; + + void onRender(SkCanvas*) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + sk_sp fChild; + + typedef RenderNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGEffectNode_DEFINED diff --git a/modules/sksg/include/SkSGGeometryNode.h b/modules/sksg/include/SkSGGeometryNode.h new file mode 100644 index 0000000000..7ce3aa9b79 --- /dev/null +++ b/modules/sksg/include/SkSGGeometryNode.h @@ -0,0 +1,49 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGGeometryNode_DEFINED +#define SkSGGeometryNode_DEFINED + +#include "SkSGNode.h" + +class SkCanvas; +class SkPaint; +class SkPath; + +namespace sksg { + +/** + * Base class for nodes which provide 'geometry' (as opposed to paint) + * for drawing. + * + * Think SkRect, SkPath, etc. + */ +class GeometryNode : public Node { +public: + void clip(SkCanvas*, bool antiAlias) const; + void draw(SkCanvas*, const SkPaint&) const; + + SkPath asPath() const; + +protected: + GeometryNode(); + + virtual void onClip(SkCanvas*, bool antiAlias) const = 0; + + virtual void onDraw(SkCanvas*, const SkPaint&) const = 0; + + virtual SkPath onAsPath() const = 0; + +private: + friend class Draw; // wants to know the cached bounds. + + typedef Node INHERITED; +}; + +} // namespace sksg + +#endif // SkSGGeometryNode_DEFINED diff --git a/modules/sksg/include/SkSGGeometryTransform.h b/modules/sksg/include/SkSGGeometryTransform.h new file mode 100644 index 0000000000..fe7e026031 --- /dev/null +++ b/modules/sksg/include/SkSGGeometryTransform.h @@ -0,0 +1,58 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGGeometryTransform_DEFINED +#define SkSGGeometryTransform_DEFINED + +#include "SkSGGeometryNode.h" + +#include "SkPath.h" +#include "SkSGTransform.h" + +class SkMatrix; + +namespace sksg { + +/** + * Concrete Effect node, binding a Matrix to a GeometryNode. + */ +class GeometryTransform final : public GeometryNode { +public: + static sk_sp Make(sk_sp child, sk_sp matrix) { + return child && matrix + ? sk_sp(new GeometryTransform(std::move(child), std::move(matrix))) + : nullptr; + } + + static sk_sp Make(sk_sp child, const SkMatrix& m) { + return Make(std::move(child), Matrix::Make(m)); + } + + ~GeometryTransform() override; + + const sk_sp& getMatrix() const { return fMatrix; } + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + GeometryTransform(sk_sp, sk_sp); + + const sk_sp fChild; + const sk_sp fMatrix; + SkPath fTransformed; + + using INHERITED = GeometryNode; +}; + +} + +#endif // SkSGGeometryTransform_DEFINED diff --git a/modules/sksg/include/SkSGGradient.h b/modules/sksg/include/SkSGGradient.h new file mode 100644 index 0000000000..d69cb1495c --- /dev/null +++ b/modules/sksg/include/SkSGGradient.h @@ -0,0 +1,105 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGGradient_DEFINED +#define SkSGGradient_DEFINED + +#include "SkSGPaintNode.h" + +#include "SkColor.h" +#include "SkPoint.h" +#include "SkScalar.h" +#include "SkShader.h" + +#include + +namespace sksg { + +/** + * Gradient base class. + */ +class Gradient : public PaintNode { +public: + struct ColorStop { + SkScalar fPosition; + SkColor fColor; + + bool operator==(const ColorStop& other) const { + return fPosition == other.fPosition && fColor == other.fColor; + } + }; + + SG_ATTRIBUTE(ColorStops, std::vector, fColorStops) + SG_ATTRIBUTE(TileMode , SkShader::TileMode , fTileMode ) + +protected: + void onApplyToPaint(SkPaint*) const final; + + virtual sk_sp onMakeShader(const std::vector& colors, + const std::vector& positions) const = 0; + +protected: + Gradient() = default; + +private: + std::vector fColorStops; + SkShader::TileMode fTileMode = SkShader::kClamp_TileMode; + + using INHERITED = PaintNode; +}; + +class LinearGradient final : public Gradient { +public: + static sk_sp Make() { + return sk_sp(new LinearGradient()); + } + + SG_ATTRIBUTE(StartPoint, SkPoint, fStartPoint) + SG_ATTRIBUTE(EndPoint , SkPoint, fEndPoint ) + +protected: + sk_sp onMakeShader(const std::vector& colors, + const std::vector& positions) const override; + +private: + LinearGradient() = default; + + SkPoint fStartPoint = SkPoint::Make(0, 0), + fEndPoint = SkPoint::Make(0, 0); + + using INHERITED = Gradient; +}; + +class RadialGradient final : public Gradient { +public: + static sk_sp Make() { + return sk_sp(new RadialGradient()); + } + + SG_ATTRIBUTE(StartCenter, SkPoint , fStartCenter) + SG_ATTRIBUTE(EndCenter , SkPoint , fEndCenter ) + SG_ATTRIBUTE(StartRadius, SkScalar, fStartRadius) + SG_ATTRIBUTE(EndRadius , SkScalar, fEndRadius ) + +protected: + sk_sp onMakeShader(const std::vector& colors, + const std::vector& positions) const override; + +private: + RadialGradient() = default; + + SkPoint fStartCenter = SkPoint::Make(0, 0), + fEndCenter = SkPoint::Make(0, 0); + SkScalar fStartRadius = 0, + fEndRadius = 0; + + using INHERITED = Gradient; +}; + +} // namespace sksg + +#endif // SkSGGradient_DEFINED diff --git a/modules/sksg/include/SkSGGroup.h b/modules/sksg/include/SkSGGroup.h new file mode 100644 index 0000000000..482f10db8c --- /dev/null +++ b/modules/sksg/include/SkSGGroup.h @@ -0,0 +1,47 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGGroup_DEFINED +#define SkSGGroup_DEFINED + +#include "SkSGRenderNode.h" + +#include "SkTArray.h" + +namespace sksg { + +/** + * Concrete node, grouping together multiple descendants. + */ +class Group : public RenderNode { +public: + static sk_sp Make() { + return sk_sp(new Group()); + } + + void addChild(sk_sp); + void removeChild(const sk_sp&); + + size_t size() const { return SkTo(fChildren.count()); } + bool empty() const { return fChildren.empty(); } + +protected: + Group(); + ~Group() override; + + void onRender(SkCanvas*) const override; + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + SkTArray, true> fChildren; + + typedef RenderNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGGroup_DEFINED diff --git a/modules/sksg/include/SkSGImage.h b/modules/sksg/include/SkSGImage.h new file mode 100644 index 0000000000..7d17a50aaa --- /dev/null +++ b/modules/sksg/include/SkSGImage.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGImage_DEFINED +#define SkSGImage_DEFINED + +#include "SkSGRenderNode.h" + +#include "SkFilterQuality.h" + +class SkImage; + +namespace sksg { + +/** + * Concrete rendering node, wrapping an SkImage. + * + */ +class Image final : public RenderNode { +public: + static sk_sp Make(sk_sp image) { + return image ? sk_sp(new Image(std::move(image))) : nullptr; + } + + SG_ATTRIBUTE(Quality , SkFilterQuality, fQuality ) + SG_ATTRIBUTE(AntiAlias, bool , fAntiAlias) + +protected: + explicit Image(sk_sp); + + void onRender(SkCanvas*) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + const sk_sp fImage; + SkFilterQuality fQuality = kLow_SkFilterQuality; + bool fAntiAlias = true; + + typedef RenderNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGImage_DEFINED diff --git a/modules/sksg/include/SkSGInvalidationController.h b/modules/sksg/include/SkSGInvalidationController.h new file mode 100644 index 0000000000..df3857c1fe --- /dev/null +++ b/modules/sksg/include/SkSGInvalidationController.h @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGInvalidationController_DEFINED +#define SkSGInvalidationController_DEFINED + +#include "SkMatrix.h" +#include "SkTDArray.h" +#include "SkTypes.h" + +struct SkRect; + +namespace sksg { + +/** + * Receiver for invalidation events. + * + * Tracks dirty regions for repaint. + */ +class InvalidationController : public SkNoncopyable { +public: + InvalidationController(); + + void inval(const SkRect&, const SkMatrix& ctm = SkMatrix::I()); + + const SkRect& bounds() const { return fBounds; } + const SkRect* begin() const { return fRects.begin(); } + const SkRect* end() const { return fRects.end(); } + +private: + SkTDArray fRects; + SkRect fBounds; + + typedef SkNoncopyable INHERITED; +}; + +} // namespace sksg + +#endif // SkSGInvalidationController_DEFINED diff --git a/modules/sksg/include/SkSGMaskEffect.h b/modules/sksg/include/SkSGMaskEffect.h new file mode 100644 index 0000000000..c4fd0120e5 --- /dev/null +++ b/modules/sksg/include/SkSGMaskEffect.h @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGMaskEffect_DEFINED +#define SkSGMaskEffect_DEFINED + +#include "SkSGEffectNode.h" + +namespace sksg { + +/** + * Concrete Effect node, applying a mask to its descendants. + * + */ +class MaskEffect final : public EffectNode { +public: + enum class Mode { + kNormal, + kInvert + }; + + static sk_sp Make(sk_sp child, sk_sp mask, + Mode mode = Mode::kNormal) { + return (child && mask) + ? sk_sp(new MaskEffect(std::move(child), std::move(mask), mode)) + : nullptr; + } + + ~MaskEffect() override; + +protected: + MaskEffect(sk_sp, sk_sp mask, Mode); + + void onRender(SkCanvas*) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + const sk_sp fMaskNode; + const Mode fMaskMode; + + typedef EffectNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGMaskEffect_DEFINED diff --git a/modules/sksg/include/SkSGMerge.h b/modules/sksg/include/SkSGMerge.h new file mode 100644 index 0000000000..54924d6475 --- /dev/null +++ b/modules/sksg/include/SkSGMerge.h @@ -0,0 +1,64 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGMerge_DEFINED +#define SkSGMerge_DEFINED + +#include "SkSGGeometryNode.h" + +#include "SkPath.h" + +#include + +class SkCanvas; +class SkPaint; + +namespace sksg { + +/** + * Concrete Geometry node, combining other geometries based on Mode. + */ +class Merge final : public GeometryNode { +public: + enum class Mode { + // Append path mode. + kMerge, + + // SkPathOp ops. + kUnion, + kIntersect, + kDifference, + kReverseDifference, + kXOR, + }; + + static sk_sp Make(std::vector>&& geos, Mode mode) { + return sk_sp(new Merge(std::move(geos), mode)); + } + + ~Merge() override; + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + Merge(std::vector>&& geos, Mode); + + std::vector> fGeos; + SkPath fMerged; + Mode fMode; + + using INHERITED = GeometryNode; +}; + +} // namespace sksg + +#endif // SkSGMerge_DEFINED diff --git a/modules/sksg/include/SkSGNode.h b/modules/sksg/include/SkSGNode.h new file mode 100644 index 0000000000..17619de485 --- /dev/null +++ b/modules/sksg/include/SkSGNode.h @@ -0,0 +1,107 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGNode_DEFINED +#define SkSGNode_DEFINED + +#include "SkRect.h" +#include "SkRefCnt.h" +#include "SkTDArray.h" + +class SkCanvas; +class SkMatrix; + +namespace sksg { + +class InvalidationController; + +/** + * Base class for all scene graph nodes. + * + * Handles ingress edge management for the DAG (i.e. node -> "parent" node mapping), + * and invalidation. + * + * Note: egress edges are only implemented/supported in container subclasses + * (e.g. Group, Effect, Draw). + */ +class Node : public SkRefCnt { +public: + // Traverse the DAG and revalidate any dependant/invalidated nodes. + // Returns the bounding box for the DAG fragment. + const SkRect& revalidate(InvalidationController*, const SkMatrix&); + +protected: + enum InvalTraits { + // Nodes with this trait never generate direct damage -- instead, + // the damage bubbles up to ancestors. + kBubbleDamage_Trait = 1 << 0, + }; + + explicit Node(uint32_t invalTraits); + ~Node() override; + + const SkRect& bounds() const { + SkASSERT(!this->hasInval()); + return fBounds; + } + + // Tag this node for invalidation and optional damage. + void invalidate(bool damage = true); + bool hasInval() const { return fFlags & kInvalidated_Flag; } + + // Dispatched on revalidation. Subclasses are expected to recompute/cache their properties + // and return their bounding box in local coordinates. + virtual SkRect onRevalidate(InvalidationController*, const SkMatrix& ctm) = 0; + + // Register/unregister |this| to receive invalidation events from a descendant. + void observeInval(const sk_sp&); + void unobserveInval(const sk_sp&); + +private: + enum Flags { + kInvalidated_Flag = 1 << 0, // the node or its descendants require revalidation + kDamage_Flag = 1 << 1, // the node contributes damage during revalidation + kObserverArray_Flag = 1 << 2, // the node has more than one inval observer + kInTraversal_Flag = 1 << 3, // the node is part of a traversal (cycle detection) + }; + + template + void forEachInvalObserver(Func&&) const; + + class ScopedFlag; + + union { + Node* fInvalObserver; + SkTDArray* fInvalObserverArray; + }; + SkRect fBounds; + const uint32_t fInvalTraits : 16; + uint32_t fFlags : 16; + + typedef SkRefCnt INHERITED; +}; + +// Helper for defining attribute getters/setters in subclasses. +#define SG_ATTRIBUTE(attr_name, attr_type, attr_container) \ + const attr_type& get##attr_name() const { return attr_container; } \ + void set##attr_name(const attr_type& v) { \ + if (attr_container == v) return; \ + attr_container = v; \ + this->invalidate(); \ + } + +#define SG_MAPPED_ATTRIBUTE(attr_name, attr_type, attr_container) \ + attr_type get##attr_name() const { return attr_container.get##attr_name(); } \ + void set##attr_name(const attr_type& v) { \ + if (attr_container.get##attr_name() == v) return; \ + attr_container.set##attr_name(v); \ + this->invalidate(); \ + } + +} // namespace sksg + +#endif // SkSGNode_DEFINED diff --git a/modules/sksg/include/SkSGOpacityEffect.h b/modules/sksg/include/SkSGOpacityEffect.h new file mode 100644 index 0000000000..d906775b44 --- /dev/null +++ b/modules/sksg/include/SkSGOpacityEffect.h @@ -0,0 +1,42 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGOpacityEffect_DEFINED +#define SkSGOpacityEffect_DEFINED + +#include "SkSGEffectNode.h" + +namespace sksg { + +/** + * Concrete Effect node, applying opacity to its descendants. + * + */ +class OpacityEffect final : public EffectNode { +public: + static sk_sp Make(sk_sp child, float opacity = 1) { + return child ? sk_sp(new OpacityEffect(std::move(child), opacity)) : nullptr; + } + + SG_ATTRIBUTE(Opacity, float, fOpacity) + +protected: + OpacityEffect(sk_sp, float); + + void onRender(SkCanvas*) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + float fOpacity; + + typedef EffectNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGOpacityEffect_DEFINED diff --git a/modules/sksg/include/SkSGPaintNode.h b/modules/sksg/include/SkSGPaintNode.h new file mode 100644 index 0000000000..5c9563b3a6 --- /dev/null +++ b/modules/sksg/include/SkSGPaintNode.h @@ -0,0 +1,60 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGPaintNode_DEFINED +#define SkSGPaintNode_DEFINED + +#include "SkSGNode.h" + +#include "SkPaint.h" + +namespace sksg { + +/** + * Base class for nodes which provide a 'paint' (as opposed to geometry) for + * drawing (e.g. colors, gradients, patterns). + * + * Roughly equivalent to Skia's SkPaint. + */ +class PaintNode : public Node { +public: + const SkPaint& makePaint(); + + SG_ATTRIBUTE(AntiAlias , bool , fAntiAlias ) + SG_ATTRIBUTE(Opacity , SkScalar , fOpacity ) + SG_ATTRIBUTE(BlendMode , SkBlendMode , fBlendMode ) + SG_ATTRIBUTE(StrokeWidth, SkScalar , fStrokeWidth) + SG_ATTRIBUTE(StrokeMiter, SkScalar , fStrokeMiter) + SG_ATTRIBUTE(Style , SkPaint::Style, fStyle ) + SG_ATTRIBUTE(StrokeJoin , SkPaint::Join , fStrokeJoin ) + SG_ATTRIBUTE(StrokeCap , SkPaint::Cap , fStrokeCap ) + +protected: + PaintNode(); + + virtual void onApplyToPaint(SkPaint*) const = 0; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) final; + +private: + SkPaint fPaint; + + SkScalar fOpacity = 1, + fStrokeWidth = 1, + fStrokeMiter = 4; + bool fAntiAlias = false; + SkBlendMode fBlendMode = SkBlendMode::kSrcOver; + SkPaint::Style fStyle = SkPaint::kFill_Style; + SkPaint::Join fStrokeJoin = SkPaint::kMiter_Join; + SkPaint::Cap fStrokeCap = SkPaint::kButt_Cap; + + typedef Node INHERITED; +}; + +} // namespace sksg + +#endif // SkSGGeometryNode_DEFINED diff --git a/modules/sksg/include/SkSGPath.h b/modules/sksg/include/SkSGPath.h new file mode 100644 index 0000000000..1a8718868d --- /dev/null +++ b/modules/sksg/include/SkSGPath.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGPath_DEFINED +#define SkSGPath_DEFINED + +#include "SkSGGeometryNode.h" + +#include "SkPath.h" + +class SkCanvas; +class SkPaint; + +namespace sksg { + +/** + * Concrete Geometry node, wrapping an SkPath. + */ +class Path : public GeometryNode { +public: + static sk_sp Make() { return sk_sp(new Path(SkPath())); } + static sk_sp Make(const SkPath& r) { return sk_sp(new Path(r)); } + + SG_ATTRIBUTE(Path, SkPath, fPath) + SG_MAPPED_ATTRIBUTE(FillType, SkPath::FillType, fPath) + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + explicit Path(const SkPath&); + + SkPath fPath; + + using INHERITED = GeometryNode; +}; + +} // namespace sksg + +#endif // SkSGPath_DEFINED diff --git a/modules/sksg/include/SkSGPlane.h b/modules/sksg/include/SkSGPlane.h new file mode 100644 index 0000000000..c0a26375b2 --- /dev/null +++ b/modules/sksg/include/SkSGPlane.h @@ -0,0 +1,40 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGPlane_DEFINED +#define SkSGPlane_DEFINED + +#include "SkSGGeometryNode.h" + +class SkCanvas; +class SkPaint; + +namespace sksg { + +/** + * Concrete Geometry node, representing the whole canvas. + */ +class Plane final : public GeometryNode { +public: + static sk_sp Make() { return sk_sp(new Plane()); } + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + Plane(); + + using INHERITED = GeometryNode; +}; + +} // namespace sksg + +#endif // SkSGPlane_DEFINED diff --git a/modules/sksg/include/SkSGRect.h b/modules/sksg/include/SkSGRect.h new file mode 100644 index 0000000000..f5fcb962c6 --- /dev/null +++ b/modules/sksg/include/SkSGRect.h @@ -0,0 +1,76 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGRect_DEFINED +#define SkSGRect_DEFINED + +#include "SkSGGeometryNode.h" + +#include "SkRect.h" +#include "SkRRect.h" + +class SkCanvas; +class SkPaint; + +namespace sksg { + +/** + * Concrete Geometry node, wrapping an SkRect. + */ +class Rect final : public GeometryNode { +public: + static sk_sp Make() { return sk_sp(new Rect(SkRect::MakeEmpty())); } + static sk_sp Make(const SkRect& r) { return sk_sp(new Rect(r)); } + + SG_ATTRIBUTE(L, SkScalar, fRect.fLeft ) + SG_ATTRIBUTE(T, SkScalar, fRect.fTop ) + SG_ATTRIBUTE(R, SkScalar, fRect.fRight ) + SG_ATTRIBUTE(B, SkScalar, fRect.fBottom) + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + explicit Rect(const SkRect&); + + SkRect fRect; + + using INHERITED = GeometryNode; +}; + +/** + * Concrete Geometry node, wrapping an SkRRect. + */ +class RRect final : public GeometryNode { +public: + static sk_sp Make() { return sk_sp(new RRect(SkRRect())); } + static sk_sp Make(const SkRRect& rr) { return sk_sp(new RRect(rr)); } + + SG_ATTRIBUTE(RRect, SkRRect, fRRect) + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + explicit RRect(const SkRRect&); + + SkRRect fRRect; + + using INHERITED = GeometryNode; +}; + +} // namespace sksg + +#endif // SkSGRect_DEFINED diff --git a/modules/sksg/include/SkSGRenderNode.h b/modules/sksg/include/SkSGRenderNode.h new file mode 100644 index 0000000000..4ca1aec616 --- /dev/null +++ b/modules/sksg/include/SkSGRenderNode.h @@ -0,0 +1,36 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGRenderNode_DEFINED +#define SkSGRenderNode_DEFINED + +#include "SkSGNode.h" + +class SkCanvas; + +namespace sksg { + +/** + * Base class for nodes which can render to a canvas. + */ +class RenderNode : public Node { +public: + // Render the node and its descendants to the canvas. + void render(SkCanvas*) const; + +protected: + RenderNode(); + + virtual void onRender(SkCanvas*) const = 0; + +private: + typedef Node INHERITED; +}; + +} // namespace sksg + +#endif // SkSGRenderNode_DEFINED diff --git a/modules/sksg/include/SkSGRoundEffect.h b/modules/sksg/include/SkSGRoundEffect.h new file mode 100644 index 0000000000..67124ca072 --- /dev/null +++ b/modules/sksg/include/SkSGRoundEffect.h @@ -0,0 +1,50 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGRoundEffect_DEFINED +#define SkSGRoundEffect_DEFINED + +#include "SkSGGeometryNode.h" + +#include "SkPath.h" + +namespace sksg { + +/** + * Concrete Geometry node, applying a rounded-corner effect to its child. + */ +class RoundEffect final : public GeometryNode { +public: + static sk_sp Make(sk_sp child) { + return child ? sk_sp(new RoundEffect(std::move(child))) : nullptr; + } + + ~RoundEffect() override; + + SG_ATTRIBUTE(Radius, SkScalar, fRadius) + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + explicit RoundEffect(sk_sp); + + const sk_sp fChild; + + SkPath fRoundedPath; + SkScalar fRadius = 0; + + using INHERITED = GeometryNode; +}; + +} // namespace sksg + +#endif // SkSGRoundEffect_DEFINED diff --git a/modules/sksg/include/SkSGScene.h b/modules/sksg/include/SkSGScene.h new file mode 100644 index 0000000000..2081c1d747 --- /dev/null +++ b/modules/sksg/include/SkSGScene.h @@ -0,0 +1,85 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGScene_DEFINED +#define SkSGScene_DEFINED + +#include "SkRefCnt.h" +#include "SkTypes.h" + +#include +#include + +class SkCanvas; + +namespace sksg { + +class RenderNode; + +/** + * Base class for animators. + * + */ +class Animator : public SkNoncopyable { +public: + virtual ~Animator(); + + void tick(float t); + +protected: + Animator(); + + virtual void onTick(float t) = 0; + +private: + using INHERITED = SkNoncopyable; +}; + +using AnimatorList = std::vector>; + +class GroupAnimator : public Animator { +protected: + explicit GroupAnimator(AnimatorList&&); + + void onTick(float t) override; + +private: + const AnimatorList fAnimators; + + using INHERITED = Animator; +}; + +/** + * Holds a scene root and a list of animators. + * + * Provides high-level mehods for driving rendering and animations. + * + */ +class Scene final : SkNoncopyable { +public: + static std::unique_ptr Make(sk_sp root, AnimatorList&& animators); + ~Scene(); + + void render(SkCanvas*) const; + void animate(float t); + + void setShowInval(bool show) { fShowInval = show; } + +private: + Scene(sk_sp root, AnimatorList&& animators); + + const sk_sp fRoot; + const AnimatorList fAnimators; + + bool fShowInval = false; + + using INHERITED = SkNoncopyable; +}; + +} // namespace sksg + +#endif // SkSGScene_DEFINED diff --git a/modules/sksg/include/SkSGText.h b/modules/sksg/include/SkSGText.h new file mode 100644 index 0000000000..eb43337a10 --- /dev/null +++ b/modules/sksg/include/SkSGText.h @@ -0,0 +1,69 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGText_DEFINED +#define SkSGText_DEFINED + +#include "SkSGGeometryNode.h" + +#include "SkPaintDefaults.h" +#include "SkPoint.h" +#include "SkString.h" + +class SkCanvas; +class SkPaint; +class SkTextBlob; +class SkTypeface; + +namespace sksg { + +/** + * Concrete Geometry node, wrapping a (shaped) SkTextBlob. + */ +class Text final : public GeometryNode { +public: + static sk_sp Make(sk_sp tf, const SkString& text); + ~Text() override; + + SG_ATTRIBUTE(Text , SkString , fText ) + SG_ATTRIBUTE(Flags , uint32_t , fFlags ) + SG_ATTRIBUTE(Position, SkPoint , fPosition) + SG_ATTRIBUTE(Size , SkScalar , fSize ) + SG_ATTRIBUTE(ScaleX , SkScalar , fScaleX ) + SG_ATTRIBUTE(SkewX , SkScalar , fSkewX ) + SG_ATTRIBUTE(Align , SkPaint::Align, fAlign ) + + // TODO: add shaping functionality. + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + explicit Text(sk_sp, const SkString&); + + const sk_sp fTypeface; + SkString fText; + uint32_t fFlags = SkPaintDefaults_Flags; + SkPoint fPosition = SkPoint::Make(0, 0); + SkScalar fSize = SkPaintDefaults_TextSize; + SkScalar fScaleX = 1; + SkScalar fSkewX = 0; + SkPaint::Align fAlign = SkPaint::kLeft_Align; + SkPaint::Hinting fHinting = SkPaintDefaults_Hinting; + + sk_sp fBlob; // cached text blob + + using INHERITED = GeometryNode; +}; + +} // namespace sksg + +#endif // SkSGText_DEFINED diff --git a/modules/sksg/include/SkSGTransform.h b/modules/sksg/include/SkSGTransform.h new file mode 100644 index 0000000000..6b7fbc010b --- /dev/null +++ b/modules/sksg/include/SkSGTransform.h @@ -0,0 +1,81 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGTransform_DEFINED +#define SkSGTransform_DEFINED + +#include "SkSGEffectNode.h" + +#include "SkMatrix.h" + +namespace sksg { + +/** + * Concrete node, wrapping an SkMatrix, with an optional parent Matrix (to allow chaining): + * + * M' = parent x M + */ +class Matrix : public Node { +public: + static sk_sp Make(const SkMatrix& m, sk_sp parent = nullptr) { + return sk_sp(new Matrix(m, std::move(parent))); + } + + ~Matrix() override; + + SG_ATTRIBUTE(Matrix, SkMatrix, fLocalMatrix) + + const SkMatrix& getTotalMatrix() const { return fTotalMatrix; } + +protected: + Matrix(const SkMatrix&, sk_sp); + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + sk_sp fParent; + SkMatrix fLocalMatrix, + fTotalMatrix; // cached during revalidation + + typedef Node INHERITED; +}; + +/** + * Concrete Effect node, binding a Matrix to a RenderNode. + */ +class Transform final : public EffectNode { +public: + static sk_sp Make(sk_sp child, sk_sp matrix) { + return child && matrix + ? sk_sp(new Transform(std::move(child), std::move(matrix))) + : nullptr; + } + + static sk_sp Make(sk_sp child, const SkMatrix& m) { + return Make(std::move(child), Matrix::Make(m)); + } + + ~Transform() override; + + const sk_sp& getMatrix() const { return fMatrix; } + +protected: + void onRender(SkCanvas*) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + +private: + Transform(sk_sp, sk_sp); + + const sk_sp fMatrix; + + typedef EffectNode INHERITED; +}; + +} // namespace sksg + +#endif // SkSGTransform_DEFINED diff --git a/modules/sksg/include/SkSGTrimEffect.h b/modules/sksg/include/SkSGTrimEffect.h new file mode 100644 index 0000000000..18f15921e7 --- /dev/null +++ b/modules/sksg/include/SkSGTrimEffect.h @@ -0,0 +1,58 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkSGTrimEffect_DEFINED +#define SkSGTrimEffect_DEFINED + +#include "SkSGGeometryNode.h" + +#include "SkPath.h" +#include "SkTrimPathEffect.h" + +class SkCanvas; +class SkPaint; + +namespace sksg { + +/** + * Concrete Geometry node, applying a trim effect to its child. + */ +class TrimEffect final : public GeometryNode { +public: + static sk_sp Make(sk_sp child) { + return child ? sk_sp(new TrimEffect(std::move(child))) : nullptr; + } + + ~TrimEffect() override; + + SG_ATTRIBUTE(Start , SkScalar , fStart ) + SG_ATTRIBUTE(Stop , SkScalar , fStop ) + SG_ATTRIBUTE(Mode , SkTrimPathEffect::Mode, fMode ) + +protected: + void onClip(SkCanvas*, bool antiAlias) const override; + void onDraw(SkCanvas*, const SkPaint&) const override; + + SkRect onRevalidate(InvalidationController*, const SkMatrix&) override; + SkPath onAsPath() const override; + +private: + explicit TrimEffect(sk_sp); + + const sk_sp fChild; + + SkPath fTrimmedPath; + SkScalar fStart = 0, + fStop = 1; + SkTrimPathEffect::Mode fMode = SkTrimPathEffect::Mode::kNormal; + + using INHERITED = GeometryNode; +}; + +} // namespace sksg + +#endif // SkSGTrimEffect_DEFINED diff --git a/modules/sksg/samples/SampleSVGPong.cpp b/modules/sksg/samples/SampleSVGPong.cpp new file mode 100644 index 0000000000..993af38be8 --- /dev/null +++ b/modules/sksg/samples/SampleSVGPong.cpp @@ -0,0 +1,299 @@ +/* + * 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 "SampleCode.h" +#include "SkAnimTimer.h" +#include "SkColor.h" +#include "SkRandom.h" +#include "SkRRect.h" + +#include "SkSGColor.h" +#include "SkSGDraw.h" +#include "SkSGGroup.h" +#include "SkSGPath.h" +#include "SkSGRect.h" +#include "SkSGScene.h" +#include "SkSGTransform.h" + +namespace { + +static const SkRect kBounds = SkRect::MakeLTRB(0.1f, 0.1f, 0.9f, 0.9f); +static const SkSize kPaddleSize = SkSize::Make(0.03f, 0.1f); +static const SkScalar kBallSize = 0.04f; +static const SkScalar kShadowOpacity = 0.40f; +static const SkScalar kShadowParallax = 0.04f; +static const SkScalar kBackgroundStroke = 0.01f; +static const uint32_t kBackgroundDashCount = 20; + +static const SkScalar kBallSpeedMax = 0.0020f; +static const SkScalar kBallSpeedMin = 0.0005f; +static const SkScalar kBallSpeedFuzz = 0.0002f; + +static const SkScalar kTimeScaleMin = 0.0f; +static const SkScalar kTimeScaleMax = 5.0f; + +// Box the value within [min, max), by applying infinite reflection on the interval endpoints. +SkScalar box_reflect(SkScalar v, SkScalar min, SkScalar max) { + const SkScalar intervalLen = max - min; + SkASSERT(intervalLen > 0); + + // f(v) is periodic in 2 * intervalLen: one normal progression + one reflection + const SkScalar P = intervalLen * 2; + // relative to P origin + const SkScalar vP = v - min; + // map to [0, P) + const SkScalar vMod = (vP < 0) ? P - SkScalarMod(-vP, P) : SkScalarMod(vP, P); + // reflect if needed, to map to [0, intervalLen) + const SkScalar vInterval = vMod < intervalLen ? vMod : P - vMod; + // finally, reposition relative to min + return vInterval + min; +} + +// Compute for the trajectory intersection with the next vertical edge. +std::tuple find_yintercept(const SkPoint& pos, const SkVector& spd, + const SkRect& box) { + const SkScalar edge = spd.fX > 0 ? box.fRight : box.fLeft; + const SkScalar t = (edge - pos.fX) / spd.fX; + SkASSERT(t >= 0); + const SkScalar dY = t * spd.fY; + + return std::make_tuple(t, box_reflect(pos.fY + dY, box.fTop, box.fBottom)); +} + +void update_pos(const sk_sp& rr, const SkPoint& pos) { + // TODO: position setters on RRect? + + const auto r = rr->getRRect().rect(); + const auto offsetX = pos.x() - r.x(), + offsetY = pos.y() - r.y(); + rr->setRRect(rr->getRRect().makeOffset(offsetX, offsetY)); +} + +} // anonymous ns + +class PongView final : public SampleView { +public: + PongView() = default; + +protected: + void onOnceBeforeDraw() override { + const SkRect fieldBounds = kBounds.makeOutset(kBallSize / 2, kBallSize / 2); + const SkRRect ball = SkRRect::MakeOval(SkRect::MakeWH(kBallSize, kBallSize)); + const SkRRect paddle = SkRRect::MakeRectXY(SkRect::MakeWH(kPaddleSize.width(), + kPaddleSize.height()), + kPaddleSize.width() / 2, + kPaddleSize.width() / 2); + fBall.initialize(ball, + SkPoint::Make(kBounds.centerX(), kBounds.centerY()), + SkVector::Make(fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax), + fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax))); + fPaddle0.initialize(paddle, + SkPoint::Make(fieldBounds.left() - kPaddleSize.width() / 2, + fieldBounds.centerY()), + SkVector::Make(0, 0)); + fPaddle1.initialize(paddle, + SkPoint::Make(fieldBounds.right() + kPaddleSize.width() / 2, + fieldBounds.centerY()), + SkVector::Make(0, 0)); + + // Background decoration. + SkPath bgPath; + bgPath.moveTo(kBounds.left() , fieldBounds.top()); + bgPath.lineTo(kBounds.right(), fieldBounds.top()); + bgPath.moveTo(kBounds.left() , fieldBounds.bottom()); + bgPath.lineTo(kBounds.right(), fieldBounds.bottom()); + // TODO: stroke-dash support would come in handy right about now. + for (uint32_t i = 0; i < kBackgroundDashCount; ++i) { + bgPath.moveTo(kBounds.centerX(), + kBounds.top() + (i + 0.25f) * kBounds.height() / kBackgroundDashCount); + bgPath.lineTo(kBounds.centerX(), + kBounds.top() + (i + 0.75f) * kBounds.height() / kBackgroundDashCount); + } + + auto bg_path = sksg::Path::Make(bgPath); + auto bg_paint = sksg::Color::Make(SK_ColorBLACK); + bg_paint->setStyle(SkPaint::kStroke_Style); + bg_paint->setStrokeWidth(kBackgroundStroke); + + auto ball_paint = sksg::Color::Make(SK_ColorGREEN), + paddle0_paint = sksg::Color::Make(SK_ColorBLUE), + paddle1_paint = sksg::Color::Make(SK_ColorRED), + shadow_paint = sksg::Color::Make(SK_ColorBLACK); + ball_paint->setAntiAlias(true); + paddle0_paint->setAntiAlias(true); + paddle1_paint->setAntiAlias(true); + shadow_paint->setAntiAlias(true); + shadow_paint->setOpacity(kShadowOpacity); + + // Build the scene graph. + auto group = sksg::Group::Make(); + group->addChild(sksg::Draw::Make(std::move(bg_path), std::move(bg_paint))); + group->addChild(sksg::Draw::Make(fPaddle0.shadowNode, shadow_paint)); + group->addChild(sksg::Draw::Make(fPaddle1.shadowNode, shadow_paint)); + group->addChild(sksg::Draw::Make(fBall.shadowNode, shadow_paint)); + group->addChild(sksg::Draw::Make(fPaddle0.objectNode, paddle0_paint)); + group->addChild(sksg::Draw::Make(fPaddle1.objectNode, paddle1_paint)); + group->addChild(sksg::Draw::Make(fBall.objectNode, ball_paint)); + + // Handle everything in a normalized 1x1 space. + fContentMatrix = sksg::Matrix::Make( + SkMatrix::MakeRectToRect(SkRect::MakeWH(1, 1), + SkRect::MakeIWH(this->width(), this->height()), + SkMatrix::kFill_ScaleToFit)); + auto root = sksg::Transform::Make(std::move(group), fContentMatrix); + fScene = sksg::Scene::Make(std::move(root), sksg::AnimatorList()); + + // Off we go. + this->updatePaddleStrategy(); + } + + bool onQuery(SkEvent* evt) override { + if (SampleCode::TitleQ(*evt)) { + SampleCode::TitleR(evt, "SGPong"); + return true; + } + + SkUnichar uni; + if (SampleCode::CharQ(*evt, &uni)) { + switch (uni) { + case '[': + fTimeScale = SkTPin(fTimeScale - 0.1f, kTimeScaleMin, kTimeScaleMax); + return true; + case ']': + fTimeScale = SkTPin(fTimeScale + 0.1f, kTimeScaleMin, kTimeScaleMax); + return true; + case 'I': + fShowInval = !fShowInval; + fScene->setShowInval(fShowInval); + return true; + default: + break; + } + } + return this->INHERITED::onQuery(evt); + } + + void onSizeChange() override { + if (fContentMatrix) { + fContentMatrix->setMatrix(SkMatrix::MakeRectToRect(SkRect::MakeWH(1, 1), + SkRect::MakeIWH(this->width(), + this->height()), + SkMatrix::kFill_ScaleToFit)); + } + + this->INHERITED::onSizeChange(); + } + + void onDrawContent(SkCanvas* canvas) override { + fScene->render(canvas); + } + + bool onAnimate(const SkAnimTimer& timer) override { + // onAnimate may fire before the first draw. + if (fScene) { + SkScalar dt = (timer.msec() - fLastTick) * fTimeScale; + fLastTick = timer.msec(); + + fPaddle0.posTick(dt); + fPaddle1.posTick(dt); + fBall.posTick(dt); + + this->enforceConstraints(); + + fPaddle0.updateDom(); + fPaddle1.updateDom(); + fBall.updateDom(); + } + return true; + } + +private: + struct Object { + void initialize(const SkRRect& rrect, const SkPoint& p, const SkVector& s) { + objectNode = sksg::RRect::Make(rrect); + shadowNode = sksg::RRect::Make(rrect); + + pos = p; + spd = s; + size = SkSize::Make(rrect.width(), rrect.height()); + } + + void posTick(SkScalar dt) { + pos += spd * dt; + } + + void updateDom() { + const SkPoint corner = pos - SkPoint::Make(size.width() / 2, size.height() / 2); + update_pos(objectNode, corner); + + // Simulate parallax shadow for a centered light source. + SkPoint shadowOffset = pos - SkPoint::Make(kBounds.centerX(), kBounds.centerY()); + shadowOffset.scale(kShadowParallax); + const SkPoint shadowCorner = corner + shadowOffset; + + update_pos(shadowNode, shadowCorner); + } + + sk_sp objectNode, + shadowNode; + SkPoint pos; + SkVector spd; + SkSize size; + }; + + void enforceConstraints() { + // Perfect vertical reflection. + if (fBall.pos.fY < kBounds.fTop || fBall.pos.fY >= kBounds.fBottom) { + fBall.spd.fY = -fBall.spd.fY; + fBall.pos.fY = box_reflect(fBall.pos.fY, kBounds.fTop, kBounds.fBottom); + } + + // Horizontal bounce - introduces a speed fuzz. + if (fBall.pos.fX < kBounds.fLeft || fBall.pos.fX >= kBounds.fRight) { + fBall.spd.fX = this->fuzzBallSpeed(-fBall.spd.fX); + fBall.spd.fY = this->fuzzBallSpeed(fBall.spd.fY); + fBall.pos.fX = box_reflect(fBall.pos.fX, kBounds.fLeft, kBounds.fRight); + this->updatePaddleStrategy(); + } + } + + SkScalar fuzzBallSpeed(SkScalar spd) { + // The speed limits are absolute values. + const SkScalar sign = spd >= 0 ? 1.0f : -1.0f; + const SkScalar fuzzed = fabs(spd) + fRand.nextRangeScalar(-kBallSpeedFuzz, kBallSpeedFuzz); + + return sign * SkTPin(fuzzed, kBallSpeedMin, kBallSpeedMax); + } + + void updatePaddleStrategy() { + Object* pitcher = fBall.spd.fX > 0 ? &fPaddle0 : &fPaddle1; + Object* catcher = fBall.spd.fX > 0 ? &fPaddle1 : &fPaddle0; + + SkScalar t, yIntercept; + std::tie(t, yIntercept) = find_yintercept(fBall.pos, fBall.spd, kBounds); + + // The pitcher aims for a neutral/centered position. + pitcher->spd.fY = (kBounds.centerY() - pitcher->pos.fY) / t; + + // The catcher goes for the ball. Duh. + catcher->spd.fY = (yIntercept - catcher->pos.fY) / t; + } + + std::unique_ptr fScene; + sk_sp fContentMatrix; + Object fPaddle0, fPaddle1, fBall; + SkRandom fRand; + + SkMSec fLastTick = 0; + SkScalar fTimeScale = 1.0f; + bool fShowInval = false; + + typedef SampleView INHERITED; +}; + +static SkView* PongFactory() { return new PongView; } +static SkViewRegister reg(PongFactory); diff --git a/modules/sksg/src/SkSGClipEffect.cpp b/modules/sksg/src/SkSGClipEffect.cpp new file mode 100644 index 0000000000..b2d68fc8cf --- /dev/null +++ b/modules/sksg/src/SkSGClipEffect.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGClipEffect.h" + +#include "SkCanvas.h" +#include "SkPath.h" +#include "SkSGGeometryNode.h" + +namespace sksg { + +ClipEffect::ClipEffect(sk_sp child, sk_sp clip, bool aa) + : INHERITED(std::move(child)) + , fClipNode(std::move(clip)) + , fAntiAlias(aa) { + this->observeInval(fClipNode); +} + +ClipEffect::~ClipEffect() { + this->unobserveInval(fClipNode); +} + +void ClipEffect::onRender(SkCanvas* canvas) const { + if (this->bounds().isEmpty()) + return; + + SkAutoCanvasRestore acr(canvas, !fNoop); + if (!fNoop) { + fClipNode->clip(canvas, fAntiAlias); + } + + this->INHERITED::onRender(canvas); +} + +SkRect ClipEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + const auto clipBounds = fClipNode->revalidate(ic, ctm); + auto childBounds = this->INHERITED::onRevalidate(ic, ctm); + + fNoop = fClipNode->asPath().conservativelyContainsRect(childBounds); + + return childBounds.intersect(clipBounds) ? childBounds : SkRect::MakeEmpty(); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGColor.cpp b/modules/sksg/src/SkSGColor.cpp new file mode 100644 index 0000000000..d5d4d1ce62 --- /dev/null +++ b/modules/sksg/src/SkSGColor.cpp @@ -0,0 +1,18 @@ +/* + * 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 "SkSGColor.h" + +namespace sksg { + +Color::Color(SkColor c) : fColor(c) {} + +void Color::onApplyToPaint(SkPaint* paint) const { + paint->setColor(fColor); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGDraw.cpp b/modules/sksg/src/SkSGDraw.cpp new file mode 100644 index 0000000000..b73bf3b577 --- /dev/null +++ b/modules/sksg/src/SkSGDraw.cpp @@ -0,0 +1,50 @@ +/* + * 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 "SkSGDraw.h" + +#include "SkSGGeometryNode.h" +#include "SkSGInvalidationController.h" +#include "SkSGPaintNode.h" + +namespace sksg { + +Draw::Draw(sk_sp geometry, sk_sp paint) + : fGeometry(std::move(geometry)) + , fPaint(std::move(paint)) { + this->observeInval(fGeometry); + this->observeInval(fPaint); +} + +Draw::~Draw() { + this->unobserveInval(fGeometry); + this->unobserveInval(fPaint); +} + +void Draw::onRender(SkCanvas* canvas) const { + const auto& paint = fPaint->makePaint(); + const auto skipDraw = paint.nothingToDraw() || + (paint.getStyle() == SkPaint::kStroke_Style && paint.getStrokeWidth() <= 0); + + if (!skipDraw) { + fGeometry->draw(canvas, paint); + } +} + +SkRect Draw::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + auto bounds = fGeometry->revalidate(ic, ctm); + fPaint->revalidate(ic, ctm); + + const auto& paint = fPaint->makePaint(); + SkASSERT(paint.canComputeFastBounds()); + + return paint.computeFastBounds(bounds, &bounds); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGEffectNode.cpp b/modules/sksg/src/SkSGEffectNode.cpp new file mode 100644 index 0000000000..70050ccb70 --- /dev/null +++ b/modules/sksg/src/SkSGEffectNode.cpp @@ -0,0 +1,31 @@ +/* + * 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 "SkSGEffectNode.h" + +namespace sksg { + +EffectNode::EffectNode(sk_sp child) + : fChild(std::move(child)) { + this->observeInval(fChild); +} + +EffectNode::~EffectNode() { + this->unobserveInval(fChild); +} + +void EffectNode::onRender(SkCanvas* canvas) const { + fChild->render(canvas); +} + +SkRect EffectNode::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + return fChild->revalidate(ic, ctm); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGGeometryNode.cpp b/modules/sksg/src/SkSGGeometryNode.cpp new file mode 100644 index 0000000000..6b78c488b7 --- /dev/null +++ b/modules/sksg/src/SkSGGeometryNode.cpp @@ -0,0 +1,32 @@ +/* + * 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 "SkSGGeometryNode.h" + +#include "SkPath.h" + +namespace sksg { + +// Geometry nodes don't generate damage on their own, but via their aggregation ancestor Draw nodes. +GeometryNode::GeometryNode() : INHERITED(kBubbleDamage_Trait) {} + +void GeometryNode::clip(SkCanvas* canvas, bool aa) const { + SkASSERT(!this->hasInval()); + this->onClip(canvas, aa); +} + +void GeometryNode::draw(SkCanvas* canvas, const SkPaint& paint) const { + SkASSERT(!this->hasInval()); + this->onDraw(canvas, paint); +} + +SkPath GeometryNode::asPath() const { + SkASSERT(!this->hasInval()); + return this->onAsPath(); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGGeometryTransform.cpp b/modules/sksg/src/SkSGGeometryTransform.cpp new file mode 100644 index 0000000000..5b366b9620 --- /dev/null +++ b/modules/sksg/src/SkSGGeometryTransform.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGGeometryTransform.h" + +#include "SkCanvas.h" + +namespace sksg { + +GeometryTransform::GeometryTransform(sk_sp child, sk_sp matrix) + : fChild(std::move(child)) + , fMatrix(std::move(matrix)) { + this->observeInval(fChild); + this->observeInval(fMatrix); +} + +GeometryTransform::~GeometryTransform() { + this->unobserveInval(fChild); + this->unobserveInval(fMatrix); +} + +void GeometryTransform::onClip(SkCanvas* canvas, bool antiAlias) const { + canvas->clipPath(fTransformed, SkClipOp::kIntersect, antiAlias); +} + +void GeometryTransform::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + canvas->drawPath(fTransformed, paint); +} + +SkRect GeometryTransform::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + // We don't care about matrix reval results. + fMatrix->revalidate(ic, ctm); + const auto& m = fMatrix->getMatrix(); + + auto bounds = fChild->revalidate(ic, ctm); + fTransformed = fChild->asPath(); + fTransformed.transform(m); + + m.mapRect(&bounds); + return bounds; +} + +SkPath GeometryTransform::onAsPath() const { + return fTransformed; +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGGradient.cpp b/modules/sksg/src/SkSGGradient.cpp new file mode 100644 index 0000000000..98e7f395f8 --- /dev/null +++ b/modules/sksg/src/SkSGGradient.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGGradient.h" + +#include "SkGradientShader.h" +#include "SkPaint.h" + +namespace sksg { + +void Gradient::onApplyToPaint(SkPaint* paint) const { + if (fColorStops.empty()) { + paint->setShader(nullptr); + return; + } + + std::vector colors; + std::vector positions; + colors.reserve(fColorStops.size()); + positions.reserve(fColorStops.size()); + + SkScalar position = 0; + for (const auto& stop : fColorStops) { + colors.push_back(stop.fColor); + position = SkTPin(stop.fPosition, position, 1.0f); + positions.push_back(position); + } + + // TODO: detect even stop distributions, pass null for positions. + paint->setShader(this->onMakeShader(colors, positions)); +} + +sk_sp LinearGradient::onMakeShader(const std::vector& colors, + const std::vector& positions) const { + SkASSERT(colors.size() == positions.size()); + + const SkPoint pts[] = { fStartPoint, fEndPoint }; + return SkGradientShader::MakeLinear(pts, colors.data(), positions.data(), colors.size(), + this->getTileMode()); +} + +sk_sp RadialGradient::onMakeShader(const std::vector& colors, + const std::vector& positions) const { + SkASSERT(colors.size() == positions.size()); + + return (fStartRadius <= 0 && fStartCenter == fEndCenter) + ? SkGradientShader::MakeRadial(fEndCenter, fEndRadius, + colors.data(), positions.data(), colors.size(), + this->getTileMode()) + : SkGradientShader::MakeTwoPointConical(fStartCenter, fStartRadius, + fEndCenter, fEndRadius, + colors.data(), positions.data(), colors.size(), + this->getTileMode()); +} + +} //namespace sksg diff --git a/modules/sksg/src/SkSGGroup.cpp b/modules/sksg/src/SkSGGroup.cpp new file mode 100644 index 0000000000..aeccf233f7 --- /dev/null +++ b/modules/sksg/src/SkSGGroup.cpp @@ -0,0 +1,66 @@ +/* + * 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 "SkSGGroup.h" + +namespace sksg { + +Group::Group() {} + +Group::~Group() { + for (const auto& child : fChildren) { + this->unobserveInval(child); + } +} + +void Group::addChild(sk_sp node) { + // should we allow duplicates? + for (const auto& child : fChildren) { + if (child == node) { + return; + } + } + + this->observeInval(node); + fChildren.push_back(std::move(node)); + + this->invalidate(); +} + +void Group::removeChild(const sk_sp& node) { + int origCount = fChildren.count(); + for (int i = 0; i < origCount; ++i) { + if (fChildren[i] == node) { + fChildren.removeShuffle(i); + this->unobserveInval(node); + break; + } + } + SkASSERT(fChildren.count() == origCount - 1); + + this->invalidate(); +} + +void Group::onRender(SkCanvas* canvas) const { + for (const auto& child : fChildren) { + child->render(canvas); + } +} + +SkRect Group::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + SkRect bounds = SkRect::MakeEmpty(); + + for (const auto& child : fChildren) { + bounds.join(child->revalidate(ic, ctm)); + } + + return bounds; +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGImage.cpp b/modules/sksg/src/SkSGImage.cpp new file mode 100644 index 0000000000..a0c3a759dc --- /dev/null +++ b/modules/sksg/src/SkSGImage.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGImage.h" + +#include "SkCanvas.h" +#include "SkImage.h" + +namespace sksg { + +Image::Image(sk_sp image) : fImage(std::move(image)) {} + +void Image::onRender(SkCanvas* canvas) const { + SkPaint paint; + paint.setAntiAlias(fAntiAlias); + paint.setFilterQuality(fQuality); + + canvas->drawImage(fImage, 0, 0); +} + +SkRect Image::onRevalidate(InvalidationController*, const SkMatrix& ctm) { + return SkRect::Make(fImage->bounds()); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGInvalidationController.cpp b/modules/sksg/src/SkSGInvalidationController.cpp new file mode 100644 index 0000000000..81a3376bf6 --- /dev/null +++ b/modules/sksg/src/SkSGInvalidationController.cpp @@ -0,0 +1,32 @@ +/* + * 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 "SkSGInvalidationController.h" + +#include "SkRect.h" +#include "SkTLazy.h" + +namespace sksg { + +InvalidationController::InvalidationController() : fBounds(SkRect::MakeEmpty()) {} + +void InvalidationController::inval(const SkRect& r, const SkMatrix& ctm) { + if (r.isEmpty()) { + return; + } + + SkTCopyOnFirstWrite rect(r); + + if (!ctm.isIdentity()) { + ctm.mapRect(rect.writable()); + } + + fRects.push(*rect); + fBounds.join(*rect); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGMaskEffect.cpp b/modules/sksg/src/SkSGMaskEffect.cpp new file mode 100644 index 0000000000..16e4c0dd8d --- /dev/null +++ b/modules/sksg/src/SkSGMaskEffect.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGMaskEffect.h" + +#include "SkCanvas.h" + +namespace sksg { + +MaskEffect::MaskEffect(sk_sp child, sk_sp mask, Mode mode) + : INHERITED(std::move(child)) + , fMaskNode(std::move(mask)) + , fMaskMode(mode) { + this->observeInval(fMaskNode); +} + +MaskEffect::~MaskEffect() { + this->unobserveInval(fMaskNode); +} + +void MaskEffect::onRender(SkCanvas* canvas) const { + if (this->bounds().isEmpty()) + return; + + SkAutoCanvasRestore acr(canvas, false); + + canvas->saveLayer(this->bounds(), nullptr); + fMaskNode->render(canvas); + + + SkPaint p; + p.setBlendMode(fMaskMode == Mode::kNormal ? SkBlendMode::kSrcIn : SkBlendMode::kSrcOut); + canvas->saveLayer(this->bounds(), &p); + + this->INHERITED::onRender(canvas); +} + + +SkRect MaskEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + const auto maskBounds = fMaskNode->revalidate(ic, ctm); + auto childBounds = this->INHERITED::onRevalidate(ic, ctm); + + return (fMaskMode == Mode::kInvert || childBounds.intersect(maskBounds)) + ? childBounds + : SkRect::MakeEmpty(); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGMerge.cpp b/modules/sksg/src/SkSGMerge.cpp new file mode 100644 index 0000000000..be1ff4123a --- /dev/null +++ b/modules/sksg/src/SkSGMerge.cpp @@ -0,0 +1,84 @@ +/* + * 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 "SkSGMerge.h" + +#include "SkCanvas.h" +#include "SkPathOps.h" + +namespace sksg { + +Merge::Merge(std::vector>&& geos, Mode mode) + : fGeos(std::move(geos)) + , fMode(mode) { + for (const auto& geo : fGeos) { + this->observeInval(geo); + } +} + +Merge::~Merge() { + for (const auto& geo : fGeos) { + this->unobserveInval(geo); + } +} + +void Merge::onClip(SkCanvas* canvas, bool antiAlias) const { + canvas->clipPath(fMerged, SkClipOp::kIntersect, antiAlias); +} + +void Merge::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + canvas->drawPath(fMerged, paint); +} + +SkPath Merge::onAsPath() const { + return fMerged; +} + +static SkPathOp mode_to_op(Merge::Mode mode) { + switch (mode) { + case Merge::Mode::kUnion: + return kUnion_SkPathOp; + case Merge::Mode::kIntersect: + return kIntersect_SkPathOp; + case Merge::Mode::kDifference: + return kDifference_SkPathOp; + case Merge::Mode::kReverseDifference: + return kReverseDifference_SkPathOp; + case Merge::Mode::kXOR: + return kXOR_SkPathOp; + default: + break; + } + + return kUnion_SkPathOp; +} + +SkRect Merge::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + const auto op = mode_to_op(fMode); + SkOpBuilder builder; + + fMerged.reset(); + + for (const auto& geo : fGeos) { + geo->revalidate(ic, ctm); + if (fMode == Mode::kMerge) { + fMerged.addPath(geo->asPath()); + } else { + builder.add(geo->asPath(), geo == fGeos.front() ? kUnion_SkPathOp : op); + } + } + + if (fMode != Mode::kMerge) { + builder.resolve(&fMerged); + } + + return fMerged.computeTightBounds(); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGNode.cpp b/modules/sksg/src/SkSGNode.cpp new file mode 100644 index 0000000000..35b2640dbb --- /dev/null +++ b/modules/sksg/src/SkSGNode.cpp @@ -0,0 +1,152 @@ +/* + * 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 "SkRectPriv.h" +#include "SkSGNode.h" +#include "SkSGInvalidationController.h" + +namespace sksg { + +class Node::ScopedFlag { +public: + ScopedFlag(Node* node, uint32_t flag) + : fNode(node) + , fFlag(flag) + , fWasSet(node->fFlags & flag) { + node->fFlags |= flag; + } + ~ScopedFlag() { + if (!fWasSet) { + fNode->fFlags &= ~fFlag;; + } + } + + bool wasSet() const { return fWasSet; } + +private: + Node* fNode; + uint32_t fFlag; + bool fWasSet; +}; + +#define TRAVERSAL_GUARD \ + ScopedFlag traversal_guard(this, kInTraversal_Flag); \ + if (traversal_guard.wasSet()) \ + return + +Node::Node(uint32_t invalTraits) + : fInvalObserver(nullptr) + , fBounds(SkRectPriv::MakeLargeS32()) + , fInvalTraits(invalTraits) + , fFlags(kInvalidated_Flag) {} + +Node::~Node() { + if (fFlags & kObserverArray_Flag) { + SkASSERT(fInvalObserverArray->isEmpty()); + delete fInvalObserverArray; + } else { + SkASSERT(!fInvalObserver); + } +} + +void Node::observeInval(const sk_sp& node) { + SkASSERT(node); + if (!(node->fFlags & kObserverArray_Flag)) { + if (!node->fInvalObserver) { + node->fInvalObserver = this; + return; + } + + auto observers = new SkTDArray(); + observers->setReserve(2); + observers->push(node->fInvalObserver); + + node->fInvalObserverArray = observers; + node->fFlags |= kObserverArray_Flag; + } + + // No duplicate observers. + SkASSERT(node->fInvalObserverArray->find(this) < 0); + + node->fInvalObserverArray->push(this); +} + +void Node::unobserveInval(const sk_sp& node) { + SkASSERT(node); + if (!(node->fFlags & kObserverArray_Flag)) { + SkASSERT(node->fInvalObserver == this); + node->fInvalObserver = nullptr; + return; + } + + const auto idx = node->fInvalObserverArray->find(this); + SkASSERT(idx >= 0); + node->fInvalObserverArray->remove(idx); +} + +template +void Node::forEachInvalObserver(Func&& func) const { + if (fFlags & kObserverArray_Flag) { + for (const auto& parent : *fInvalObserverArray) { + func(parent); + } + return; + } + + if (fInvalObserver) { + func(fInvalObserver); + } +} + +void Node::invalidate(bool damageBubbling) { + TRAVERSAL_GUARD; + + if (this->hasInval() && (!damageBubbling || (fFlags & kDamage_Flag))) { + // All done. + return; + } + + if (damageBubbling && !(fInvalTraits & kBubbleDamage_Trait)) { + // Found a damage observer. + fFlags |= kDamage_Flag; + damageBubbling = false; + } + + fFlags |= kInvalidated_Flag; + + forEachInvalObserver([&](Node* observer) { + observer->invalidate(damageBubbling); + }); +} + +const SkRect& Node::revalidate(InvalidationController* ic, const SkMatrix& ctm) { + TRAVERSAL_GUARD fBounds; + + if (!this->hasInval()) { + return fBounds; + } + + SkRect prevBounds; + if (fFlags & kDamage_Flag) { + prevBounds = fBounds; + } + + fBounds = this->onRevalidate(ic, ctm); + + if (fFlags & kDamage_Flag) { + ic->inval(prevBounds, ctm); + if (fBounds != prevBounds) { + ic->inval(fBounds, ctm); + } + } + + fFlags &= ~(kInvalidated_Flag | kDamage_Flag); + + return fBounds; +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGOpacityEffect.cpp b/modules/sksg/src/SkSGOpacityEffect.cpp new file mode 100644 index 0000000000..b1ff10d217 --- /dev/null +++ b/modules/sksg/src/SkSGOpacityEffect.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGOpacityEffect.h" + +#include "SkCanvas.h" + +#include + +namespace sksg { + +OpacityEffect::OpacityEffect(sk_sp child, float opacity) + : INHERITED(std::move(child)) + , fOpacity(opacity) {} + +void OpacityEffect::onRender(SkCanvas* canvas) const { + // opacity <= 0 disables rendering + if (fOpacity <= 0) + return; + + // TODO: we could avoid savelayer if there is no more than one drawing primitive + // in the sub-DAG. + SkAutoCanvasRestore acr(canvas, false); + if (fOpacity < 1) { + canvas->saveLayerAlpha(&this->bounds(), roundf(fOpacity * 255)); + } + + this->INHERITED::onRender(canvas); +} + +SkRect OpacityEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + // opacity <= 0 disables rendering AND revalidation for the sub-DAG + return fOpacity > 0 ? this->INHERITED::onRevalidate(ic, ctm) : SkRect::MakeEmpty(); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGPaintNode.cpp b/modules/sksg/src/SkSGPaintNode.cpp new file mode 100644 index 0000000000..9220b0f0af --- /dev/null +++ b/modules/sksg/src/SkSGPaintNode.cpp @@ -0,0 +1,41 @@ +/* + * 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 "SkSGPaintNode.h" + +namespace sksg { + +// Paint nodes don't generate damage on their own, but via their aggregation ancestor Draw nodes. +PaintNode::PaintNode() : INHERITED(kBubbleDamage_Trait) {} + +const SkPaint& PaintNode::makePaint() { + SkASSERT(!this->hasInval()); + + return fPaint; +} + +SkRect PaintNode::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasInval()); + + fPaint.reset(); + fPaint.setAntiAlias(fAntiAlias); + fPaint.setBlendMode(fBlendMode); + fPaint.setStyle(fStyle); + fPaint.setStrokeWidth(fStrokeWidth); + fPaint.setStrokeMiter(fStrokeMiter); + fPaint.setStrokeJoin(fStrokeJoin); + fPaint.setStrokeCap(fStrokeCap); + + this->onApplyToPaint(&fPaint); + + // Compose opacity on top of the subclass value. + fPaint.setAlpha(SkScalarRoundToInt(fPaint.getAlpha() * SkTPin(fOpacity, 0, 1))); + + return SkRect::MakeEmpty(); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGPath.cpp b/modules/sksg/src/SkSGPath.cpp new file mode 100644 index 0000000000..230442d409 --- /dev/null +++ b/modules/sksg/src/SkSGPath.cpp @@ -0,0 +1,41 @@ +/* + * 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 "SkSGPath.h" + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkRectPriv.h" + +namespace sksg { + +Path::Path(const SkPath& path) : fPath(path) {} + +void Path::onClip(SkCanvas* canvas, bool antiAlias) const { + canvas->clipPath(fPath, SkClipOp::kIntersect, antiAlias); +} + +void Path::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + canvas->drawPath(fPath, paint); +} + +SkRect Path::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasInval()); + + const auto ft = fPath.getFillType(); + return (ft == SkPath::kWinding_FillType || ft == SkPath::kEvenOdd_FillType) + // "Containing" fills have finite bounds. + ? fPath.computeTightBounds() + // Inverse fills are "infinite". + : SkRectPriv::MakeLargeS32(); +} + +SkPath Path::onAsPath() const { + return fPath; +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGPlane.cpp b/modules/sksg/src/SkSGPlane.cpp new file mode 100644 index 0000000000..806fcc7d29 --- /dev/null +++ b/modules/sksg/src/SkSGPlane.cpp @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGPlane.h" + +#include "SkCanvas.h" +#include "SkPath.h" + +namespace sksg { + +Plane::Plane() = default; + +void Plane::onClip(SkCanvas*, bool) const {} + +void Plane::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + canvas->drawPaint(paint); +} + +SkRect Plane::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasInval()); + + return SkRect::MakeLTRB(SK_ScalarMin, SK_ScalarMin, SK_ScalarMax, SK_ScalarMax); +} + +SkPath Plane::onAsPath() const { + SkPath path; + path.setFillType(SkPath::kInverseWinding_FillType); + + return path; +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGRect.cpp b/modules/sksg/src/SkSGRect.cpp new file mode 100644 index 0000000000..16f0a6f1e1 --- /dev/null +++ b/modules/sksg/src/SkSGRect.cpp @@ -0,0 +1,60 @@ +/* + * 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 "SkSGRect.h" + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkPath.h" + +namespace sksg { + +Rect::Rect(const SkRect& rect) : fRect(rect) {} + +void Rect::onClip(SkCanvas* canvas, bool antiAlias) const { + canvas->clipRect(fRect, SkClipOp::kIntersect, antiAlias); +} + +void Rect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + canvas->drawRect(fRect, paint); +} + +SkRect Rect::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasInval()); + + return fRect; +} + +SkPath Rect::onAsPath() const { + SkPath path; + path.addRect(fRect); + return path; +} + +RRect::RRect(const SkRRect& rr) : fRRect(rr) {} + +void RRect::onClip(SkCanvas* canvas, bool antiAlias) const { + canvas->clipRRect(fRRect, SkClipOp::kIntersect, antiAlias); +} + +void RRect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + canvas->drawRRect(fRRect, paint); +} + +SkRect RRect::onRevalidate(InvalidationController*, const SkMatrix&) { + SkASSERT(this->hasInval()); + + return fRRect.getBounds(); +} + +SkPath RRect::onAsPath() const { + SkPath path; + path.addRRect(fRRect); + return path; +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGRenderNode.cpp b/modules/sksg/src/SkSGRenderNode.cpp new file mode 100644 index 0000000000..e952c69f20 --- /dev/null +++ b/modules/sksg/src/SkSGRenderNode.cpp @@ -0,0 +1,19 @@ +/* + * 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 "SkSGRenderNode.h" + +namespace sksg { + +RenderNode::RenderNode() : INHERITED(0) {} + +void RenderNode::render(SkCanvas* canvas) const { + SkASSERT(!this->hasInval()); + this->onRender(canvas); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGRoundEffect.cpp b/modules/sksg/src/SkSGRoundEffect.cpp new file mode 100644 index 0000000000..8cf9068f65 --- /dev/null +++ b/modules/sksg/src/SkSGRoundEffect.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGRoundEffect.h" + +#include "SkCanvas.h" +#include "SkCornerPathEffect.h" +#include "SkStrokeRec.h" + +namespace sksg { + +RoundEffect::RoundEffect(sk_sp child) + : fChild(std::move(child)) { + this->observeInval(fChild); +} + +RoundEffect::~RoundEffect() { + this->unobserveInval(fChild); +} + +void RoundEffect::onClip(SkCanvas* canvas, bool antiAlias) const { + canvas->clipPath(fRoundedPath, SkClipOp::kIntersect, antiAlias); +} + +void RoundEffect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + SkASSERT(!paint.getPathEffect()); + + canvas->drawPath(fRoundedPath, paint); +} + +SkPath RoundEffect::onAsPath() const { + return fRoundedPath; +} + +SkRect RoundEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + const auto childbounds = fChild->revalidate(ic, ctm); + const auto path = fChild->asPath(); + + if (auto round = SkCornerPathEffect::Make(fRadius)) { + fRoundedPath.reset(); + SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle); + SkAssertResult(round->filterPath(&fRoundedPath, path, &rec, &childbounds)); + } else { + fRoundedPath = path; + } + + return fRoundedPath.computeTightBounds(); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGScene.cpp b/modules/sksg/src/SkSGScene.cpp new file mode 100644 index 0000000000..8d7e0b369b --- /dev/null +++ b/modules/sksg/src/SkSGScene.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGScene.h" + +#include "SkCanvas.h" +#include "SkMatrix.h" +#include "SkPaint.h" +#include "SkSGInvalidationController.h" +#include "SkSGRenderNode.h" + +namespace sksg { + +Animator::Animator() = default; +Animator::~Animator() = default; + +void Animator::tick(float t) { + this->onTick(t); +} + +GroupAnimator::GroupAnimator(AnimatorList&& animators) + : fAnimators(std::move(animators)) {} + +void GroupAnimator::onTick(float t) { + for (const auto& a : fAnimators) { + a->tick(t); + } +} + +std::unique_ptr Scene::Make(sk_sp root, AnimatorList&& anims) { + return root ? std::unique_ptr(new Scene(std::move(root), std::move(anims))) : nullptr; +} + +Scene::Scene(sk_sp root, AnimatorList&& animators) + : fRoot(std::move(root)) + , fAnimators(std::move(animators)) {} + +Scene::~Scene() = default; + +void Scene::render(SkCanvas* canvas) const { + InvalidationController ic; + fRoot->revalidate(&ic, SkMatrix::I()); + fRoot->render(canvas); + + if (fShowInval) { + SkPaint fill, stroke; + fill.setAntiAlias(true); + fill.setColor(0x40ff0000); + stroke.setAntiAlias(true); + stroke.setColor(0xffff0000); + stroke.setStyle(SkPaint::kStroke_Style); + + for (const auto& r : ic) { + canvas->drawRect(r, fill); + canvas->drawRect(r, stroke); + } + } +} + +void Scene::animate(float t) { + for (const auto& anim : fAnimators) { + anim->tick(t); + } +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGText.cpp b/modules/sksg/src/SkSGText.cpp new file mode 100644 index 0000000000..c149390023 --- /dev/null +++ b/modules/sksg/src/SkSGText.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkSGText.h" + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkTArray.h" +#include "SkTextBlob.h" +#include "SkTypeface.h" + +namespace sksg { + +sk_sp Text::Make(sk_sp tf, const SkString& text) { + return sk_sp(new Text(std::move(tf), text)); +} + +Text::Text(sk_sp tf, const SkString& text) + : fTypeface(std::move(tf)) + , fText(text) {} + +Text::~Text() = default; + +SkRect Text::onRevalidate(InvalidationController*, const SkMatrix&) { + // TODO: we could potentially track invals which don't require rebuilding the blob. + + SkPaint font; + font.setFlags(fFlags); + font.setTypeface(fTypeface); + font.setTextSize(fSize); + font.setTextScaleX(fScaleX); + font.setTextSkewX(fSkewX); + font.setTextAlign(fAlign); + font.setHinting(fHinting); + + // First, convert to glyphIDs. + font.setTextEncoding(SkPaint::kUTF8_TextEncoding); + SkSTArray<256, SkGlyphID, true> glyphs; + glyphs.reset(font.textToGlyphs(fText.c_str(), fText.size(), nullptr)); + SkAssertResult(font.textToGlyphs(fText.c_str(), fText.size(), glyphs.begin()) == glyphs.count()); + font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + + // Next, build the cached blob. + SkTextBlobBuilder builder; + const auto& buf = builder.allocRun(font, glyphs.count(), 0, 0, nullptr); + if (!buf.glyphs) { + fBlob.reset(); + return SkRect::MakeEmpty(); + } + + memcpy(buf.glyphs, glyphs.begin(), glyphs.count() * sizeof(SkGlyphID)); + + fBlob = builder.make(); + return fBlob + ? fBlob->bounds().makeOffset(fPosition.x(), fPosition.y()) + : SkRect::MakeEmpty(); +} + +void Text::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + canvas->drawTextBlob(fBlob, fPosition.x(), fPosition.y(), paint); +} + +SkPath Text::onAsPath() const { + // TODO + return SkPath(); +} + +void Text::onClip(SkCanvas* canvas, bool antiAlias) const { + canvas->clipPath(this->asPath(), antiAlias); +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGTransform.cpp b/modules/sksg/src/SkSGTransform.cpp new file mode 100644 index 0000000000..6a985a971e --- /dev/null +++ b/modules/sksg/src/SkSGTransform.cpp @@ -0,0 +1,70 @@ +/* + * 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 "SkSGTransform.h" + +#include "SkCanvas.h" + +namespace sksg { +// Matrix nodes don't generate damage on their own, but via aggregation ancestor Transform nodes. +Matrix::Matrix(const SkMatrix& m, sk_sp parent) + : INHERITED(kBubbleDamage_Trait) + , fParent(std::move(parent)) + , fLocalMatrix(m) { + if (fParent) { + this->observeInval(fParent); + } +} + +Matrix::~Matrix() { + if (fParent) { + this->unobserveInval(fParent); + } +} + +SkRect Matrix::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + fTotalMatrix = fLocalMatrix; + + if (fParent) { + fParent->revalidate(ic, ctm); + fTotalMatrix.postConcat(fParent->getTotalMatrix()); + } + + return SkRect::MakeEmpty(); +} + +Transform::Transform(sk_sp child, sk_sp matrix) + : INHERITED(std::move(child)) + , fMatrix(std::move(matrix)) { + this->observeInval(fMatrix); +} + +Transform::~Transform() { + this->unobserveInval(fMatrix); +} + +void Transform::onRender(SkCanvas* canvas) const { + const auto& m = fMatrix->getTotalMatrix(); + SkAutoCanvasRestore acr(canvas, !m.isIdentity()); + canvas->concat(m); + this->INHERITED::onRender(canvas); +} + +SkRect Transform::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + // We don't care about matrix reval results. + fMatrix->revalidate(ic, ctm); + + const auto& m = fMatrix->getTotalMatrix(); + auto bounds = this->INHERITED::onRevalidate(ic, SkMatrix::Concat(ctm, m)); + m.mapRect(&bounds); + + return bounds; +} + +} // namespace sksg diff --git a/modules/sksg/src/SkSGTrimEffect.cpp b/modules/sksg/src/SkSGTrimEffect.cpp new file mode 100644 index 0000000000..b8c59bcfe8 --- /dev/null +++ b/modules/sksg/src/SkSGTrimEffect.cpp @@ -0,0 +1,56 @@ +/* + * 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 "SkSGTrimEffect.h" + +#include "SkCanvas.h" +#include "SkStrokeRec.h" +#include "SkTrimPathEffect.h" + +namespace sksg { + +TrimEffect::TrimEffect(sk_sp child) + : fChild(std::move(child)) { + this->observeInval(fChild); +} + +TrimEffect::~TrimEffect() { + this->unobserveInval(fChild); +} + +void TrimEffect::onClip(SkCanvas* canvas, bool antiAlias) const { + canvas->clipPath(fTrimmedPath, SkClipOp::kIntersect, antiAlias); +} + +void TrimEffect::onDraw(SkCanvas* canvas, const SkPaint& paint) const { + SkASSERT(!paint.getPathEffect()); + + canvas->drawPath(fTrimmedPath, paint); +} + +SkPath TrimEffect::onAsPath() const { + return fTrimmedPath; +} + +SkRect TrimEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { + SkASSERT(this->hasInval()); + + const auto childbounds = fChild->revalidate(ic, ctm); + const auto path = fChild->asPath(); + + if (auto trim = SkTrimPathEffect::Make(fStart, fStop, fMode)) { + fTrimmedPath.reset(); + SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle); + SkAssertResult(trim->filterPath(&fTrimmedPath, path, &rec, &childbounds)); + } else { + fTrimmedPath = path; + } + + return fTrimmedPath.computeTightBounds(); +} + +} // namespace sksg diff --git a/modules/sksg/tests/SGTest.cpp b/modules/sksg/tests/SGTest.cpp new file mode 100644 index 0000000000..1228e666e7 --- /dev/null +++ b/modules/sksg/tests/SGTest.cpp @@ -0,0 +1,197 @@ +/* + * 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 "SkRect.h" +#include "SkRectPriv.h" + +#if !defined(SK_BUILD_FOR_GOOGLE3) + +#include "SkSGColor.h" +#include "SkSGDraw.h" +#include "SkSGGroup.h" +#include "SkSGInvalidationController.h" +#include "SkSGRect.h" +#include "SkSGTransform.h" + +#include "Test.h" + +#include + +static void check_inval(skiatest::Reporter* reporter, const sk_sp& root, + const SkRect& expected_bounds, + const SkRect& expected_inval_bounds, + const std::vector* expected_damage) { + sksg::InvalidationController ic; + const auto bbox = root->revalidate(&ic, SkMatrix::I()); + + if (0) { + SkDebugf("** bbox: [%f %f %f %f], ibbox: [%f %f %f %f]\n", + bbox.fLeft, bbox.fTop, bbox.fRight, bbox.fBottom, + ic.bounds().left(), ic.bounds().top(), ic.bounds().right(), ic.bounds().bottom()); + } + + REPORTER_ASSERT(reporter, bbox == expected_bounds); + REPORTER_ASSERT(reporter, ic.bounds() == expected_inval_bounds); + + if (expected_damage) { + const auto damage_count = SkTo(ic.end() - ic.begin()); + REPORTER_ASSERT(reporter, expected_damage->size() == damage_count); + for (size_t i = 0; i < std::min(expected_damage->size(), damage_count); ++i) { + const auto r1 = (*expected_damage)[i], + r2 = ic.begin()[i]; + if (0) { + SkDebugf("*** expected inval: [%f %f %f %f], actual: [%f %f %f %f]\n", + r1.left(), r1.top(), r1.right(), r1.bottom(), + r2.left(), r2.top(), r2.right(), r2.bottom()); + } + REPORTER_ASSERT(reporter, r1 == r2); + } + } +} + +static void inval_test1(skiatest::Reporter* reporter) { + auto color = sksg::Color::Make(0xff000000); + auto r1 = sksg::Rect::Make(SkRect::MakeWH(100, 100)), + r2 = sksg::Rect::Make(SkRect::MakeWH(100, 100)); + auto grp = sksg::Group::Make(); + auto matrix = sksg::Matrix::Make(SkMatrix::I()); + auto root = sksg::Transform::Make(grp, matrix); + + grp->addChild(sksg::Draw::Make(r1, color)); + grp->addChild(sksg::Draw::Make(r2, color)); + + { + // Initial revalidation. + check_inval(reporter, root, + SkRect::MakeWH(100, 100), + SkRectPriv::MakeLargeS32(), + nullptr); + } + + { + // Move r2 to (200 100). + r2->setL(200); r2->setT(100); r2->setR(300); r2->setB(200); + std::vector damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} }; + check_inval(reporter, root, + SkRect::MakeWH(300, 200), + SkRect::MakeWH(300, 200), + &damage); + } + + { + // Update the common color. + color->setColor(0xffff0000); + std::vector damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} }; + check_inval(reporter, root, + SkRect::MakeWH(300, 200), + SkRect::MakeWH(300, 200), + &damage); + } + + { + // Shrink r1. + r1->setR(50); + std::vector damage = { {0, 0, 100, 100}, { 0, 0, 50, 100} }; + check_inval(reporter, root, + SkRect::MakeWH(300, 200), + SkRect::MakeWH(100, 100), + &damage); + } + + { + // Update transform. + matrix->setMatrix(SkMatrix::MakeScale(2, 2)); + std::vector damage = { {0, 0, 300, 200}, { 0, 0, 600, 400} }; + check_inval(reporter, root, + SkRect::MakeWH(600, 400), + SkRect::MakeWH(600, 400), + &damage); + } + + { + // Shrink r2 under transform. + r2->setR(250); + std::vector damage = { {400, 200, 600, 400}, { 400, 200, 500, 400} }; + check_inval(reporter, root, + SkRect::MakeWH(500, 400), + SkRect::MakeLTRB(400, 200, 600, 400), + &damage); + } +} + +static void inval_test2(skiatest::Reporter* reporter) { + auto color = sksg::Color::Make(0xff000000); + auto rect = sksg::Rect::Make(SkRect::MakeWH(100, 100)); + auto m1 = sksg::Matrix::Make(SkMatrix::I()), + m2 = sksg::Matrix::Make(SkMatrix::I(), m1); + auto t1 = sksg::Transform::Make(sksg::Draw::Make(rect, color), m2), + t2 = sksg::Transform::Make(sksg::Draw::Make(rect, color), m1); + auto root = sksg::Group::Make(); + root->addChild(t1); + root->addChild(t2); + + { + // Initial revalidation. + check_inval(reporter, root, + SkRect::MakeWH(100, 100), + SkRectPriv::MakeLargeS32(), + nullptr); + } + + { + // Update the shared color. + color->setColor(0xffff0000); + std::vector damage = { {0, 0, 100, 100}, { 0, 0, 100, 100} }; + check_inval(reporter, root, + SkRect::MakeWH(100, 100), + SkRect::MakeWH(100, 100), + &damage); + } + + { + // Update m2. + m2->setMatrix(SkMatrix::MakeScale(2, 2)); + std::vector damage = { {0, 0, 100, 100}, { 0, 0, 200, 200} }; + check_inval(reporter, root, + SkRect::MakeWH(200, 200), + SkRect::MakeWH(200, 200), + &damage); + } + + { + // Update shared m1. + m1->setMatrix(SkMatrix::MakeTrans(100, 100)); + std::vector damage = { { 0, 0, 200, 200}, // draw1 prev bounds + { 100, 100, 300, 300}, // draw1 new bounds + { 0, 0, 100, 100}, // draw2 prev bounds + { 100, 100, 200, 200} }; // draw2 new bounds + check_inval(reporter, root, + SkRect::MakeLTRB(100, 100, 300, 300), + SkRect::MakeLTRB( 0, 0, 300, 300), + &damage); + } + + { + // Update shared rect. + rect->setR(50); + std::vector damage = { { 100, 100, 300, 300}, // draw1 prev bounds + { 100, 100, 200, 300}, // draw1 new bounds + { 100, 100, 200, 200}, // draw2 prev bounds + { 100, 100, 150, 200} }; // draw2 new bounds + check_inval(reporter, root, + SkRect::MakeLTRB(100, 100, 200, 300), + SkRect::MakeLTRB(100, 100, 300, 300), + &damage); + } +} + +DEF_TEST(SGInvalidation, reporter) { + inval_test1(reporter); + inval_test2(reporter); +} + +#endif // !defined(SK_BUILD_FOR_GOOGLE3) diff --git a/samplecode/SampleSGInval.cpp b/samplecode/SampleSGInval.cpp deleted file mode 100644 index 44cdcb91d9..0000000000 --- a/samplecode/SampleSGInval.cpp +++ /dev/null @@ -1,94 +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 "SampleCode.h" -#include "SkCanvas.h" -#include "SkSGColor.h" -#include "SkSGDraw.h" -#include "SkSGGroup.h" -#include "SkSGInvalidationController.h" -#include "SkSGRect.h" -#include "SkSGTransform.h" -#include "SkAnimTimer.h" - -#include - -class SGInvalView final : public SampleView { -public: - SGInvalView() {} - -protected: - void onOnceBeforeDraw() override { - fRect1 = sksg::Rect::Make(SkRect::MakeLTRB(100, 100, 100, 100)); - fRect2 = sksg::Rect::Make(SkRect::MakeLTRB(300, 200, 300, 200)); - fColor1 = sksg::Color::Make(0); - fColor2 = sksg::Color::Make(0); - - fRoot = sksg::Group::Make(); - fRoot->addChild(sksg::Draw::Make(fRect1, fColor1)); - fRoot->addChild(sksg::Transform::Make(sksg::Draw::Make(fRect2, fColor2), - SkMatrix::MakeScale(1.5f, 1.5f))); - } - - bool onQuery(SkEvent* evt) override { - if (SampleCode::TitleQ(*evt)) { - SampleCode::TitleR(evt, "SGInval"); - return true; - } - - return this->INHERITED::onQuery(evt); - } - - void onDrawContent(SkCanvas* canvas) override { - sksg::InvalidationController ic; - fRoot->revalidate(&ic, SkMatrix::I()); - - // TODO: clip/cull - fRoot->render(canvas); - - SkPaint p; - p.setColor(0xffff0000); - p.setStyle(SkPaint::kStroke_Style); - p.setAntiAlias(true); - p.setStrokeWidth(0); - - for (const auto& r : ic) { - canvas->drawRect(r, p); - } - } - - bool onAnimate(const SkAnimTimer& timer) override { - if (!fRoot) { - return true; - } - - static constexpr SkScalar kSize = 50; - static constexpr SkScalar kRate = 1.0f / 500; - const auto t = timer.msec() * kRate; - - fRect1->setR(fRect1->getL() + kSize * (1 + std::sin(t))); - fRect1->setB(fRect1->getT() + kSize * (1 + std::cos(t))); - fRect2->setR(fRect2->getL() + kSize * (1 + std::cos(SK_ScalarPI / 2 + t))); - fRect2->setB(fRect2->getT() + kSize * (1 + std::sin(SK_ScalarPI / 2 + t))); - - fColor1->setColor(SkColorSetARGB(128 * (1 + std::sin(t)), 0, 0x80, 0)); - fColor2->setColor(SkColorSetARGB(128 * (1 + std::cos(t)), 0, 0, 0x80)); - return true; - } - -private: - typedef SampleView INHERITED; - - sk_sp fRect1, - fRect2; - sk_sp fColor1, - fColor2; - sk_sp fRoot; -}; - -static SkView* SGInvalFactory() { return new SGInvalView; } -static SkViewRegister reg(SGInvalFactory); diff --git a/samplecode/SampleSVGPong.cpp b/samplecode/SampleSVGPong.cpp deleted file mode 100644 index 993af38be8..0000000000 --- a/samplecode/SampleSVGPong.cpp +++ /dev/null @@ -1,299 +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 "SampleCode.h" -#include "SkAnimTimer.h" -#include "SkColor.h" -#include "SkRandom.h" -#include "SkRRect.h" - -#include "SkSGColor.h" -#include "SkSGDraw.h" -#include "SkSGGroup.h" -#include "SkSGPath.h" -#include "SkSGRect.h" -#include "SkSGScene.h" -#include "SkSGTransform.h" - -namespace { - -static const SkRect kBounds = SkRect::MakeLTRB(0.1f, 0.1f, 0.9f, 0.9f); -static const SkSize kPaddleSize = SkSize::Make(0.03f, 0.1f); -static const SkScalar kBallSize = 0.04f; -static const SkScalar kShadowOpacity = 0.40f; -static const SkScalar kShadowParallax = 0.04f; -static const SkScalar kBackgroundStroke = 0.01f; -static const uint32_t kBackgroundDashCount = 20; - -static const SkScalar kBallSpeedMax = 0.0020f; -static const SkScalar kBallSpeedMin = 0.0005f; -static const SkScalar kBallSpeedFuzz = 0.0002f; - -static const SkScalar kTimeScaleMin = 0.0f; -static const SkScalar kTimeScaleMax = 5.0f; - -// Box the value within [min, max), by applying infinite reflection on the interval endpoints. -SkScalar box_reflect(SkScalar v, SkScalar min, SkScalar max) { - const SkScalar intervalLen = max - min; - SkASSERT(intervalLen > 0); - - // f(v) is periodic in 2 * intervalLen: one normal progression + one reflection - const SkScalar P = intervalLen * 2; - // relative to P origin - const SkScalar vP = v - min; - // map to [0, P) - const SkScalar vMod = (vP < 0) ? P - SkScalarMod(-vP, P) : SkScalarMod(vP, P); - // reflect if needed, to map to [0, intervalLen) - const SkScalar vInterval = vMod < intervalLen ? vMod : P - vMod; - // finally, reposition relative to min - return vInterval + min; -} - -// Compute for the trajectory intersection with the next vertical edge. -std::tuple find_yintercept(const SkPoint& pos, const SkVector& spd, - const SkRect& box) { - const SkScalar edge = spd.fX > 0 ? box.fRight : box.fLeft; - const SkScalar t = (edge - pos.fX) / spd.fX; - SkASSERT(t >= 0); - const SkScalar dY = t * spd.fY; - - return std::make_tuple(t, box_reflect(pos.fY + dY, box.fTop, box.fBottom)); -} - -void update_pos(const sk_sp& rr, const SkPoint& pos) { - // TODO: position setters on RRect? - - const auto r = rr->getRRect().rect(); - const auto offsetX = pos.x() - r.x(), - offsetY = pos.y() - r.y(); - rr->setRRect(rr->getRRect().makeOffset(offsetX, offsetY)); -} - -} // anonymous ns - -class PongView final : public SampleView { -public: - PongView() = default; - -protected: - void onOnceBeforeDraw() override { - const SkRect fieldBounds = kBounds.makeOutset(kBallSize / 2, kBallSize / 2); - const SkRRect ball = SkRRect::MakeOval(SkRect::MakeWH(kBallSize, kBallSize)); - const SkRRect paddle = SkRRect::MakeRectXY(SkRect::MakeWH(kPaddleSize.width(), - kPaddleSize.height()), - kPaddleSize.width() / 2, - kPaddleSize.width() / 2); - fBall.initialize(ball, - SkPoint::Make(kBounds.centerX(), kBounds.centerY()), - SkVector::Make(fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax), - fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax))); - fPaddle0.initialize(paddle, - SkPoint::Make(fieldBounds.left() - kPaddleSize.width() / 2, - fieldBounds.centerY()), - SkVector::Make(0, 0)); - fPaddle1.initialize(paddle, - SkPoint::Make(fieldBounds.right() + kPaddleSize.width() / 2, - fieldBounds.centerY()), - SkVector::Make(0, 0)); - - // Background decoration. - SkPath bgPath; - bgPath.moveTo(kBounds.left() , fieldBounds.top()); - bgPath.lineTo(kBounds.right(), fieldBounds.top()); - bgPath.moveTo(kBounds.left() , fieldBounds.bottom()); - bgPath.lineTo(kBounds.right(), fieldBounds.bottom()); - // TODO: stroke-dash support would come in handy right about now. - for (uint32_t i = 0; i < kBackgroundDashCount; ++i) { - bgPath.moveTo(kBounds.centerX(), - kBounds.top() + (i + 0.25f) * kBounds.height() / kBackgroundDashCount); - bgPath.lineTo(kBounds.centerX(), - kBounds.top() + (i + 0.75f) * kBounds.height() / kBackgroundDashCount); - } - - auto bg_path = sksg::Path::Make(bgPath); - auto bg_paint = sksg::Color::Make(SK_ColorBLACK); - bg_paint->setStyle(SkPaint::kStroke_Style); - bg_paint->setStrokeWidth(kBackgroundStroke); - - auto ball_paint = sksg::Color::Make(SK_ColorGREEN), - paddle0_paint = sksg::Color::Make(SK_ColorBLUE), - paddle1_paint = sksg::Color::Make(SK_ColorRED), - shadow_paint = sksg::Color::Make(SK_ColorBLACK); - ball_paint->setAntiAlias(true); - paddle0_paint->setAntiAlias(true); - paddle1_paint->setAntiAlias(true); - shadow_paint->setAntiAlias(true); - shadow_paint->setOpacity(kShadowOpacity); - - // Build the scene graph. - auto group = sksg::Group::Make(); - group->addChild(sksg::Draw::Make(std::move(bg_path), std::move(bg_paint))); - group->addChild(sksg::Draw::Make(fPaddle0.shadowNode, shadow_paint)); - group->addChild(sksg::Draw::Make(fPaddle1.shadowNode, shadow_paint)); - group->addChild(sksg::Draw::Make(fBall.shadowNode, shadow_paint)); - group->addChild(sksg::Draw::Make(fPaddle0.objectNode, paddle0_paint)); - group->addChild(sksg::Draw::Make(fPaddle1.objectNode, paddle1_paint)); - group->addChild(sksg::Draw::Make(fBall.objectNode, ball_paint)); - - // Handle everything in a normalized 1x1 space. - fContentMatrix = sksg::Matrix::Make( - SkMatrix::MakeRectToRect(SkRect::MakeWH(1, 1), - SkRect::MakeIWH(this->width(), this->height()), - SkMatrix::kFill_ScaleToFit)); - auto root = sksg::Transform::Make(std::move(group), fContentMatrix); - fScene = sksg::Scene::Make(std::move(root), sksg::AnimatorList()); - - // Off we go. - this->updatePaddleStrategy(); - } - - bool onQuery(SkEvent* evt) override { - if (SampleCode::TitleQ(*evt)) { - SampleCode::TitleR(evt, "SGPong"); - return true; - } - - SkUnichar uni; - if (SampleCode::CharQ(*evt, &uni)) { - switch (uni) { - case '[': - fTimeScale = SkTPin(fTimeScale - 0.1f, kTimeScaleMin, kTimeScaleMax); - return true; - case ']': - fTimeScale = SkTPin(fTimeScale + 0.1f, kTimeScaleMin, kTimeScaleMax); - return true; - case 'I': - fShowInval = !fShowInval; - fScene->setShowInval(fShowInval); - return true; - default: - break; - } - } - return this->INHERITED::onQuery(evt); - } - - void onSizeChange() override { - if (fContentMatrix) { - fContentMatrix->setMatrix(SkMatrix::MakeRectToRect(SkRect::MakeWH(1, 1), - SkRect::MakeIWH(this->width(), - this->height()), - SkMatrix::kFill_ScaleToFit)); - } - - this->INHERITED::onSizeChange(); - } - - void onDrawContent(SkCanvas* canvas) override { - fScene->render(canvas); - } - - bool onAnimate(const SkAnimTimer& timer) override { - // onAnimate may fire before the first draw. - if (fScene) { - SkScalar dt = (timer.msec() - fLastTick) * fTimeScale; - fLastTick = timer.msec(); - - fPaddle0.posTick(dt); - fPaddle1.posTick(dt); - fBall.posTick(dt); - - this->enforceConstraints(); - - fPaddle0.updateDom(); - fPaddle1.updateDom(); - fBall.updateDom(); - } - return true; - } - -private: - struct Object { - void initialize(const SkRRect& rrect, const SkPoint& p, const SkVector& s) { - objectNode = sksg::RRect::Make(rrect); - shadowNode = sksg::RRect::Make(rrect); - - pos = p; - spd = s; - size = SkSize::Make(rrect.width(), rrect.height()); - } - - void posTick(SkScalar dt) { - pos += spd * dt; - } - - void updateDom() { - const SkPoint corner = pos - SkPoint::Make(size.width() / 2, size.height() / 2); - update_pos(objectNode, corner); - - // Simulate parallax shadow for a centered light source. - SkPoint shadowOffset = pos - SkPoint::Make(kBounds.centerX(), kBounds.centerY()); - shadowOffset.scale(kShadowParallax); - const SkPoint shadowCorner = corner + shadowOffset; - - update_pos(shadowNode, shadowCorner); - } - - sk_sp objectNode, - shadowNode; - SkPoint pos; - SkVector spd; - SkSize size; - }; - - void enforceConstraints() { - // Perfect vertical reflection. - if (fBall.pos.fY < kBounds.fTop || fBall.pos.fY >= kBounds.fBottom) { - fBall.spd.fY = -fBall.spd.fY; - fBall.pos.fY = box_reflect(fBall.pos.fY, kBounds.fTop, kBounds.fBottom); - } - - // Horizontal bounce - introduces a speed fuzz. - if (fBall.pos.fX < kBounds.fLeft || fBall.pos.fX >= kBounds.fRight) { - fBall.spd.fX = this->fuzzBallSpeed(-fBall.spd.fX); - fBall.spd.fY = this->fuzzBallSpeed(fBall.spd.fY); - fBall.pos.fX = box_reflect(fBall.pos.fX, kBounds.fLeft, kBounds.fRight); - this->updatePaddleStrategy(); - } - } - - SkScalar fuzzBallSpeed(SkScalar spd) { - // The speed limits are absolute values. - const SkScalar sign = spd >= 0 ? 1.0f : -1.0f; - const SkScalar fuzzed = fabs(spd) + fRand.nextRangeScalar(-kBallSpeedFuzz, kBallSpeedFuzz); - - return sign * SkTPin(fuzzed, kBallSpeedMin, kBallSpeedMax); - } - - void updatePaddleStrategy() { - Object* pitcher = fBall.spd.fX > 0 ? &fPaddle0 : &fPaddle1; - Object* catcher = fBall.spd.fX > 0 ? &fPaddle1 : &fPaddle0; - - SkScalar t, yIntercept; - std::tie(t, yIntercept) = find_yintercept(fBall.pos, fBall.spd, kBounds); - - // The pitcher aims for a neutral/centered position. - pitcher->spd.fY = (kBounds.centerY() - pitcher->pos.fY) / t; - - // The catcher goes for the ball. Duh. - catcher->spd.fY = (yIntercept - catcher->pos.fY) / t; - } - - std::unique_ptr fScene; - sk_sp fContentMatrix; - Object fPaddle0, fPaddle1, fBall; - SkRandom fRand; - - SkMSec fLastTick = 0; - SkScalar fTimeScale = 1.0f; - bool fShowInval = false; - - typedef SampleView INHERITED; -}; - -static SkView* PongFactory() { return new PongView; } -static SkViewRegister reg(PongFactory); diff --git a/tests/SGTest.cpp b/tests/SGTest.cpp deleted file mode 100644 index 1228e666e7..0000000000 --- a/tests/SGTest.cpp +++ /dev/null @@ -1,197 +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 "SkRect.h" -#include "SkRectPriv.h" - -#if !defined(SK_BUILD_FOR_GOOGLE3) - -#include "SkSGColor.h" -#include "SkSGDraw.h" -#include "SkSGGroup.h" -#include "SkSGInvalidationController.h" -#include "SkSGRect.h" -#include "SkSGTransform.h" - -#include "Test.h" - -#include - -static void check_inval(skiatest::Reporter* reporter, const sk_sp& root, - const SkRect& expected_bounds, - const SkRect& expected_inval_bounds, - const std::vector* expected_damage) { - sksg::InvalidationController ic; - const auto bbox = root->revalidate(&ic, SkMatrix::I()); - - if (0) { - SkDebugf("** bbox: [%f %f %f %f], ibbox: [%f %f %f %f]\n", - bbox.fLeft, bbox.fTop, bbox.fRight, bbox.fBottom, - ic.bounds().left(), ic.bounds().top(), ic.bounds().right(), ic.bounds().bottom()); - } - - REPORTER_ASSERT(reporter, bbox == expected_bounds); - REPORTER_ASSERT(reporter, ic.bounds() == expected_inval_bounds); - - if (expected_damage) { - const auto damage_count = SkTo(ic.end() - ic.begin()); - REPORTER_ASSERT(reporter, expected_damage->size() == damage_count); - for (size_t i = 0; i < std::min(expected_damage->size(), damage_count); ++i) { - const auto r1 = (*expected_damage)[i], - r2 = ic.begin()[i]; - if (0) { - SkDebugf("*** expected inval: [%f %f %f %f], actual: [%f %f %f %f]\n", - r1.left(), r1.top(), r1.right(), r1.bottom(), - r2.left(), r2.top(), r2.right(), r2.bottom()); - } - REPORTER_ASSERT(reporter, r1 == r2); - } - } -} - -static void inval_test1(skiatest::Reporter* reporter) { - auto color = sksg::Color::Make(0xff000000); - auto r1 = sksg::Rect::Make(SkRect::MakeWH(100, 100)), - r2 = sksg::Rect::Make(SkRect::MakeWH(100, 100)); - auto grp = sksg::Group::Make(); - auto matrix = sksg::Matrix::Make(SkMatrix::I()); - auto root = sksg::Transform::Make(grp, matrix); - - grp->addChild(sksg::Draw::Make(r1, color)); - grp->addChild(sksg::Draw::Make(r2, color)); - - { - // Initial revalidation. - check_inval(reporter, root, - SkRect::MakeWH(100, 100), - SkRectPriv::MakeLargeS32(), - nullptr); - } - - { - // Move r2 to (200 100). - r2->setL(200); r2->setT(100); r2->setR(300); r2->setB(200); - std::vector damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} }; - check_inval(reporter, root, - SkRect::MakeWH(300, 200), - SkRect::MakeWH(300, 200), - &damage); - } - - { - // Update the common color. - color->setColor(0xffff0000); - std::vector damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} }; - check_inval(reporter, root, - SkRect::MakeWH(300, 200), - SkRect::MakeWH(300, 200), - &damage); - } - - { - // Shrink r1. - r1->setR(50); - std::vector damage = { {0, 0, 100, 100}, { 0, 0, 50, 100} }; - check_inval(reporter, root, - SkRect::MakeWH(300, 200), - SkRect::MakeWH(100, 100), - &damage); - } - - { - // Update transform. - matrix->setMatrix(SkMatrix::MakeScale(2, 2)); - std::vector damage = { {0, 0, 300, 200}, { 0, 0, 600, 400} }; - check_inval(reporter, root, - SkRect::MakeWH(600, 400), - SkRect::MakeWH(600, 400), - &damage); - } - - { - // Shrink r2 under transform. - r2->setR(250); - std::vector damage = { {400, 200, 600, 400}, { 400, 200, 500, 400} }; - check_inval(reporter, root, - SkRect::MakeWH(500, 400), - SkRect::MakeLTRB(400, 200, 600, 400), - &damage); - } -} - -static void inval_test2(skiatest::Reporter* reporter) { - auto color = sksg::Color::Make(0xff000000); - auto rect = sksg::Rect::Make(SkRect::MakeWH(100, 100)); - auto m1 = sksg::Matrix::Make(SkMatrix::I()), - m2 = sksg::Matrix::Make(SkMatrix::I(), m1); - auto t1 = sksg::Transform::Make(sksg::Draw::Make(rect, color), m2), - t2 = sksg::Transform::Make(sksg::Draw::Make(rect, color), m1); - auto root = sksg::Group::Make(); - root->addChild(t1); - root->addChild(t2); - - { - // Initial revalidation. - check_inval(reporter, root, - SkRect::MakeWH(100, 100), - SkRectPriv::MakeLargeS32(), - nullptr); - } - - { - // Update the shared color. - color->setColor(0xffff0000); - std::vector damage = { {0, 0, 100, 100}, { 0, 0, 100, 100} }; - check_inval(reporter, root, - SkRect::MakeWH(100, 100), - SkRect::MakeWH(100, 100), - &damage); - } - - { - // Update m2. - m2->setMatrix(SkMatrix::MakeScale(2, 2)); - std::vector damage = { {0, 0, 100, 100}, { 0, 0, 200, 200} }; - check_inval(reporter, root, - SkRect::MakeWH(200, 200), - SkRect::MakeWH(200, 200), - &damage); - } - - { - // Update shared m1. - m1->setMatrix(SkMatrix::MakeTrans(100, 100)); - std::vector damage = { { 0, 0, 200, 200}, // draw1 prev bounds - { 100, 100, 300, 300}, // draw1 new bounds - { 0, 0, 100, 100}, // draw2 prev bounds - { 100, 100, 200, 200} }; // draw2 new bounds - check_inval(reporter, root, - SkRect::MakeLTRB(100, 100, 300, 300), - SkRect::MakeLTRB( 0, 0, 300, 300), - &damage); - } - - { - // Update shared rect. - rect->setR(50); - std::vector damage = { { 100, 100, 300, 300}, // draw1 prev bounds - { 100, 100, 200, 300}, // draw1 new bounds - { 100, 100, 200, 200}, // draw2 prev bounds - { 100, 100, 150, 200} }; // draw2 new bounds - check_inval(reporter, root, - SkRect::MakeLTRB(100, 100, 200, 300), - SkRect::MakeLTRB(100, 100, 300, 300), - &damage); - } -} - -DEF_TEST(SGInvalidation, reporter) { - inval_test1(reporter); - inval_test2(reporter); -} - -#endif // !defined(SK_BUILD_FOR_GOOGLE3) diff --git a/tools/viewer/SlideDir.cpp b/tools/viewer/SlideDir.cpp index 1da6df4678..41bff87b79 100644 --- a/tools/viewer/SlideDir.cpp +++ b/tools/viewer/SlideDir.cpp @@ -7,6 +7,8 @@ #include "SlideDir.h" +#ifdef SK_HAS_SKSG + #include "SkAnimTimer.h" #include "SkCanvas.h" #include "SkCubicMap.h" @@ -418,3 +420,5 @@ const SlideDir::Rec* SlideDir::findCell(float x, float y) const { return idx < fRecs.count() ? &fRecs[idx] : nullptr; } + +#endif // SK_HAS_SKSG diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp index 85a72984a3..2357a18bb5 100644 --- a/tools/viewer/Viewer.cpp +++ b/tools/viewer/Viewer.cpp @@ -37,11 +37,14 @@ #include "SkTaskGroup.h" #include "SkTestFontMgr.h" #include "SkThreadedBMPDevice.h" -#include "SlideDir.h" #include "SvgSlide.h" #include "ccpr/GrCoverageCountingPathRenderer.h" #include "imgui.h" +#if defined(SK_HAS_SKSG) + #include "SlideDir.h" +#endif + #if defined(SK_ENABLE_SKOTTIE) #include "SkottieSlide.h" #endif @@ -646,13 +649,14 @@ void Viewer::initSlides() { addSlide(name, SkOSPath::Join(flag.c_str(), name.c_str()), info.fFactory); } } - +#if defined(SK_HAS_SKSG) if (!dirSlides.empty()) { fSlides.push_back( sk_make_sp(SkStringPrintf("%s[%s]", info.fDirName, flag.c_str()), std::move(dirSlides))); dirSlides.reset(); } +#endif } } } -- cgit v1.2.3