1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkPathMeasure.h" 9cb93a386Sopenharmony_ci#include "include/effects/SkTrimPathEffect.h" 10cb93a386Sopenharmony_ci#include "include/private/SkTPin.h" 11cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h" 12cb93a386Sopenharmony_ci#include "src/core/SkWriteBuffer.h" 13cb93a386Sopenharmony_ci#include "src/effects/SkTrimPE.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_cinamespace { 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci// Returns the number of contours iterated to satisfy the request. 18cb93a386Sopenharmony_cistatic size_t add_segments(const SkPath& src, SkScalar start, SkScalar stop, SkPath* dst, 19cb93a386Sopenharmony_ci bool requires_moveto = true) { 20cb93a386Sopenharmony_ci SkASSERT(start < stop); 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci SkPathMeasure measure(src, false); 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci SkScalar current_segment_offset = 0; 25cb93a386Sopenharmony_ci size_t contour_count = 1; 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci do { 28cb93a386Sopenharmony_ci const auto next_offset = current_segment_offset + measure.getLength(); 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci if (start < next_offset) { 31cb93a386Sopenharmony_ci measure.getSegment(start - current_segment_offset, 32cb93a386Sopenharmony_ci stop - current_segment_offset, 33cb93a386Sopenharmony_ci dst, requires_moveto); 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci if (stop <= next_offset) 36cb93a386Sopenharmony_ci break; 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci contour_count++; 40cb93a386Sopenharmony_ci current_segment_offset = next_offset; 41cb93a386Sopenharmony_ci } while (measure.nextContour()); 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci return contour_count; 44cb93a386Sopenharmony_ci} 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci} // namespace 47cb93a386Sopenharmony_ci 48cb93a386Sopenharmony_ciSkTrimPE::SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode mode) 49cb93a386Sopenharmony_ci : fStartT(startT), fStopT(stopT), fMode(mode) {} 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_cibool SkTrimPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*, 52cb93a386Sopenharmony_ci const SkMatrix&) const { 53cb93a386Sopenharmony_ci if (fStartT >= fStopT) { 54cb93a386Sopenharmony_ci SkASSERT(fMode == SkTrimPathEffect::Mode::kNormal); 55cb93a386Sopenharmony_ci return true; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci // First pass: compute the total len. 59cb93a386Sopenharmony_ci SkScalar len = 0; 60cb93a386Sopenharmony_ci SkPathMeasure meas(src, false); 61cb93a386Sopenharmony_ci do { 62cb93a386Sopenharmony_ci len += meas.getLength(); 63cb93a386Sopenharmony_ci } while (meas.nextContour()); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci const auto arcStart = len * fStartT, 66cb93a386Sopenharmony_ci arcStop = len * fStopT; 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci // Second pass: actually add segments. 69cb93a386Sopenharmony_ci if (fMode == SkTrimPathEffect::Mode::kNormal) { 70cb93a386Sopenharmony_ci // Normal mode -> one span. 71cb93a386Sopenharmony_ci if (arcStart < arcStop) { 72cb93a386Sopenharmony_ci add_segments(src, arcStart, arcStop, dst); 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci } else { 75cb93a386Sopenharmony_ci // Inverted mode -> one logical span which wraps around at the end -> two actual spans. 76cb93a386Sopenharmony_ci // In order to preserve closed path continuity: 77cb93a386Sopenharmony_ci // 78cb93a386Sopenharmony_ci // 1) add the second/tail span first 79cb93a386Sopenharmony_ci // 80cb93a386Sopenharmony_ci // 2) skip the head span move-to for single-closed-contour paths 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci bool requires_moveto = true; 83cb93a386Sopenharmony_ci if (arcStop < len) { 84cb93a386Sopenharmony_ci // since we're adding the "tail" first, this is the total number of contours 85cb93a386Sopenharmony_ci const auto contour_count = add_segments(src, arcStop, len, dst); 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci // if the path consists of a single closed contour, we don't want to disconnect 88cb93a386Sopenharmony_ci // the two parts with a moveto. 89cb93a386Sopenharmony_ci if (contour_count == 1 && src.isLastContourClosed()) { 90cb93a386Sopenharmony_ci requires_moveto = false; 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci if (0 < arcStart) { 94cb93a386Sopenharmony_ci add_segments(src, 0, arcStart, dst, requires_moveto); 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci return true; 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_civoid SkTrimPE::flatten(SkWriteBuffer& buffer) const { 102cb93a386Sopenharmony_ci buffer.writeScalar(fStartT); 103cb93a386Sopenharmony_ci buffer.writeScalar(fStopT); 104cb93a386Sopenharmony_ci buffer.writeUInt(static_cast<uint32_t>(fMode)); 105cb93a386Sopenharmony_ci} 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_cisk_sp<SkFlattenable> SkTrimPE::CreateProc(SkReadBuffer& buffer) { 108cb93a386Sopenharmony_ci const auto start = buffer.readScalar(), 109cb93a386Sopenharmony_ci stop = buffer.readScalar(); 110cb93a386Sopenharmony_ci const auto mode = buffer.readUInt(); 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci return SkTrimPathEffect::Make(start, stop, 113cb93a386Sopenharmony_ci (mode & 1) ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal); 114cb93a386Sopenharmony_ci} 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////////////////////// 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_cisk_sp<SkPathEffect> SkTrimPathEffect::Make(SkScalar startT, SkScalar stopT, Mode mode) { 119cb93a386Sopenharmony_ci if (!SkScalarsAreFinite(startT, stopT)) { 120cb93a386Sopenharmony_ci return nullptr; 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci if (startT <= 0 && stopT >= 1 && mode == Mode::kNormal) { 124cb93a386Sopenharmony_ci return nullptr; 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci startT = SkTPin(startT, 0.f, 1.f); 128cb93a386Sopenharmony_ci stopT = SkTPin(stopT, 0.f, 1.f); 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci if (startT >= stopT && mode == Mode::kInverted) { 131cb93a386Sopenharmony_ci return nullptr; 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci return sk_sp<SkPathEffect>(new SkTrimPE(startT, stopT, mode)); 135cb93a386Sopenharmony_ci} 136