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
149 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const150 void SkImageSource::toString(SkString* str) const {
151 str->appendf("SkImageSource: (");
152 str->appendf("src: (%f,%f,%f,%f) dst: (%f,%f,%f,%f) ",
153 fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom,
154 fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom);
155 str->appendf("image: (%d,%d)",
156 fImage->width(), fImage->height());
157 str->append(")");
158 }
159 #endif
160