Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Displaylist ColorFilter objects #31491

Merged
merged 8 commits into from
Feb 17, 2022
Prev Previous commit
doc comments
  • Loading branch information
flar committed Feb 17, 2022
commit 1aa74667cffe8bb1ba4e1c2682b234e6638ab4fe
131 changes: 126 additions & 5 deletions display_list/display_list_color_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,68 @@ namespace flutter {

class DlBlendColorFilter;
class DlMatrixColorFilter;
class DlSrgbToLinearGammaColorFilter;
class DlLinearToSrgbGammaColorFilter;
class DlUnknownColorFilter;

// The DisplayList ColorFilter class. This class was designed to be:
//
// - Typed:
// Even though most references and pointers are passed around as the
// base class, a DlColorFilter::Type can be queried using the |type|
// method to determine which type of ColorFilter is being used.
//
// - Inspectable:
// Any parameters required to full specify the filtering operations are
// provided on the specific base classes.
//
// - Safely Downcast:
// For the subclasses that have specific data to query, methods |asBlend|
// and |asMatrix| are provided to safely downcast the reference for
// inspection.
//
// - Skiafiable:
// The classes override an |sk_filter| method to easily obtain a Skia
// version of the filter on demand.
//
// - Immutable:
// Neither the base class or any of the subclasses specify any mutation
// methods. Instances are often passed around as const as a reminder,
// but the classes have no mutation methods anyway.
//
// - Flat and Embeddable:
// Bulk freed + bulk compared + zero memory fragmentation.
//
// All of these classes are designed to be stored in the DisplayList
// buffer allocated in-line with the rest of the data to avoid dangling
// pointers that require explicit freeing when the DisplayList goes
// away, or that fragment the memory needed to read the operations in
// the DisplayList. Furthermore, the data in the classes can be bulk
// compared using a |memcmp| when performing a |DisplayList::Equals|.
//
// - Passed by Pointer:
// The data shared via the |Dispatcher::setColorFilter| call is stored
// in the buffer itself and so its lifetime is controlled by the
// DisplayList. That memory cannot be shared as by a |shared_ptr|
// because the memory may be freed outside the control of the shared
// pointer. Creating a shared version of the object would require a
// new instantiation which we'd like to avoid on every dispatch call,
// so a raw (const) pointer is shared instead with all of the
// responsibilities of non-ownership in the called method.
//
// But, for methods that need to keep a copy of the data...
//
// - Shared_Ptr-able:
// The classes support a method to return a |std::shared_ptr| version of
// themselves, safely instantiating a new copy of the object into a
// shared_ptr using |std::make_shared|. For those dispatcher objects
// that may want to hold on to the contents of the object (typically
// in a |current_color_filter_| field), they can obtain a shared_ptr
// copy safely and easily using the |shared| method.

class DlColorFilter {
public:
// An enumerated type for the recognized ColorFilter operations.
// If a custom ColorFilter outside of the recognized types is needed
// then a |kUnknown| type that simply defers to an SkColorFilter is
// provided as a fallback.
enum Type {
kBlend,
kMatrix,
Expand All @@ -26,40 +82,82 @@ class DlColorFilter {
kUnknown
};

// Return a shared_ptr holding a DlColorFilter representing the indicated
// Skia SkColorFilter pointer.
//
// This method can detect each of the 4 recognized types from an analogous
// SkColorFilter.
static std::shared_ptr<DlColorFilter> From(SkColorFilter* sk_filter);

// Return a shared_ptr holding a DlColorFilter representing the indicated
// Skia SkColorFilter pointer.
//
// This method can detect each of the 4 recognized types from an analogous
// SkColorFilter.
static std::shared_ptr<DlColorFilter> From(sk_sp<SkColorFilter> sk_filter) {
return From(sk_filter.get());
}

// Return the recognized type of the ColorFilter operation.
virtual Type type() const = 0;

// Return the size of the instantiated data (typically used to allocate)
// storage in the DisplayList buffer.
virtual size_t size() const = 0;

// Return a boolean indicating whether the color filtering operation will
// modify transparent black. This is typically used to determine if applying
// the ColorFilter to a temporary saveLayer buffer will turn the surrounding
// pixels non-transparent and therefore expand the bounds.
virtual bool modifies_transparent_black() const = 0;

// Return a shared version of a DlColorFilter pointer, or nullptr if the
// pointer is null.
static std::shared_ptr<DlColorFilter> Shared(const DlColorFilter* filter) {
return filter == nullptr ? nullptr : filter->shared();
}

// Return a shared version of |this| ColorFilter. The |shared_ptr| returned
// will reference a copy of this object so that the lifetime of the shared
// version is not tied to the storage of this particular instance.
virtual std::shared_ptr<DlColorFilter> shared() const = 0;

// Return an equivalent |SkColorFilter| version of this object.
virtual sk_sp<SkColorFilter> sk_filter() const = 0;

// Return a DlBlendColorFilter pointer to this object iff it is a Blend
// type of ColorFilter, otherwise return nullptr.
virtual const DlBlendColorFilter* asBlend() const { return nullptr; }

// Return a DlMatrixColorFilter pointer to this object iff it is a Matrix
// type of ColorFilter, otherwise return nullptr.
virtual const DlMatrixColorFilter* asMatrix() const { return nullptr; }

// asSrgb<->Linear and asUnknown are not needed because they
// have no properties to query. Their type fully specifies their
// operation or can be accessed via the common sk_filter() method.
virtual const DlBlendColorFilter* asBlend() const { return nullptr; }
virtual const DlMatrixColorFilter* asMatrix() const { return nullptr; }

// Perform a content aware |==| comparison of the ColorFilter.
bool operator==(DlColorFilter const& other) const {
return type() == other.type() && equals_(other);
}
// Perform a content aware |!=| comparison of the ColorFilter.
bool operator!=(DlColorFilter const& other) const {
return !(*this == other);
}

virtual ~DlColorFilter() = default;

protected:
// Virtual comparison method to support |==| and |!=|.
virtual bool equals_(DlColorFilter const& other) const = 0;
};

// The Blend type of ColorFilter which specifies modifying the
// colors as if the color specified in the Blend filter is the
// source color and the color drawn by the rendering operation
// is the destination color. The mode parameter of the Blend
// filter is then used to combine those colors.
class DlBlendColorFilter final : public DlColorFilter {
public:
DlBlendColorFilter(SkColor color, SkBlendMode mode)
Expand Down Expand Up @@ -101,6 +199,18 @@ class DlBlendColorFilter final : public DlColorFilter {
SkBlendMode mode_;
};

// The Matrix type of ColorFilter which runs every pixel drawn by
// the rendering operation [iR,iG,iB,iA] through a vector/matrix
// multiplication, as in:
//
// [ oR ] [ m[ 0] m[ 1] m[ 2] m[ 3] m[ 4] ] [ iR ]
// [ oG ] [ m[ 5] m[ 6] m[ 7] m[ 8] m[ 9] ] [ iG ]
// [ oB ] = [ m[10] m[11] m[12] m[13] m[14] ] x [ iB ]
// [ oA ] [ m[15] m[16] m[17] m[18] m[19] ] [ iA ]
// [ 1 ]
//
// The resulting color [oR,oG,oB,oA] is then clamped to the range of
// valid pixel components before storing in the output.
class DlMatrixColorFilter final : public DlColorFilter {
public:
DlMatrixColorFilter(const float matrix[20]) {
Expand Down Expand Up @@ -145,6 +255,8 @@ class DlMatrixColorFilter final : public DlColorFilter {
float matrix_[20];
};

// The SrgbToLinear type of ColorFilter that applies the inverse of the sRGB
// gamma curve to the rendered pixels.
class DlSrgbToLinearGammaColorFilter final : public DlColorFilter {
public:
static const std::shared_ptr<DlSrgbToLinearGammaColorFilter> instance;
Expand Down Expand Up @@ -173,6 +285,8 @@ class DlSrgbToLinearGammaColorFilter final : public DlColorFilter {
friend class DlColorFilter;
};

// The LinearToSrgb type of ColorFilter that applies the sRGB gamma curve
// to the rendered pixels.
class DlLinearToSrgbGammaColorFilter final : public DlColorFilter {
public:
static const std::shared_ptr<DlLinearToSrgbGammaColorFilter> instance;
Expand Down Expand Up @@ -201,6 +315,13 @@ class DlLinearToSrgbGammaColorFilter final : public DlColorFilter {
friend class DlColorFilter;
};

// A wrapper class for a Skia ColorFilter of unknown type. The above 4 types
// are the only types that can be constructed by Flutter using the
// ui.ColorFilter class so this class should be rarely used. The main use
// would come from the |DisplayListCanvasRecorder| recording Skia rendering
// calls that originated outside of the Flutter dart code. This would
// primarily happen in the Paragraph code that renders the text using the
// SkCanvas interface which we capture into DisplayList data structures.
class DlUnknownColorFilter final : public DlColorFilter {
public:
DlUnknownColorFilter(sk_sp<SkColorFilter> sk_filter)
Expand Down