| /* | 
 |  * Copyright 2006 The Android Open Source Project | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 |  | 
 | #include "include/core/SkPath.h" | 
 | #include "include/core/SkRegion.h" | 
 | #include "include/core/SkStrokeRec.h" | 
 | #include "include/effects/Sk2DPathEffect.h" | 
 | #include "src/core/SkReadBuffer.h" | 
 | #include "src/core/SkWriteBuffer.h" | 
 |  | 
 | Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) { | 
 |     // Calling invert will set the type mask on both matrices, making them thread safe. | 
 |     fMatrixIsInvertible = fMatrix.invert(&fInverse); | 
 | } | 
 |  | 
 | bool Sk2DPathEffect::onFilterPath(SkPath* dst, const SkPath& src, | 
 |                                   SkStrokeRec*, const SkRect*) const { | 
 |     if (!fMatrixIsInvertible) { | 
 |         return false; | 
 |     } | 
 |  | 
 |     SkPath  tmp; | 
 |     SkIRect ir; | 
 |  | 
 |     src.transform(fInverse, &tmp); | 
 |     tmp.getBounds().round(&ir); | 
 |     if (!ir.isEmpty()) { | 
 |         this->begin(ir, dst); | 
 |  | 
 |         SkRegion rgn; | 
 |         rgn.setPath(tmp, SkRegion(ir)); | 
 |         SkRegion::Iterator iter(rgn); | 
 |         for (; !iter.done(); iter.next()) { | 
 |             const SkIRect& rect = iter.rect(); | 
 |             for (int y = rect.fTop; y < rect.fBottom; ++y) { | 
 |                 this->nextSpan(rect.fLeft, y, rect.width(), dst); | 
 |             } | 
 |         } | 
 |  | 
 |         this->end(dst); | 
 |     } | 
 |     return true; | 
 | } | 
 |  | 
 | void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path) const { | 
 |     if (!fMatrixIsInvertible) { | 
 |         return; | 
 |     } | 
 | #if defined(SK_BUILD_FOR_FUZZER) | 
 |     if (count > 100) { | 
 |         return; | 
 |     } | 
 | #endif | 
 |  | 
 |     const SkMatrix& mat = this->getMatrix(); | 
 |     SkPoint src, dst; | 
 |  | 
 |     src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf); | 
 |     do { | 
 |         mat.mapPoints(&dst, &src, 1); | 
 |         this->next(dst, x++, y, path); | 
 |         src.fX += SK_Scalar1; | 
 |     } while (--count > 0); | 
 | } | 
 |  | 
 | void Sk2DPathEffect::begin(const SkIRect& uvBounds, SkPath* dst) const {} | 
 | void Sk2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) const {} | 
 | void Sk2DPathEffect::end(SkPath* dst) const {} | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | void Sk2DPathEffect::flatten(SkWriteBuffer& buffer) const { | 
 |     this->INHERITED::flatten(buffer); | 
 |     buffer.writeMatrix(fMatrix); | 
 | } | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | bool SkLine2DPathEffect::onFilterPath(SkPath* dst, const SkPath& src, | 
 |                                       SkStrokeRec* rec, const SkRect* cullRect) const { | 
 |     if (this->INHERITED::onFilterPath(dst, src, rec, cullRect)) { | 
 |         rec->setStrokeStyle(fWidth); | 
 |         return true; | 
 |     } | 
 |     return false; | 
 | } | 
 |  | 
 | void SkLine2DPathEffect::nextSpan(int u, int v, int ucount, SkPath* dst) const { | 
 |     if (ucount > 1) { | 
 |         SkPoint    src[2], dstP[2]; | 
 |  | 
 |         src[0].set(SkIntToScalar(u) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf); | 
 |         src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf, SkIntToScalar(v) + SK_ScalarHalf); | 
 |         this->getMatrix().mapPoints(dstP, src, 2); | 
 |  | 
 |         dst->moveTo(dstP[0]); | 
 |         dst->lineTo(dstP[1]); | 
 |     } | 
 | } | 
 |  | 
 | sk_sp<SkFlattenable> SkLine2DPathEffect::CreateProc(SkReadBuffer& buffer) { | 
 |     SkMatrix matrix; | 
 |     buffer.readMatrix(&matrix); | 
 |     SkScalar width = buffer.readScalar(); | 
 |     return SkLine2DPathEffect::Make(width, matrix); | 
 | } | 
 |  | 
 | void SkLine2DPathEffect::flatten(SkWriteBuffer &buffer) const { | 
 |     buffer.writeMatrix(this->getMatrix()); | 
 |     buffer.writeScalar(fWidth); | 
 | } | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | SkPath2DPathEffect::SkPath2DPathEffect(const SkMatrix& m, const SkPath& p) | 
 |     : INHERITED(m), fPath(p) { | 
 | } | 
 |  | 
 | sk_sp<SkFlattenable> SkPath2DPathEffect::CreateProc(SkReadBuffer& buffer) { | 
 |     SkMatrix matrix; | 
 |     buffer.readMatrix(&matrix); | 
 |     SkPath path; | 
 |     buffer.readPath(&path); | 
 |     return SkPath2DPathEffect::Make(matrix, path); | 
 | } | 
 |  | 
 | void SkPath2DPathEffect::flatten(SkWriteBuffer& buffer) const { | 
 |     buffer.writeMatrix(this->getMatrix()); | 
 |     buffer.writePath(fPath); | 
 | } | 
 |  | 
 | void SkPath2DPathEffect::next(const SkPoint& loc, int u, int v, | 
 |                               SkPath* dst) const { | 
 |     dst->addPath(fPath, loc.fX, loc.fY); | 
 | } |