1 /*
2  * Copyright 2015 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 "SkImageSource.h"
9 
10 #include "SkCanvas.h"
11 #include "SkColorSpaceXformer.h"
12 #include "SkImage.h"
13 #include "SkReadBuffer.h"
14 #include "SkSpecialImage.h"
15 #include "SkSpecialSurface.h"
16 #include "SkWriteBuffer.h"
17 #include "SkString.h"
18 
Make(sk_sp<SkImage> image)19 sk_sp<SkImageFilter> SkImageSource::Make(sk_sp<SkImage> image) {
20     if (!image) {
21         return nullptr;
22     }
23 
24     return sk_sp<SkImageFilter>(new SkImageSource(std::move(image)));
25 }
26 
Make(sk_sp<SkImage> image,const SkRect & srcRect,const SkRect & dstRect,SkFilterQuality filterQuality)27 sk_sp<SkImageFilter> SkImageSource::Make(sk_sp<SkImage> image,
28                                          const SkRect& srcRect,
29                                          const SkRect& dstRect,
30                                          SkFilterQuality filterQuality) {
31     if (!image || srcRect.width() <= 0.0f || srcRect.height() <= 0.0f) {
32         return nullptr;
33     }
34 
35     return sk_sp<SkImageFilter>(new SkImageSource(std::move(image),
36                                                   srcRect, dstRect,
37                                                   filterQuality));
38 }
39 
SkImageSource(sk_sp<SkImage> image)40 SkImageSource::SkImageSource(sk_sp<SkImage> image)
41     : INHERITED(nullptr, 0, nullptr)
42     , fImage(std::move(image))
43     , fSrcRect(SkRect::MakeIWH(fImage->width(), fImage->height()))
44     , fDstRect(fSrcRect)
45     , fFilterQuality(kHigh_SkFilterQuality) {
46 }
47 
SkImageSource(sk_sp<SkImage> image,const SkRect & srcRect,const SkRect & dstRect,SkFilterQuality filterQuality)48 SkImageSource::SkImageSource(sk_sp<SkImage> image,
49                              const SkRect& srcRect,
50                              const SkRect& dstRect,
51                              SkFilterQuality filterQuality)
52     : INHERITED(nullptr, 0, nullptr)
53     , fImage(std::move(image))
54     , fSrcRect(srcRect)
55     , fDstRect(dstRect)
56     , fFilterQuality(filterQuality) {
57 }
58 
CreateProc(SkReadBuffer & buffer)59 sk_sp<SkFlattenable> SkImageSource::CreateProc(SkReadBuffer& buffer) {
60     SkFilterQuality filterQuality = (SkFilterQuality)buffer.readInt();
61 
62     SkRect src, dst;
63     buffer.readRect(&src);
64     buffer.readRect(&dst);
65 
66     sk_sp<SkImage> image(buffer.readImage());
67     if (!image) {
68         return nullptr;
69     }
70 
71     return SkImageSource::Make(std::move(image), src, dst, filterQuality);
72 }
73 
flatten(SkWriteBuffer & buffer) const74 void SkImageSource::flatten(SkWriteBuffer& buffer) const {
75     buffer.writeInt(fFilterQuality);
76     buffer.writeRect(fSrcRect);
77     buffer.writeRect(fDstRect);
78     buffer.writeImage(fImage.get());
79 }
80 
onFilterImage(SkSpecialImage * source,const Context & ctx,SkIPoint * offset) const81 sk_sp<SkSpecialImage> SkImageSource::onFilterImage(SkSpecialImage* source, const Context& ctx,
82                                                    SkIPoint* offset) const {
83     SkRect dstRect;
84     ctx.ctm().mapRect(&dstRect, fDstRect);
85 
86     SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height());
87     if (fSrcRect == bounds) {
88         int iLeft = dstRect.fLeft;
89         int iTop = dstRect.fTop;
90         // TODO: this seems to be a very noise-prone way to determine this (esp. the floating-point
91         // widths & heights).
92         if (dstRect.width() == bounds.width() && dstRect.height() == bounds.height() &&
93             iLeft == dstRect.fLeft && iTop == dstRect.fTop) {
94             // The dest is just an un-scaled integer translation of the entire image; return it
95             offset->fX = iLeft;
96             offset->fY = iTop;
97 
98             return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(fImage->width(), fImage->height()),
99                                                  fImage, ctx.outputProperties().colorSpace(),
100                                                  &source->props());
101         }
102     }
103 
104     const SkIRect dstIRect = dstRect.roundOut();
105 
106     sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), dstIRect.size()));
107     if (!surf) {
108         return nullptr;
109     }
110 
111     SkCanvas* canvas = surf->getCanvas();
112     SkASSERT(canvas);
113 
114     // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075)
115     canvas->clear(0x0);
116 
117     SkPaint paint;
118 
119     // Subtract off the integer component of the translation (will be applied in offset, below).
120     dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop));
121     paint.setBlendMode(SkBlendMode::kSrc);
122     // FIXME: this probably shouldn't be necessary, but drawImageRect asserts
123     // None filtering when it's translate-only
124     paint.setFilterQuality(
125         fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ?
126                kNone_SkFilterQuality : fFilterQuality);
127     canvas->drawImageRect(fImage.get(), fSrcRect, dstRect, &paint,
128                           SkCanvas::kStrict_SrcRectConstraint);
129 
130     offset->fX = dstIRect.fLeft;
131     offset->fY = dstIRect.fTop;
132     return surf->makeImageSnapshot();
133 }
134 
onMakeColorSpace(SkColorSpaceXformer * xformer) const135 sk_sp<SkImageFilter> SkImageSource::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
136     SkASSERT(0 == this->countInputs());
137 
138     auto image = xformer->apply(fImage.get());
139     if (image != fImage) {
140         return SkImageSource::Make(image, fSrcRect, fDstRect, fFilterQuality);
141     }
142     return this->refMe();
143 }
144 
computeFastBounds(const SkRect & src) const145 SkRect SkImageSource::computeFastBounds(const SkRect& src) const {
146     return fDstRect;
147 }
148 
onFilterNodeBounds(const SkIRect & src,const SkMatrix & ctm,MapDirection direction) const149 SkIRect SkImageSource::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
150                                           MapDirection direction) const {
151     if (kReverse_MapDirection == direction) {
152         return SkImageFilter::onFilterNodeBounds(src, ctm, direction);
153     }
154 
155     SkRect dstRect = fDstRect;
156     ctm.mapRect(&dstRect);
157     return dstRect.roundOut();
158 }
159 
160 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const161 void SkImageSource::toString(SkString* str) const {
162     str->appendf("SkImageSource: (");
163     str->appendf("src: (%f,%f,%f,%f) dst: (%f,%f,%f,%f) ",
164                  fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom,
165                  fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
166     str->appendf("image: (%d,%d)",
167                  fImage->width(), fImage->height());
168     str->append(")");
169 }
170 #endif
171