text: /*
   * 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:
      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
  