blob: ec9f7749e169243302b4c172d7c6ba3b0da9a509 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_DISPLAY_LIST_DL_OP_FLAGS_H_
#define FLUTTER_DISPLAY_LIST_DL_OP_FLAGS_H_
#include "flutter/display_list/dl_paint.h"
#include "flutter/fml/logging.h"
namespace flutter {
class DlPathEffect;
/// The base class for the classes that maintain a list of
/// attributes that might be important for a number of operations
/// including which rendering attributes need to be set before
/// calling a rendering method (all |drawSomething| calls),
/// or for determining which exceptional conditions may need
/// to be accounted for in bounds calculations.
/// This class contains only protected definitions and helper methods
/// for the public classes |DisplayListAttributeFlags| and
/// |DisplayListSpecialGeometryFlags|.
class DisplayListFlags {
protected:
// A drawing operation that is not geometric in nature (but which
// may still apply a MaskFilter - see |kUsesMaskFilter| below).
static constexpr int kIsNonGeometric = 0;
// A geometric operation that is defined as a fill operation
// regardless of what the current paint Style is set to.
// This flag will automatically assume |kUsesMaskFilter|.
static constexpr int kIsFilledGeometry = 1 << 0;
// A geometric operation that is defined as a stroke operation
// regardless of what the current paint Style is set to.
// This flag will automatically assume |kUsesMaskFilter|.
static constexpr int kIsStrokedGeometry = 1 << 1;
// A geometric operation that may be a stroke or fill operation
// depending on the current state of the paint Style attribute.
// This flag will automatically assume |kUsesMaskFilter|.
static constexpr int kIsDrawnGeometry = 1 << 2;
static constexpr int kIsAnyGeometryMask = //
kIsFilledGeometry | //
kIsStrokedGeometry | //
kIsDrawnGeometry;
// A primitive that floods the surface (or clip) with no
// natural bounds, such as |drawColor| or |drawPaint|.
static constexpr int kFloodsSurface = 1 << 3;
static constexpr int kMayHaveCaps = 1 << 4;
static constexpr int kMayHaveJoins = 1 << 5;
static constexpr int kButtCapIsSquare = 1 << 6;
// A geometric operation which has a path that might have
// end caps that are not rectilinear which means that square
// end caps might project further than half the stroke width
// from the geometry bounds.
// A rectilinear path such as |drawRect| will not have
// diagonal end caps. |drawLine| might have diagonal end
// caps depending on the angle of the line, and more likely
// |drawPath| will often have such end caps.
static constexpr int kMayHaveDiagonalCaps = 1 << 7;
// A geometric operation which has joined vertices that are
// not guaranteed to be smooth (angles of incoming and outgoing)
// segments at some joins may not have the same angle) or
// rectilinear (squares have right angles at the corners, but
// those corners will never extend past the bounding box of
// the geometry pre-transform).
// |drawRect|, |drawOval| and |drawRRect| all have well
// behaved joins, but |drawPath| might have joins that cause
// mitered extensions outside the pre-transformed bounding box.
static constexpr int kMayHaveAcuteJoins = 1 << 8;
static constexpr int kAnySpecialGeometryMask = //
kMayHaveCaps | kMayHaveJoins | kButtCapIsSquare | //
kMayHaveDiagonalCaps | kMayHaveAcuteJoins;
// clang-format off
static constexpr int kUsesAntiAlias = 1 << 10;
static constexpr int kUsesAlpha = 1 << 11;
static constexpr int kUsesColor = 1 << 12;
static constexpr int kUsesBlend = 1 << 13;
static constexpr int kUsesShader = 1 << 14;
static constexpr int kUsesColorFilter = 1 << 15;
static constexpr int kUsesPathEffect = 1 << 16;
static constexpr int kUsesMaskFilter = 1 << 17;
static constexpr int kUsesImageFilter = 1 << 18;
// Some ops have an optional paint argument. If the version
// stored in the DisplayList ignores the paint, but there
// is an option to render the same op with a paint then
// both of the following flags are set to indicate that
// a default paint object can be constructed when rendering
// the op to carry information imposed from outside the
// DisplayList (for example, the opacity override).
static constexpr int kIgnoresPaint = 1 << 30;
// clang-format on
static constexpr int kAnyAttributeMask = //
kUsesAntiAlias | kUsesAlpha | kUsesColor | kUsesBlend | kUsesShader |
kUsesColorFilter | kUsesPathEffect | kUsesMaskFilter | kUsesImageFilter;
};
class DisplayListFlagsBase : protected DisplayListFlags {
protected:
explicit constexpr DisplayListFlagsBase(int flags) : flags_(flags) {}
const int flags_;
constexpr bool has_any(int qFlags) const { return (flags_ & qFlags) != 0; }
constexpr bool has_all(int qFlags) const {
return (flags_ & qFlags) == qFlags;
}
constexpr bool has_none(int qFlags) const { return (flags_ & qFlags) == 0; }
};
/// An attribute class for advertising specific properties of
/// a geometric attribute that can affect the computation of
/// the bounds of the primitive.
class DisplayListSpecialGeometryFlags : DisplayListFlagsBase {
public:
/// The geometry may have segments that end without closing the path.
constexpr bool may_have_end_caps() const { return has_any(kMayHaveCaps); }
/// The geometry may have segments connect non-continuously.
constexpr bool may_have_joins() const { return has_any(kMayHaveJoins); }
/// Mainly for drawPoints(PointMode) where Butt caps are rendered as squares.
constexpr bool butt_cap_becomes_square() const {
return has_any(kButtCapIsSquare);
}
/// The geometry may have segments that end on a diagonal
/// such that their end caps extend further than the default
/// |strokeWidth * 0.5| margin around the geometry.
constexpr bool may_have_diagonal_caps() const {
return has_any(kMayHaveDiagonalCaps);
}
/// The geometry may have segments that meet at vertices at
/// an acute angle such that the miter joins will extend
/// further than the default |strokeWidth * 0.5| margin around
/// the geometry.
constexpr bool may_have_acute_joins() const {
return has_any(kMayHaveAcuteJoins);
}
private:
explicit constexpr DisplayListSpecialGeometryFlags(int flags)
: DisplayListFlagsBase(flags) {
FML_DCHECK((flags & kAnySpecialGeometryMask) == flags);
}
const DisplayListSpecialGeometryFlags with(int extra) const {
return extra == 0 ? *this : DisplayListSpecialGeometryFlags(flags_ | extra);
}
friend class DisplayListAttributeFlags;
};
class DisplayListAttributeFlags : DisplayListFlagsBase {
public:
const DisplayListSpecialGeometryFlags WithPathEffect(
const DlPathEffect* effect,
bool is_stroked) const;
constexpr bool ignores_paint() const { return has_any(kIgnoresPaint); }
constexpr bool applies_anti_alias() const { return has_any(kUsesAntiAlias); }
constexpr bool applies_color() const { return has_any(kUsesColor); }
constexpr bool applies_alpha() const { return has_any(kUsesAlpha); }
constexpr bool applies_alpha_or_color() const {
return has_any(kUsesAlpha | kUsesColor);
}
/// The primitive dynamically determines whether it is a stroke or fill
/// operation (or both) based on the setting of the |Style| attribute.
constexpr bool applies_style() const { return has_any(kIsDrawnGeometry); }
/// The primitive can use any of the stroke attributes, such as
/// StrokeWidth, StrokeMiter, StrokeCap, or StrokeJoin. This
/// method will return if the primitive is defined as one that
/// strokes its geometry (such as |drawLine|) or if it is defined
/// as one that honors the Style attribute. If the Style attribute
/// is known then a more accurate answer can be returned from
/// the |is_stroked| method by supplying the actual setting of
/// the style.
// bool applies_stroke_attributes() const { return is_stroked(); }
constexpr bool applies_shader() const { return has_any(kUsesShader); }
/// The primitive honors the current DlColorFilter, including
/// the related attribute InvertColors
constexpr bool applies_color_filter() const {
return has_any(kUsesColorFilter);
}
/// The primitive honors the DlBlendMode
constexpr bool applies_blend() const { return has_any(kUsesBlend); }
constexpr bool applies_path_effect() const {
return has_any(kUsesPathEffect);
}
/// The primitive honors the DlMaskFilter whether set using the
/// filter object or using the convenience method |setMaskBlurFilter|
constexpr bool applies_mask_filter() const {
return has_any(kUsesMaskFilter);
}
constexpr bool applies_image_filter() const {
return has_any(kUsesImageFilter);
}
constexpr bool is_geometric() const { return has_any(kIsAnyGeometryMask); }
constexpr bool always_stroked() const { return has_any(kIsStrokedGeometry); }
constexpr bool is_stroked(DlDrawStyle style = DlDrawStyle::kStroke) const {
return (has_any(kIsStrokedGeometry) ||
(style != DlDrawStyle::kFill && has_any(kIsDrawnGeometry)));
}
constexpr bool is_flood() const { return has_any(kFloodsSurface); }
constexpr bool operator==(DisplayListAttributeFlags const& other) const {
return flags_ == other.flags_;
}
private:
explicit constexpr DisplayListAttributeFlags(int flags)
: DisplayListFlagsBase(flags),
special_flags_(flags & kAnySpecialGeometryMask) {
FML_DCHECK((flags & kIsAnyGeometryMask) == kIsNonGeometric ||
(flags & kIsAnyGeometryMask) == kIsFilledGeometry ||
(flags & kIsAnyGeometryMask) == kIsStrokedGeometry ||
(flags & kIsAnyGeometryMask) == kIsDrawnGeometry);
FML_DCHECK(((flags & kAnyAttributeMask) == 0) !=
((flags & kIgnoresPaint) == 0));
FML_DCHECK((flags & kIsAnyGeometryMask) != 0 ||
(flags & kAnySpecialGeometryMask) == 0);
}
constexpr DisplayListAttributeFlags operator+(int extra) const {
return extra == 0 ? *this : DisplayListAttributeFlags(flags_ | extra);
}
constexpr DisplayListAttributeFlags operator-(int remove) const {
FML_DCHECK(has_all(remove));
return DisplayListAttributeFlags(flags_ & ~remove);
}
const DisplayListSpecialGeometryFlags special_flags_;
friend class DisplayListOpFlags;
};
class DisplayListOpFlags : DisplayListFlags {
private:
// Flags common to all primitives that apply colors
static constexpr int kBasePaintFlags = (kUsesColor | //
kUsesAlpha | //
kUsesBlend | //
kUsesShader | //
kUsesColorFilter | //
kUsesImageFilter);
// Flags common to all primitives that stroke or fill
static constexpr int kBaseStrokeOrFillFlags = (kIsDrawnGeometry | //
kUsesAntiAlias | //
kUsesMaskFilter | //
kUsesPathEffect);
// Flags common to primitives that stroke geometry
static constexpr int kBaseStrokeFlags = (kIsStrokedGeometry | //
kUsesAntiAlias | //
kUsesMaskFilter | //
kUsesPathEffect);
// Flags common to primitives that render an image with paint attributes
static constexpr int kBaseImageFlags = (kIsNonGeometric | //
kUsesAlpha | //
kUsesBlend | //
kUsesColorFilter | //
kUsesImageFilter);
public:
static constexpr DisplayListAttributeFlags kSaveLayerFlags{
kIgnoresPaint //
};
static constexpr DisplayListAttributeFlags kSaveLayerWithPaintFlags{
kIsNonGeometric | //
kUsesAlpha | //
kUsesBlend | //
kUsesColorFilter | //
kUsesImageFilter //
};
static constexpr DisplayListAttributeFlags kDrawColorFlags{
kFloodsSurface | //
kIgnoresPaint //
};
static constexpr DisplayListAttributeFlags kDrawPaintFlags{
kBasePaintFlags | //
kFloodsSurface //
};
// Special case flags for horizonal and vertical lines
static constexpr DisplayListAttributeFlags kDrawHVLineFlags{
kBasePaintFlags | //
kBaseStrokeFlags | //
kMayHaveCaps //
};
static constexpr DisplayListAttributeFlags kDrawLineFlags{
kDrawHVLineFlags //
+ kMayHaveDiagonalCaps //
};
static constexpr DisplayListAttributeFlags kDrawRectFlags{
kBasePaintFlags | //
kBaseStrokeOrFillFlags | //
kMayHaveJoins //
};
static constexpr DisplayListAttributeFlags kDrawOvalFlags{
kBasePaintFlags | //
kBaseStrokeOrFillFlags //
};
static constexpr DisplayListAttributeFlags kDrawCircleFlags{
kBasePaintFlags | //
kBaseStrokeOrFillFlags //
};
static constexpr DisplayListAttributeFlags kDrawRRectFlags{
kBasePaintFlags | //
kBaseStrokeOrFillFlags //
};
static constexpr DisplayListAttributeFlags kDrawDRRectFlags{
kBasePaintFlags | //
kBaseStrokeOrFillFlags //
};
static constexpr DisplayListAttributeFlags kDrawPathFlags{
kBasePaintFlags | //
kBaseStrokeOrFillFlags | //
kMayHaveCaps | //
kMayHaveDiagonalCaps | //
kMayHaveJoins | //
kMayHaveAcuteJoins //
};
static constexpr DisplayListAttributeFlags kDrawArcNoCenterFlags{
kBasePaintFlags | //
kBaseStrokeOrFillFlags | //
kMayHaveCaps | //
kMayHaveDiagonalCaps //
};
static constexpr DisplayListAttributeFlags kDrawArcWithCenterFlags{
kBasePaintFlags | //
kBaseStrokeOrFillFlags | //
kMayHaveJoins | //
kMayHaveAcuteJoins //
};
static constexpr DisplayListAttributeFlags kDrawPointsAsPointsFlags{
kBasePaintFlags | //
kBaseStrokeFlags | //
kMayHaveCaps | //
kButtCapIsSquare //
};
static constexpr DisplayListAttributeFlags kDrawPointsAsLinesFlags{
kBasePaintFlags | //
kBaseStrokeFlags | //
kMayHaveCaps | //
kMayHaveDiagonalCaps //
};
// Polygon mode just draws (count-1) separate lines, no joins
static constexpr DisplayListAttributeFlags kDrawPointsAsPolygonFlags{
kBasePaintFlags | //
kBaseStrokeFlags | //
kMayHaveCaps | //
kMayHaveDiagonalCaps //
};
static constexpr DisplayListAttributeFlags kDrawVerticesFlags{
kIsNonGeometric | //
kUsesAlpha | //
kUsesShader | //
kUsesBlend | //
kUsesColorFilter | //
kUsesImageFilter //
};
static constexpr DisplayListAttributeFlags kDrawImageFlags{
kIgnoresPaint //
};
static constexpr DisplayListAttributeFlags kDrawImageWithPaintFlags{
kBaseImageFlags | //
kUsesAntiAlias | //
kUsesMaskFilter //
};
static constexpr DisplayListAttributeFlags kDrawImageRectFlags{
kIgnoresPaint //
};
static constexpr DisplayListAttributeFlags kDrawImageRectWithPaintFlags{
kBaseImageFlags | //
kUsesAntiAlias | //
kUsesMaskFilter //
};
static constexpr DisplayListAttributeFlags kDrawImageNineFlags{
kIgnoresPaint //
};
static constexpr DisplayListAttributeFlags kDrawImageNineWithPaintFlags{
kBaseImageFlags //
};
static constexpr DisplayListAttributeFlags kDrawAtlasFlags{
kIgnoresPaint //
};
static constexpr DisplayListAttributeFlags kDrawAtlasWithPaintFlags{
kBaseImageFlags //
};
static constexpr DisplayListAttributeFlags kDrawDisplayListFlags{
kIgnoresPaint //
};
static constexpr DisplayListAttributeFlags kDrawTextBlobFlags{
DisplayListAttributeFlags(kBasePaintFlags | //
kBaseStrokeOrFillFlags | //
kMayHaveJoins) //
- kUsesAntiAlias //
};
static constexpr DisplayListAttributeFlags kDrawShadowFlags{
kIgnoresPaint //
};
};
} // namespace flutter
#endif // FLUTTER_DISPLAY_LIST_DL_OP_FLAGS_H_