/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrStrokeInfo_DEFINED #define GrStrokeInfo_DEFINED #include "SkPathEffect.h" #include "SkStrokeRec.h" #include "SkTemplates.h" class GrUniqueKey; /* * GrStrokeInfo encapsulates all the pertinent infomation regarding the stroke. The SkStrokeRec * which holds information on fill style, width, miter, cap, and join. It also holds information * about the dash like intervals, count, and phase. */ class GrStrokeInfo : public SkStrokeRec { public: static const GrStrokeInfo& FillInfo() { static const GrStrokeInfo gFill(kFill_InitStyle); return gFill; } GrStrokeInfo(SkStrokeRec::InitStyle style) : INHERITED(style) , fDashType(SkPathEffect::kNone_DashType) { } GrStrokeInfo(const GrStrokeInfo& src, bool includeDash = true) : INHERITED(src) { if (includeDash && src.isDashed()) { fDashType = src.fDashType; fDashPhase = src.fDashPhase; fIntervals.reset(src.getDashCount()); memcpy(fIntervals.get(), src.fIntervals.get(), fIntervals.count() * sizeof(SkScalar)); } else { fDashType = SkPathEffect::kNone_DashType; } } GrStrokeInfo(const SkPaint& paint, SkPaint::Style styleOverride) : INHERITED(paint, styleOverride) , fDashType(SkPathEffect::kNone_DashType) { this->init(paint); } explicit GrStrokeInfo(const SkPaint& paint) : INHERITED(paint) , fDashType(SkPathEffect::kNone_DashType) { this->init(paint); } GrStrokeInfo& operator=(const GrStrokeInfo& other) { if (other.isDashed()) { fDashType = other.fDashType; fDashPhase = other.fDashPhase; fIntervals.reset(other.getDashCount()); memcpy(fIntervals.get(), other.fIntervals.get(), fIntervals.count() * sizeof(SkScalar)); } else { this->removeDash(); } this->INHERITED::operator=(other); return *this; } bool hasEqualEffect(const GrStrokeInfo& other) const { if (this->isDashed() != other.isDashed()) { return false; } if (this->isDashed()) { if (fDashPhase != other.fDashPhase || fIntervals.count() != other.fIntervals.count() || memcmp(fIntervals.get(), other.fIntervals.get(), fIntervals.count() * sizeof(SkScalar)) != 0) { return false; } } return this->INHERITED::hasEqualEffect(other); } /* * This functions takes in a patheffect and updates the dashing information if the path effect * is a Dash type. Returns true if the path effect is a dashed effect and we are stroking, * otherwise it returns false. */ bool setDashInfo(const SkPathEffect* pe) { if (pe && !this->isFillStyle()) { SkPathEffect::DashInfo dashInfo; fDashType = pe->asADash(&dashInfo); if (SkPathEffect::kDash_DashType == fDashType) { fIntervals.reset(dashInfo.fCount); dashInfo.fIntervals = fIntervals.get(); pe->asADash(&dashInfo); fDashPhase = dashInfo.fPhase; return true; } } return false; } /* * Like the above, but sets with an explicit SkPathEffect::DashInfo */ bool setDashInfo(const SkPathEffect::DashInfo& info) { if (!this->isFillStyle()) { fDashType = SkPathEffect::kDash_DashType; fDashPhase = info.fPhase; fIntervals.reset(info.fCount); for (int i = 0; i < fIntervals.count(); i++) { fIntervals[i] = info.fIntervals[i]; } return true; } return false; } bool isDashed() const { return (!this->isFillStyle() && SkPathEffect::kDash_DashType == fDashType); } int32_t getDashCount() const { SkASSERT(this->isDashed()); return fIntervals.count(); } SkScalar getDashPhase() const { SkASSERT(this->isDashed()); return fDashPhase; } const SkScalar* getDashIntervals() const { SkASSERT(this->isDashed()); return fIntervals.get(); } void removeDash() { fDashType = SkPathEffect::kNone_DashType; } /** Applies the dash to a path, if the stroke info has dashing. * @return true if the dashing was applied (dst and dstStrokeInfo will be modified). * false if the stroke info did not have dashing. The dst and dstStrokeInfo * will be unmodified. The stroking in the SkStrokeRec might still * be applicable. */ bool applyDashToPath(SkPath* dst, GrStrokeInfo* dstStrokeInfo, const SkPath& src) const; /** * Computes the length of the data that will be written by asUniqueKeyFragment() function. */ int computeUniqueKeyFragmentData32Cnt() const { const int kSkScalarData32Cnt = sizeof(SkScalar) / sizeof(uint32_t); // SkStrokeRec data: 32 bits for style+join+cap and 2 scalars for miter and width. int strokeKeyData32Cnt = 1 + 2 * kSkScalarData32Cnt; if (this->isDashed()) { // One scalar for dash phase and one for each dash value. strokeKeyData32Cnt += (1 + this->getDashCount()) * kSkScalarData32Cnt; } return strokeKeyData32Cnt; } /** * Writes the object contents as uint32_t data, to be used with GrUniqueKey. * Note: the data written does not encode the length, so care must be taken to ensure * that the full unique key data is encoded properly. For example, GrStrokeInfo * fragment can be placed last in the sequence, at fixed index. */ void asUniqueKeyFragment(uint32_t*) const; private: // Prevent accidental usage, should use GrStrokeInfo::hasEqualEffect. bool hasEqualEffect(const SkStrokeRec& other) const; void init(const SkPaint& paint) { const SkPathEffect* pe = paint.getPathEffect(); this->setDashInfo(pe); } SkPathEffect::DashType fDashType; SkScalar fDashPhase; SkAutoSTArray<2, SkScalar> fIntervals; typedef SkStrokeRec INHERITED; }; #endif