1 /* 2 * Copyright 2013 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 "SkTileImageFilter.h" 9 #include "SkBitmap.h" 10 #include "SkCanvas.h" 11 #include "SkDevice.h" 12 #include "SkOffsetImageFilter.h" 13 #include "SkReadBuffer.h" 14 #include "SkWriteBuffer.h" 15 #include "SkMatrix.h" 16 #include "SkPaint.h" 17 #include "SkShader.h" 18 #include "SkValidationUtils.h" 19 20 SkImageFilter* SkTileImageFilter::Create(const SkRect& srcRect, const SkRect& dstRect, 21 SkImageFilter* input) { 22 if (!SkIsValidRect(srcRect) || !SkIsValidRect(dstRect)) { 23 return nullptr; 24 } 25 if (srcRect.width() == dstRect.width() && srcRect.height() == dstRect.height()) { 26 SkRect ir = dstRect; 27 if (!ir.intersect(srcRect)) { 28 return SkSafeRef(input); 29 } 30 CropRect cropRect(ir); 31 return SkOffsetImageFilter::Create(dstRect.x() - srcRect.x(), 32 dstRect.y() - srcRect.y(), 33 input, &cropRect); 34 } 35 return new SkTileImageFilter(srcRect, dstRect, input); 36 } 37 38 bool SkTileImageFilter::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src, 39 const Context& ctx, 40 SkBitmap* dst, SkIPoint* offset) const { 41 SkBitmap source = src; 42 SkIPoint srcOffset = SkIPoint::Make(0, 0); 43 if (!this->filterInputDeprecated(0, proxy, src, ctx, &source, &srcOffset)) { 44 return false; 45 } 46 47 SkRect dstRect; 48 ctx.ctm().mapRect(&dstRect, fDstRect); 49 if (!dstRect.intersect(SkRect::Make(ctx.clipBounds()))) { 50 offset->fX = offset->fY = 0; 51 return true; 52 } 53 const SkIRect dstIRect = dstRect.roundOut(); 54 int w = dstIRect.width(); 55 int h = dstIRect.height(); 56 if (!fSrcRect.width() || !fSrcRect.height() || !w || !h) { 57 return false; 58 } 59 60 SkRect srcRect; 61 ctx.ctm().mapRect(&srcRect, fSrcRect); 62 SkIRect srcIRect; 63 srcRect.roundOut(&srcIRect); 64 srcIRect.offset(-srcOffset); 65 SkBitmap subset; 66 SkIRect srcBounds; 67 source.getBounds(&srcBounds); 68 69 if (!SkIRect::Intersects(srcIRect, srcBounds)) { 70 offset->fX = offset->fY = 0; 71 return true; 72 } 73 if (srcBounds.contains(srcIRect)) { 74 if (!source.extractSubset(&subset, srcIRect)) { 75 return false; 76 } 77 } else { 78 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(srcIRect.width(), 79 srcIRect.height(), 80 kPossible_TileUsage)); 81 if (!device) { 82 return false; 83 } 84 SkCanvas canvas(device); 85 canvas.drawBitmap(src, SkIntToScalar(srcOffset.x()), 86 SkIntToScalar(srcOffset.y())); 87 subset = device->accessBitmap(false); 88 } 89 SkASSERT(subset.width() == srcIRect.width()); 90 SkASSERT(subset.height() == srcIRect.height()); 91 92 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h)); 93 if (nullptr == device.get()) { 94 return false; 95 } 96 SkCanvas canvas(device); 97 SkPaint paint; 98 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 99 100 SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset, 101 SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); 102 paint.setShader(shader); 103 canvas.translate(-dstRect.fLeft, -dstRect.fTop); 104 canvas.drawRect(dstRect, paint); 105 *dst = device->accessBitmap(false); 106 offset->fX = dstIRect.fLeft; 107 offset->fY = dstIRect.fTop; 108 return true; 109 } 110 111 void SkTileImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, 112 SkIRect* dst, MapDirection direction) const { 113 SkRect rect = kReverse_MapDirection == direction ? fSrcRect : fDstRect; 114 ctm.mapRect(&rect); 115 rect.roundOut(dst); 116 } 117 118 bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 119 SkIRect* dst, MapDirection direction) const { 120 // Don't recurse into inputs. 121 *dst = src; 122 return true; 123 } 124 125 void SkTileImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 126 *dst = fDstRect; 127 } 128 129 SkFlattenable* SkTileImageFilter::CreateProc(SkReadBuffer& buffer) { 130 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 131 SkRect src, dst; 132 buffer.readRect(&src); 133 buffer.readRect(&dst); 134 return Create(src, dst, common.getInput(0)); 135 } 136 137 void SkTileImageFilter::flatten(SkWriteBuffer& buffer) const { 138 this->INHERITED::flatten(buffer); 139 buffer.writeRect(fSrcRect); 140 buffer.writeRect(fDstRect); 141 } 142 143 #ifndef SK_IGNORE_TO_STRING 144 void SkTileImageFilter::toString(SkString* str) const { 145 str->appendf("SkTileImageFilter: ("); 146 str->appendf("src: %.2f %.2f %.2f %.2f", 147 fSrcRect.fLeft, fSrcRect.fTop, fSrcRect.fRight, fSrcRect.fBottom); 148 str->appendf(" dst: %.2f %.2f %.2f %.2f", 149 fDstRect.fLeft, fDstRect.fTop, fDstRect.fRight, fDstRect.fBottom); 150 if (this->getInput(0)) { 151 str->appendf("input: ("); 152 this->getInput(0)->toString(str); 153 str->appendf(")"); 154 } 155 str->append(")"); 156 } 157 #endif 158