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 19sk_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 27sk_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 40SkImageSource::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 48SkImageSource::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 59sk_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 74void SkImageSource::flatten(SkWriteBuffer& buffer) const { 75 buffer.writeInt(fFilterQuality); 76 buffer.writeRect(fSrcRect); 77 buffer.writeRect(fDstRect); 78 buffer.writeImage(fImage.get()); 79} 80 81sk_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 135sk_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 145SkRect SkImageSource::computeFastBounds(const SkRect& src) const { 146 return fDstRect; 147} 148 149#ifndef SK_IGNORE_TO_STRING 150void 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