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