1/*
2 * Copyright 2016 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/effects/SkPaintImageFilter.h"
9
10#include "include/core/SkCanvas.h"
11#include "include/core/SkPaint.h"
12#include "src/core/SkImageFilter_Base.h"
13#include "src/core/SkReadBuffer.h"
14#include "src/core/SkSpecialImage.h"
15#include "src/core/SkSpecialSurface.h"
16#include "src/core/SkWriteBuffer.h"
17
18namespace {
19
20class SkPaintImageFilterImpl final : public SkImageFilter_Base {
21public:
22 SkPaintImageFilterImpl(const SkPaint& paint, const CropRect* rect)
23 : INHERITED(nullptr, 0, rect)
24 , fPaint(paint) {}
25
26 bool affectsTransparentBlack() const override;
27
28protected:
29 void flatten(SkWriteBuffer&) const override;
30 sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
31
32private:
33 friend void SkPaintImageFilter::RegisterFlattenables();
34 SK_FLATTENABLE_HOOKS(SkPaintImageFilterImpl)
35
36 SkPaint fPaint;
37
38 typedef SkImageFilter_Base INHERITED;
39};
40
41} // end namespace
42
43sk_sp<SkImageFilter> SkPaintImageFilter::Make(const SkPaint& paint,
44 const SkImageFilter::CropRect* cropRect) {
45 return sk_sp<SkImageFilter>(new SkPaintImageFilterImpl(paint, cropRect));
46}
47
48void SkPaintImageFilter::RegisterFlattenables() {
49 SK_REGISTER_FLATTENABLE(SkPaintImageFilterImpl);
50 // TODO (michaelludwig) - Remove after grace period for SKPs to stop using old name
51 SkFlattenable::Register("SkPaintImageFilter", SkPaintImageFilterImpl::CreateProc);
52}
53
54///////////////////////////////////////////////////////////////////////////////////////////////////
55
56sk_sp<SkFlattenable> SkPaintImageFilterImpl::CreateProc(SkReadBuffer& buffer) {
57 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
58 SkPaint paint;
59 buffer.readPaint(&paint, nullptr);
60 return SkPaintImageFilter::Make(paint, &common.cropRect());
61}
62
63void SkPaintImageFilterImpl::flatten(SkWriteBuffer& buffer) const {
64 this->INHERITED::flatten(buffer);
65 buffer.writePaint(fPaint);
66}
67
68sk_sp<SkSpecialImage> SkPaintImageFilterImpl::onFilterImage(const Context& ctx,
69 SkIPoint* offset) const {
70 SkIRect bounds;
71 const SkIRect srcBounds = SkIRect::MakeWH(ctx.sourceImage()->width(),
72 ctx.sourceImage()->height());
73 if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
74 return nullptr;
75 }
76
77 sk_sp<SkSpecialSurface> surf(ctx.makeSurface(bounds.size()));
78 if (!surf) {
79 return nullptr;
80 }
81
82 SkCanvas* canvas = surf->getCanvas();
83 SkASSERT(canvas);
84
85 canvas->clear(0x0);
86
87 SkMatrix matrix(ctx.ctm());
88 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
89 SkRect rect = SkRect::MakeIWH(bounds.width(), bounds.height());
90 SkMatrix inverse;
91 if (matrix.invert(&inverse)) {
92 inverse.mapRect(&rect);
93 }
94 canvas->setMatrix(matrix);
95 if (rect.isFinite()) {
96 canvas->drawRect(rect, fPaint);
97 }
98
99 offset->fX = bounds.fLeft;
100 offset->fY = bounds.fTop;
101 return surf->makeImageSnapshot();
102}
103
104bool SkPaintImageFilterImpl::affectsTransparentBlack() const {
105 return true;
106}
107