GrShape GrShape::MakeFilled(const GrShape& original, FillInversion inversion) { if (original.style().isSimpleFill() && !flip_inversion(original.inverseFilled(), inversion)) { // By returning the original rather than falling through we can preserve any inherited style // key. Otherwise, we wipe it out below since the style change invalidates it. return original; } GrShape result; if (original.fInheritedPathForListeners.isValid()) { result.fInheritedPathForListeners.set(*original.fInheritedPathForListeners.get()); } switch (original.fType) { case Type::kRRect: result.fType = original.fType; result.fRRectData.fRRect = original.fRRectData.fRRect; result.fRRectData.fDir = kDefaultRRectDir; result.fRRectData.fStart = kDefaultRRectStart; result.fRRectData.fInverted = is_inverted(original.fRRectData.fInverted, inversion); break; case Type::kArc: result.fType = original.fType; result.fArcData.fOval = original.fArcData.fOval; result.fArcData.fStartAngleDegrees = original.fArcData.fStartAngleDegrees; result.fArcData.fSweepAngleDegrees = original.fArcData.fSweepAngleDegrees; result.fArcData.fUseCenter = original.fArcData.fUseCenter; result.fArcData.fInverted = is_inverted(original.fArcData.fInverted, inversion); break; case Type::kLine: // Lines don't fill. if (is_inverted(original.fLineData.fInverted, inversion)) { result.fType = Type::kInvertedEmpty; } else { result.fType = Type::kEmpty; } break; case Type::kEmpty: result.fType = is_inverted(false, inversion) ? Type::kInvertedEmpty : Type::kEmpty; break; case Type::kInvertedEmpty: result.fType = is_inverted(true, inversion) ? Type::kInvertedEmpty : Type::kEmpty; break; case Type::kPath: result.initType(Type::kPath, &original.fPathData.fPath); result.fPathData.fGenID = original.fPathData.fGenID; if (flip_inversion(original.fPathData.fPath.isInverseFillType(), inversion)) { result.fPathData.fPath.toggleInverseFillType(); } if (!original.style().isSimpleFill()) { // Going from a non-filled style to fill may allow additional simplifications (e.g. // closing an open rect that wasn't closed in the original shape because it had // stroke style). result.attemptToSimplifyPath(); } break; } // We don't copy the inherited key since it can contain path effect information that we just // stripped. return result; }
TessellatingPathBatch(const GrColor& color, const GrShape& shape, const SkMatrix& viewMatrix, const SkRect& clipBounds) : INHERITED(ClassID()) , fColor(color) , fShape(shape) , fViewMatrix(viewMatrix) { const SkRect& pathBounds = shape.bounds(); fClipBounds = clipBounds; // Because the clip bounds are used to add a contour for inverse fills, they must also // include the path bounds. fClipBounds.join(pathBounds); const SkRect& srcBounds = shape.inverseFilled() ? fClipBounds : pathBounds; this->setTransformedBounds(srcBounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); }
static inline bool single_pass_shape(const GrShape& shape) { #if STENCIL_OFF return true; #else // Inverse fill is always two pass. if (shape.inverseFilled()) { return false; } // This path renderer only accepts simple fill paths or stroke paths that are either hairline // or have a stroke width small enough to treat as hairline. Hairline paths are always single // pass. Filled paths are single pass if they're convex. if (shape.style().isSimpleFill()) { return shape.knownToBeConvex(); } return true; #endif }