aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Matt Sarett <msarett@google.com>2017-04-17 11:57:29 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-04-17 17:17:32 +0000
commit62745a8bba20d7ca91167915eb459339bcfb8862 (patch)
tree1765b63e0e3b8a73e154f4d866a5284ca475b314
parent1c9c13a4c1b8d52afc8974e58f60e9f4f27f1965 (diff)
Finish overriding onMakeColorSpace() for SkImageFilters
Fixes 3 gms in gbr-8888. Breaks 0 gms in gbr-8888. Bug: skia: Change-Id: I3365390b16353821ef6057a7bb68020887e36f72 Reviewed-on: https://skia-review.googlesource.com/13323 Commit-Queue: Matt Sarett <msarett@google.com> Reviewed-by: Mike Klein <mtklein@chromium.org>
-rw-r--r--gm/imagefiltersbase.cpp6
-rw-r--r--include/core/SkImageFilter.h8
-rw-r--r--src/core/SkLocalMatrixImageFilter.cpp8
-rw-r--r--src/core/SkLocalMatrixImageFilter.h1
-rw-r--r--src/core/SkMatrixImageFilter.cpp10
-rw-r--r--src/core/SkMatrixImageFilter.h1
-rw-r--r--src/effects/SkLightingImageFilter.cpp109
-rw-r--r--tests/ImageFilterTest.cpp6
-rw-r--r--tests/PDFPrimitivesTest.cpp3
9 files changed, 116 insertions, 36 deletions
diff --git a/gm/imagefiltersbase.cpp b/gm/imagefiltersbase.cpp
index 8c702b20b3..f088f67396 100644
--- a/gm/imagefiltersbase.cpp
+++ b/gm/imagefiltersbase.cpp
@@ -41,6 +41,9 @@ protected:
SkIPoint* offset) const override {
return nullptr;
}
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
+ return nullptr;
+ }
private:
typedef SkImageFilter INHERITED;
@@ -83,6 +86,9 @@ protected:
offset->set(0, 0);
return sk_ref_sp<SkSpecialImage>(source);
}
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
+ return sk_ref_sp(const_cast<IdentityImageFilter*>(this));
+ }
private:
IdentityImageFilter(sk_sp<SkImageFilter> input) : INHERITED(&input, 1, nullptr) {}
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
index ee24d96964..a6ade97b1f 100644
--- a/include/core/SkImageFilter.h
+++ b/include/core/SkImageFilter.h
@@ -406,9 +406,7 @@ protected:
sk_sp<SkImageFilter> makeColorSpace(SkColorSpaceXformer* xformer) const {
return this->onMakeColorSpace(xformer);
}
- virtual sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const {
- return sk_ref_sp(const_cast<SkImageFilter*>(this));
- }
+ virtual sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const = 0;
private:
// For makeColorSpace().
@@ -418,14 +416,18 @@ private:
friend class SkColorFilterImageFilter;
friend class SkColorSpaceXformer;
friend class SkComposeImageFilter;
+ friend class SkDiffuseLightingImageFilter;
friend class SkDisplacementMapEffect;
friend class SkDropShadowImageFilter;
friend class SkImageSource;
friend class SkMagnifierImageFilter;
friend class SkMatrixConvolutionImageFilter;
+ friend class SkMatrixImageFilter;
+ friend class SkLocalMatrixImageFilter;
friend class SkMergeImageFilter;
friend class SkMorphologyImageFilter;
friend class SkOffsetImageFilter;
+ friend class SkSpecularLightingImageFilter;
friend class SkTileImageFilter;
friend class SkXfermodeImageFilter_Base;
diff --git a/src/core/SkLocalMatrixImageFilter.cpp b/src/core/SkLocalMatrixImageFilter.cpp
index 864b24b0fc..1e50101e01 100644
--- a/src/core/SkLocalMatrixImageFilter.cpp
+++ b/src/core/SkLocalMatrixImageFilter.cpp
@@ -55,6 +55,14 @@ SkIRect SkLocalMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMat
return this->getInput(0)->filterBounds(src, SkMatrix::Concat(matrix, fLocalM), direction);
}
+sk_sp<SkImageFilter> SkLocalMatrixImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer)
+const {
+ SkASSERT(1 == this->countInputs() && this->getInput(0));
+
+ sk_sp<SkImageFilter> input = this->getInput(0)->makeColorSpace(xformer);
+ return SkLocalMatrixImageFilter::Make(fLocalM, std::move(input));
+}
+
#ifndef SK_IGNORE_TO_STRING
void SkLocalMatrixImageFilter::toString(SkString* str) const {
str->append("SkLocalMatrixImageFilter: (");
diff --git a/src/core/SkLocalMatrixImageFilter.h b/src/core/SkLocalMatrixImageFilter.h
index 5d69a20f3f..b19c065bd1 100644
--- a/src/core/SkLocalMatrixImageFilter.h
+++ b/src/core/SkLocalMatrixImageFilter.h
@@ -25,6 +25,7 @@ protected:
void flatten(SkWriteBuffer&) const override;
sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
SkIPoint* offset) const override;
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override;
SkIRect onFilterBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override;
private:
diff --git a/src/core/SkMatrixImageFilter.cpp b/src/core/SkMatrixImageFilter.cpp
index 0a33280414..4d9ea215e4 100644
--- a/src/core/SkMatrixImageFilter.cpp
+++ b/src/core/SkMatrixImageFilter.cpp
@@ -95,6 +95,16 @@ sk_sp<SkSpecialImage> SkMatrixImageFilter::onFilterImage(SkSpecialImage* source,
return surf->makeImageSnapshot();
}
+sk_sp<SkImageFilter> SkMatrixImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
+ SkASSERT(1 == this->countInputs());
+ if (!this->getInput(0)) {
+ return sk_ref_sp(const_cast<SkMatrixImageFilter*>(this));
+ }
+
+ sk_sp<SkImageFilter> input = this->getInput(0)->makeColorSpace(xformer);
+ return SkMatrixImageFilter::Make(fTransform, fFilterQuality, std::move(input));
+}
+
SkRect SkMatrixImageFilter::computeFastBounds(const SkRect& src) const {
SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src;
SkRect dst;
diff --git a/src/core/SkMatrixImageFilter.h b/src/core/SkMatrixImageFilter.h
index f6880877c0..3b451a4904 100644
--- a/src/core/SkMatrixImageFilter.h
+++ b/src/core/SkMatrixImageFilter.h
@@ -42,6 +42,7 @@ protected:
sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
SkIPoint* offset) const override;
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override;
SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override;
private:
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 5933cffd2a..cd2a36e7d7 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -8,6 +8,7 @@
#include "SkLightingImageFilter.h"
#include "SkBitmap.h"
#include "SkColorPriv.h"
+#include "SkColorSpaceXformer.h"
#include "SkPoint3.h"
#include "SkReadBuffer.h"
#include "SkSpecialImage.h"
@@ -38,28 +39,26 @@ class GrGLSpecularLightingEffect;
typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
#endif
-namespace {
-
const SkScalar gOneThird = SkIntToScalar(1) / 3;
const SkScalar gTwoThirds = SkIntToScalar(2) / 3;
const SkScalar gOneHalf = 0.5f;
const SkScalar gOneQuarter = 0.25f;
#if SK_SUPPORT_GPU
-void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
- const SkPoint3& point) {
+static void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
+ const SkPoint3& point) {
GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(float));
pdman.set3fv(uni, 1, &point.fX);
}
-void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
- const SkPoint3& point) {
+static void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni,
+ const SkPoint3& point) {
setUniformPoint3(pdman, uni, point);
}
#endif
// Shift matrix components to the left, as we advance pixels to the right.
-inline void shiftMatrixLeft(int m[9]) {
+static inline void shiftMatrixLeft(int m[9]) {
m[0] = m[1];
m[3] = m[4];
m[6] = m[7];
@@ -121,66 +120,66 @@ private:
SkScalar fShininess;
};
-inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
+static inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
return (-a + b - 2 * c + 2 * d -e + f) * scale;
}
-inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
+static inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
SkPoint3 vector = SkPoint3::Make(-x * surfaceScale, -y * surfaceScale, 1);
fast_normalize(&vector);
return vector;
}
-inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
surfaceScale);
}
-inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
surfaceScale);
}
-inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
surfaceScale);
}
-inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
surfaceScale);
}
-inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
surfaceScale);
}
-inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
surfaceScale);
}
-inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
surfaceScale);
}
-inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
surfaceScale);
}
-inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
+static inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
surfaceScale);
@@ -207,7 +206,7 @@ public:
};
template <class LightingType, class LightType, class PixelFetcher>
-void lightBitmap(const LightingType& lightingType,
+static void lightBitmap(const LightingType& lightingType,
const SkImageFilterLight* light,
const SkBitmap& src,
SkBitmap* dst,
@@ -299,7 +298,7 @@ void lightBitmap(const LightingType& lightingType,
}
template <class LightingType, class LightType>
-void lightBitmap(const LightingType& lightingType,
+static void lightBitmap(const LightingType& lightingType,
const SkImageFilterLight* light,
const SkBitmap& src,
SkBitmap* dst,
@@ -314,7 +313,7 @@ void lightBitmap(const LightingType& lightingType,
}
}
-SkPoint3 readPoint3(SkReadBuffer& buffer) {
+static SkPoint3 readPoint3(SkReadBuffer& buffer) {
SkPoint3 point;
point.fX = buffer.readScalar();
point.fY = buffer.readScalar();
@@ -325,7 +324,7 @@ SkPoint3 readPoint3(SkReadBuffer& buffer) {
return point;
};
-void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
+static void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
buffer.writeScalar(point.fX);
buffer.writeScalar(point.fY);
buffer.writeScalar(point.fZ);
@@ -490,6 +489,7 @@ protected:
sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
SkIPoint* offset) const override;
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override;
#if SK_SUPPORT_GPU
sk_sp<GrFragmentProcessor> makeFragmentProcessor(GrResourceProvider*, sk_sp<GrTextureProxy>,
@@ -526,6 +526,7 @@ protected:
sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
SkIPoint* offset) const override;
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override;
#if SK_SUPPORT_GPU
sk_sp<GrFragmentProcessor> makeFragmentProcessor(GrResourceProvider*, sk_sp<GrTextureProxy>,
@@ -752,8 +753,6 @@ class GrGLLight;
#endif
-};
-
///////////////////////////////////////////////////////////////////////////////
class SkImageFilterLight : public SkRefCnt {
@@ -771,6 +770,8 @@ public:
}
virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0;
+ virtual sk_sp<SkImageFilterLight> makeColorSpace(SkColorSpaceXformer*) const = 0;
+
// Defined below SkLight's subclasses.
void flattenLight(SkWriteBuffer& buffer) const;
static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer);
@@ -797,6 +798,14 @@ private:
///////////////////////////////////////////////////////////////////////////////
+static SkColor xform_color(const SkPoint3& color, SkColorSpaceXformer* xformer) {
+ SkColor origColor = SkColorSetARGBInline(0xFF,
+ SkScalarRoundToInt(color.fX),
+ SkScalarRoundToInt(color.fY),
+ SkScalarRoundToInt(color.fZ));
+ return xformer->apply(origColor);
+}
+
class SkDistantLight : public SkImageFilterLight {
public:
SkDistantLight(const SkPoint3& direction, SkColor color)
@@ -818,6 +827,10 @@ public:
#endif
}
+ sk_sp<SkImageFilterLight> makeColorSpace(SkColorSpaceXformer* xformer) const override {
+ return sk_make_sp<SkDistantLight>(fDirection, xform_color(this->color(), xformer));
+ }
+
bool isEqual(const SkImageFilterLight& other) const override {
if (other.type() != kDistant_LightType) {
return false;
@@ -874,6 +887,11 @@ public:
return nullptr;
#endif
}
+
+ sk_sp<SkImageFilterLight> makeColorSpace(SkColorSpaceXformer* xformer) const override {
+ return sk_make_sp<SkPointLight>(fLocation, xform_color(this->color(), xformer));
+ }
+
bool isEqual(const SkImageFilterLight& other) const override {
if (other.type() != kPoint_LightType) {
return false;
@@ -923,7 +941,8 @@ public:
: INHERITED(color),
fLocation(location),
fTarget(target),
- fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
+ fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax)),
+ fCutoffAngle(cutoffAngle)
{
fS = target - location;
fast_normalize(&fS);
@@ -933,6 +952,11 @@ public:
fConeScale = SkScalarInvert(antiAliasThreshold);
}
+ sk_sp<SkImageFilterLight> makeColorSpace(SkColorSpaceXformer* xformer) const override {
+ return sk_make_sp<SkSpotLight>(fLocation, fTarget, fSpecularExponent, fCutoffAngle,
+ xform_color(this->color(), xformer));
+ }
+
SkImageFilterLight* transform(const SkMatrix& matrix) const override {
SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
matrix.mapPoints(&location2, 1);
@@ -1056,6 +1080,7 @@ private:
SkPoint3 fLocation;
SkPoint3 fTarget;
SkScalar fSpecularExponent;
+ SkScalar fCutoffAngle;
SkScalar fCosOuterConeAngle;
SkScalar fCosInnerConeAngle;
SkScalar fConeScale;
@@ -1326,6 +1351,16 @@ sk_sp<SkSpecialImage> SkDiffuseLightingImageFilter::onFilterImage(SkSpecialImage
dst);
}
+sk_sp<SkImageFilter> SkDiffuseLightingImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer)
+const {
+ SkASSERT(1 == this->countInputs());
+ sk_sp<SkImageFilter> input =
+ this->getInput(0) ? this->getInput(0)->onMakeColorSpace(xformer) : nullptr;
+ return SkDiffuseLightingImageFilter::Make(this->light()->makeColorSpace(xformer),
+ 255.0f * this->surfaceScale(), fKD, std::move(input),
+ this->getCropRectIfSet());
+}
+
#ifndef SK_IGNORE_TO_STRING
void SkDiffuseLightingImageFilter::toString(SkString* str) const {
str->appendf("SkDiffuseLightingImageFilter: (");
@@ -1490,6 +1525,17 @@ sk_sp<SkSpecialImage> SkSpecularLightingImageFilter::onFilterImage(SkSpecialImag
return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst);
}
+sk_sp<SkImageFilter> SkSpecularLightingImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer)
+const {
+ SkASSERT(1 == this->countInputs());
+
+ sk_sp<SkImageFilter> input =
+ this->getInput(0) ? this->getInput(0)->onMakeColorSpace(xformer) : nullptr;
+ return SkSpecularLightingImageFilter::Make(this->light()->makeColorSpace(xformer),
+ 255.0f * this->surfaceScale(), fKS, fShininess,
+ std::move(input), this->getCropRectIfSet());
+}
+
#ifndef SK_IGNORE_TO_STRING
void SkSpecularLightingImageFilter::toString(SkString* str) const {
str->appendf("SkSpecularLightingImageFilter: (");
@@ -1516,14 +1562,13 @@ sk_sp<GrFragmentProcessor> SkSpecularLightingImageFilter::makeFragmentProcessor(
#if SK_SUPPORT_GPU
-namespace {
-SkPoint3 random_point3(SkRandom* random) {
+static SkPoint3 random_point3(SkRandom* random) {
return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()),
SkScalarToFloat(random->nextSScalar1()),
SkScalarToFloat(random->nextSScalar1()));
}
-SkImageFilterLight* create_random_light(SkRandom* random) {
+static SkImageFilterLight* create_random_light(SkRandom* random) {
int type = random->nextULessThan(3);
switch (type) {
case 0: {
@@ -1542,9 +1587,9 @@ SkImageFilterLight* create_random_light(SkRandom* random) {
}
}
-SkString emitNormalFunc(BoundaryMode mode,
- const char* pointToNormalName,
- const char* sobelFuncName) {
+static SkString emitNormalFunc(BoundaryMode mode,
+ const char* pointToNormalName,
+ const char* sobelFuncName) {
SkString result;
switch (mode) {
case kTopLeft_BoundaryMode:
@@ -1617,8 +1662,6 @@ SkString emitNormalFunc(BoundaryMode mode,
return result;
}
-}
-
class GrGLLightingEffect : public GrGLSLFragmentProcessor {
public:
GrGLLightingEffect() : fLight(nullptr) { }
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index 5d959d16dd..56cd5d5250 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -63,6 +63,9 @@ protected:
offset->fX = offset->fY = 0;
return sk_ref_sp<SkSpecialImage>(source);
}
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
+ return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
+ }
void flatten(SkWriteBuffer& buffer) const override {
SkDEBUGFAIL("Should never get here");
@@ -90,6 +93,9 @@ public:
SkIPoint* offset) const override {
return nullptr;
}
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
+ return nullptr;
+ }
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index de9af07d2f..766bbefec2 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -366,6 +366,9 @@ protected:
offset->fX = offset->fY = 0;
return sk_ref_sp<SkSpecialImage>(source);
}
+ sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
+ return sk_ref_sp(const_cast<DummyImageFilter*>(this));
+ }
private:
DummyImageFilter(bool visited) : INHERITED(nullptr, 0, nullptr), fVisited(visited) {}