SkTrimPathEffect.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * Copyright 2018 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkPathMeasure.h"
  8. #include "include/effects/SkTrimPathEffect.h"
  9. #include "src/core/SkReadBuffer.h"
  10. #include "src/core/SkWriteBuffer.h"
  11. #include "src/effects/SkTrimPE.h"
  12. namespace {
  13. class Segmentator : public SkNoncopyable {
  14. public:
  15. Segmentator(const SkPath& src, SkPath* dst)
  16. : fMeasure(src, false)
  17. , fDst(dst) {}
  18. void add(SkScalar start, SkScalar stop) {
  19. SkASSERT(start < stop);
  20. // TODO: we appear to skip zero-length contours.
  21. do {
  22. const auto nextOffset = fCurrentSegmentOffset + fMeasure.getLength();
  23. if (start < nextOffset) {
  24. fMeasure.getSegment(start - fCurrentSegmentOffset,
  25. stop - fCurrentSegmentOffset,
  26. fDst, true);
  27. if (stop < nextOffset)
  28. break;
  29. }
  30. fCurrentSegmentOffset = nextOffset;
  31. } while (fMeasure.nextContour());
  32. }
  33. private:
  34. SkPathMeasure fMeasure;
  35. SkPath* fDst;
  36. SkScalar fCurrentSegmentOffset = 0;
  37. using INHERITED = SkNoncopyable;
  38. };
  39. } // namespace
  40. SkTrimPE::SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode mode)
  41. : fStartT(startT), fStopT(stopT), fMode(mode) {}
  42. bool SkTrimPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
  43. const SkRect* cullRect) const {
  44. if (fStartT >= fStopT) {
  45. SkASSERT(fMode == SkTrimPathEffect::Mode::kNormal);
  46. return true;
  47. }
  48. // First pass: compute the total len.
  49. SkScalar len = 0;
  50. SkPathMeasure meas(src, false);
  51. do {
  52. len += meas.getLength();
  53. } while (meas.nextContour());
  54. const auto arcStart = len * fStartT,
  55. arcStop = len * fStopT;
  56. // Second pass: actually add segments.
  57. Segmentator segmentator(src, dst);
  58. if (fMode == SkTrimPathEffect::Mode::kNormal) {
  59. if (arcStart < arcStop) segmentator.add(arcStart, arcStop);
  60. } else {
  61. if (0 < arcStart) segmentator.add(0, arcStart);
  62. if (arcStop < len) segmentator.add(arcStop, len);
  63. }
  64. return true;
  65. }
  66. void SkTrimPE::flatten(SkWriteBuffer& buffer) const {
  67. buffer.writeScalar(fStartT);
  68. buffer.writeScalar(fStopT);
  69. buffer.writeUInt(static_cast<uint32_t>(fMode));
  70. }
  71. sk_sp<SkFlattenable> SkTrimPE::CreateProc(SkReadBuffer& buffer) {
  72. const auto start = buffer.readScalar(),
  73. stop = buffer.readScalar();
  74. const auto mode = buffer.readUInt();
  75. return SkTrimPathEffect::Make(start, stop,
  76. (mode & 1) ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal);
  77. }
  78. //////////////////////////////////////////////////////////////////////////////////////////////////
  79. sk_sp<SkPathEffect> SkTrimPathEffect::Make(SkScalar startT, SkScalar stopT, Mode mode) {
  80. if (!SkScalarsAreFinite(startT, stopT)) {
  81. return nullptr;
  82. }
  83. if (startT <= 0 && stopT >= 1 && mode == Mode::kNormal) {
  84. return nullptr;
  85. }
  86. startT = SkTPin(startT, 0.f, 1.f);
  87. stopT = SkTPin(stopT, 0.f, 1.f);
  88. if (startT >= stopT && mode == Mode::kInverted) {
  89. return nullptr;
  90. }
  91. return sk_sp<SkPathEffect>(new SkTrimPE(startT, stopT, mode));
  92. }