[svg] Add feTurbulence filter (incomplete)

This was the simplest one to start with. I need to add support for the
"filter effect subregion" in order to handle tile stitching property,
so this isn't quite complete. But I believe this is enough for the
basic filters-turb-01-f test to pass, which gives us a baseline for
further filter work.

Summary of changes:
- Added attribute type and parsing for SVG integer datatype
- Added new node class for feTurbulence
- Added several new properties and parsing for feTurbulence

Bug: skia:10841
Change-Id: I8c877a5e1a837bfd527782253062eeb58febdde6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/330621
Commit-Queue: Tyler Denniston <tdenniston@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/modules/svg/src/SkSVGFeTurbulence.cpp b/modules/svg/src/SkSVGFeTurbulence.cpp
new file mode 100644
index 0000000..3adb554
--- /dev/null
+++ b/modules/svg/src/SkSVGFeTurbulence.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/effects/SkImageFilters.h"
+#include "include/effects/SkPerlinNoiseShader.h"
+#include "modules/svg/include/SkSVGFeTurbulence.h"
+#include "modules/svg/include/SkSVGFilterContext.h"
+#include "modules/svg/include/SkSVGRenderContext.h"
+#include "modules/svg/include/SkSVGValue.h"
+
+void SkSVGFeTurbulence::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
+    switch (attr) {
+        case SkSVGAttribute::kFeTurbulenceBaseFrequency:
+            if (const auto* f = v.as<SkSVGFeTurbulenceBaseFrequencyValue>()) {
+                this->setBaseFrequency(*f);
+            }
+            break;
+        case SkSVGAttribute::kFeTurbulenceNumOctaves:
+            if (const auto* n = v.as<SkSVGIntegerValue>()) {
+                this->setNumOctaves(*n);
+            }
+            break;
+        case SkSVGAttribute::kFeTurbulenceSeed:
+            if (const auto* s = v.as<SkSVGNumberValue>()) {
+                this->setSeed(*s);
+            }
+            break;
+        case SkSVGAttribute::kFeTurbulenceType:
+            if (const auto* t = v.as<SkSVGFeTurbulenceTypeValue>()) {
+                this->setTurbulenceType(*t);
+            }
+            break;
+        default:
+            this->INHERITED::onSetAttribute(attr, v);
+    }
+}
+
+sk_sp<SkImageFilter> SkSVGFeTurbulence::onMakeImageFilter(const SkSVGRenderContext& ctx,
+                                                          const SkSVGFilterContext& fctx) const {
+    const SkISize* tileSize = nullptr;  // TODO: needs filter element subregion properties
+
+    sk_sp<SkShader> shader;
+    switch (fTurbulenceType.fType) {
+        case SkSVGFeTurbulenceType::Type::kTurbulence:
+            shader = SkPerlinNoiseShader::MakeTurbulence(
+                    fBaseFrequency.freqX(), fBaseFrequency.freqY(), fNumOctaves, fSeed, tileSize);
+            break;
+        case SkSVGFeTurbulenceType::Type::kFractalNoise:
+            shader = SkPerlinNoiseShader::MakeFractalNoise(
+                    fBaseFrequency.freqX(), fBaseFrequency.freqY(), fNumOctaves, fSeed, tileSize);
+            break;
+    }
+
+    return SkImageFilters::Shader(shader, fctx.filterEffectsRegion());
+}