SkDiscretePathEffect.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * Copyright 2006 The Android Open Source Project
  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/core/SkStrokeRec.h"
  9. #include "include/effects/SkDiscretePathEffect.h"
  10. #include "include/private/SkFixed.h"
  11. #include "src/core/SkPointPriv.h"
  12. #include "src/core/SkReadBuffer.h"
  13. #include "src/core/SkWriteBuffer.h"
  14. sk_sp<SkPathEffect> SkDiscretePathEffect::Make(SkScalar segLength, SkScalar deviation,
  15. uint32_t seedAssist) {
  16. if (!SkScalarIsFinite(segLength) || !SkScalarIsFinite(deviation)) {
  17. return nullptr;
  18. }
  19. if (segLength <= SK_ScalarNearlyZero) {
  20. return nullptr;
  21. }
  22. return sk_sp<SkPathEffect>(new SkDiscretePathEffect(segLength, deviation, seedAssist));
  23. }
  24. static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale) {
  25. SkVector normal = tangent;
  26. SkPointPriv::RotateCCW(&normal);
  27. normal.setLength(scale);
  28. *p += normal;
  29. }
  30. SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength,
  31. SkScalar deviation,
  32. uint32_t seedAssist)
  33. : fSegLength(segLength), fPerterb(deviation), fSeedAssist(seedAssist)
  34. {
  35. }
  36. /** \class LCGRandom
  37. Utility class that implements pseudo random 32bit numbers using a fast
  38. linear equation. Unlike rand(), this class holds its own seed (initially
  39. set to 0), so that multiple instances can be used with no side-effects.
  40. Copied from the original implementation of SkRandom. Only contains the
  41. methods used by SkDiscretePathEffect::filterPath, with methods that were
  42. not called directly moved to private.
  43. */
  44. class LCGRandom {
  45. public:
  46. LCGRandom(uint32_t seed) : fSeed(seed) {}
  47. /** Return the next pseudo random number expressed as a SkScalar
  48. in the range [-SK_Scalar1..SK_Scalar1).
  49. */
  50. SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
  51. private:
  52. /** Return the next pseudo random number as an unsigned 32bit value.
  53. */
  54. uint32_t nextU() { uint32_t r = fSeed * kMul + kAdd; fSeed = r; return r; }
  55. /** Return the next pseudo random number as a signed 32bit value.
  56. */
  57. int32_t nextS() { return (int32_t)this->nextU(); }
  58. /** Return the next pseudo random number expressed as a signed SkFixed
  59. in the range [-SK_Fixed1..SK_Fixed1).
  60. */
  61. SkFixed nextSFixed1() { return this->nextS() >> 15; }
  62. // See "Numerical Recipes in C", 1992 page 284 for these constants
  63. enum {
  64. kMul = 1664525,
  65. kAdd = 1013904223
  66. };
  67. uint32_t fSeed;
  68. };
  69. bool SkDiscretePathEffect::onFilterPath(SkPath* dst, const SkPath& src,
  70. SkStrokeRec* rec, const SkRect*) const {
  71. bool doFill = rec->isFillStyle();
  72. SkPathMeasure meas(src, doFill);
  73. /* Caller may supply their own seed assist, which by default is 0 */
  74. uint32_t seed = fSeedAssist ^ SkScalarRoundToInt(meas.getLength());
  75. LCGRandom rand(seed ^ ((seed << 16) | (seed >> 16)));
  76. SkScalar scale = fPerterb;
  77. SkPoint p;
  78. SkVector v;
  79. do {
  80. SkScalar length = meas.getLength();
  81. if (fSegLength * (2 + doFill) > length) {
  82. meas.getSegment(0, length, dst, true); // to short for us to mangle
  83. } else {
  84. int n = SkScalarRoundToInt(length / fSegLength);
  85. constexpr int kMaxReasonableIterations = 100000;
  86. n = SkTMin(n, kMaxReasonableIterations);
  87. SkScalar delta = length / n;
  88. SkScalar distance = 0;
  89. if (meas.isClosed()) {
  90. n -= 1;
  91. distance += delta/2;
  92. }
  93. if (meas.getPosTan(distance, &p, &v)) {
  94. Perterb(&p, v, rand.nextSScalar1() * scale);
  95. dst->moveTo(p);
  96. }
  97. while (--n >= 0) {
  98. distance += delta;
  99. if (meas.getPosTan(distance, &p, &v)) {
  100. Perterb(&p, v, rand.nextSScalar1() * scale);
  101. dst->lineTo(p);
  102. }
  103. }
  104. if (meas.isClosed()) {
  105. dst->close();
  106. }
  107. }
  108. } while (meas.nextContour());
  109. return true;
  110. }
  111. sk_sp<SkFlattenable> SkDiscretePathEffect::CreateProc(SkReadBuffer& buffer) {
  112. SkScalar segLength = buffer.readScalar();
  113. SkScalar perterb = buffer.readScalar();
  114. uint32_t seed = buffer.readUInt();
  115. return Make(segLength, perterb, seed);
  116. }
  117. void SkDiscretePathEffect::flatten(SkWriteBuffer& buffer) const {
  118. buffer.writeScalar(fSegLength);
  119. buffer.writeScalar(fPerterb);
  120. buffer.writeUInt(fSeedAssist);
  121. }