| 1 | /* |
| 2 | * Copyright 2013 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 | |
| 8 | #include "include/core/SkCanvas.h" |
| 9 | #include "include/core/SkDrawLooper.h" |
| 10 | #include "include/core/SkMatrix.h" |
| 11 | #include "include/core/SkPaint.h" |
| 12 | #include "include/core/SkRect.h" |
| 13 | #include "src/core/SkArenaAlloc.h" |
| 14 | |
| 15 | void SkDrawLooper::Context::Info::applyToCTM(SkMatrix* ctm) const { |
| 16 | if (fApplyPostCTM) { |
| 17 | ctm->postTranslate(fTranslate.fX, fTranslate.fY); |
| 18 | } else { |
| 19 | ctm->preTranslate(fTranslate.fX, fTranslate.fY); |
| 20 | } |
| 21 | } |
| 22 | |
| 23 | void SkDrawLooper::Context::Info::applyToCanvas(SkCanvas* canvas) const { |
| 24 | if (fApplyPostCTM) { |
| 25 | SkMatrix ctm = canvas->getTotalMatrix(); |
| 26 | ctm.postTranslate(fTranslate.fX, fTranslate.fY); |
| 27 | canvas->setMatrix(ctm); |
| 28 | } else { |
| 29 | canvas->translate(fTranslate.fX, fTranslate.fY); |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) const { |
| 34 | SkSTArenaAlloc<48> alloc; |
| 35 | |
| 36 | SkDrawLooper::Context* context = this->makeContext(&alloc); |
| 37 | for (;;) { |
| 38 | SkPaint p(paint); |
| 39 | SkDrawLooper::Context::Info info; |
| 40 | if (context->next(&info, &p)) { |
| 41 | if (!p.canComputeFastBounds()) { |
| 42 | return false; |
| 43 | } |
| 44 | } else { |
| 45 | break; |
| 46 | } |
| 47 | } |
| 48 | return true; |
| 49 | } |
| 50 | |
| 51 | void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& s, |
| 52 | SkRect* dst) const { |
| 53 | // src and dst rects may alias and we need to keep the original src, so copy it. |
| 54 | const SkRect src = s; |
| 55 | |
| 56 | SkSTArenaAlloc<48> alloc; |
| 57 | |
| 58 | *dst = src; // catch case where there are no loops |
| 59 | SkDrawLooper::Context* context = this->makeContext(&alloc); |
| 60 | |
| 61 | for (bool firstTime = true;; firstTime = false) { |
| 62 | SkPaint p(paint); |
| 63 | SkDrawLooper::Context::Info info; |
| 64 | if (context->next(&info, &p)) { |
| 65 | SkRect r(src); |
| 66 | |
| 67 | p.computeFastBounds(r, &r); |
| 68 | r.offset(info.fTranslate.fX, info.fTranslate.fY); |
| 69 | |
| 70 | if (firstTime) { |
| 71 | *dst = r; |
| 72 | } else { |
| 73 | dst->join(r); |
| 74 | } |
| 75 | } else { |
| 76 | break; |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | bool SkDrawLooper::asABlurShadow(BlurShadowRec*) const { |
| 82 | return false; |
| 83 | } |
| 84 | |
| 85 | void SkDrawLooper::apply(SkCanvas* canvas, const SkPaint& paint, |
| 86 | std::function<void(SkCanvas*, const SkPaint&)> proc) { |
| 87 | SkSTArenaAlloc<256> alloc; |
| 88 | Context* ctx = this->makeContext(&alloc); |
| 89 | if (ctx) { |
| 90 | Context::Info info; |
| 91 | for (;;) { |
| 92 | SkPaint p = paint; |
| 93 | if (!ctx->next(&info, &p)) { |
| 94 | break; |
| 95 | } |
| 96 | canvas->save(); |
| 97 | if (info.fApplyPostCTM) { |
| 98 | SkMatrix ctm = canvas->getTotalMatrix(); |
| 99 | ctm.postTranslate(info.fTranslate.fX, info.fTranslate.fY); |
| 100 | canvas->setMatrix(ctm); |
| 101 | } else { |
| 102 | canvas->translate(info.fTranslate.fX, info.fTranslate.fY); |
| 103 | } |
| 104 | proc(canvas, p); |
| 105 | canvas->restore(); |
| 106 | } |
| 107 | } |
| 108 | } |
| 109 | |