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 "SkReadBuffer.h" 13 #include "SkWriteBuffer.h" 14 #include "SkMatrix.h" 15 #include "SkPaint.h" 16 #include "SkShader.h" 17 #include "SkValidationUtils.h" 18 19 SkTileImageFilter* SkTileImageFilter::Create(const SkRect& srcRect, const SkRect& dstRect, 20 SkImageFilter* input) { 21 if (!SkIsValidRect(srcRect) || !SkIsValidRect(dstRect)) { 22 return NULL; 23 } 24 return SkNEW_ARGS(SkTileImageFilter, (srcRect, dstRect, input)); 25 } 26 27 bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, 28 const Context& ctx, 29 SkBitmap* dst, SkIPoint* offset) const { 30 SkBitmap source = src; 31 SkImageFilter* input = getInput(0); 32 SkIPoint srcOffset = SkIPoint::Make(0, 0); 33 if (input && !input->filterImage(proxy, src, ctx, &source, &srcOffset)) { 34 return false; 35 } 36 37 SkRect dstRect; 38 ctx.ctm().mapRect(&dstRect, fDstRect); 39 const SkIRect dstIRect = dstRect.roundOut(); 40 int w = dstIRect.width(); 41 int h = dstIRect.height(); 42 if (!fSrcRect.width() || !fSrcRect.height() || !w || !h) { 43 return false; 44 } 45 46 SkRect srcRect; 47 ctx.ctm().mapRect(&srcRect, fSrcRect); 48 SkIRect srcIRect; 49 srcRect.roundOut(&srcIRect); 50 srcIRect.offset(-srcOffset); 51 SkBitmap subset; 52 SkIRect bounds; 53 source.getBounds(&bounds); 54 55 if (!srcIRect.intersect(bounds)) { 56 offset->fX = offset->fY = 0; 57 return true; 58 } else if (!source.extractSubset(&subset, srcIRect)) { 59 return false; 60 } 61 62 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(w, h)); 63 if (NULL == device.get()) { 64 return false; 65 } 66 SkCanvas canvas(device); 67 SkPaint paint; 68 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 69 70 SkMatrix shaderMatrix; 71 shaderMatrix.setTranslate(SkIntToScalar(srcOffset.fX), 72 SkIntToScalar(srcOffset.fY)); 73 SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset, 74 SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, 75 &shaderMatrix)); 76 paint.setShader(shader); 77 canvas.translate(-dstRect.fLeft, -dstRect.fTop); 78 canvas.drawRect(dstRect, paint); 79 *dst = device->accessBitmap(false); 80 offset->fX = dstIRect.fLeft; 81 offset->fY = dstIRect.fTop; 82 return true; 83 } 84 85 bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 86 SkIRect* dst) const { 87 SkRect srcRect; 88 ctm.mapRect(&srcRect, fSrcRect); 89 SkIRect srcIRect; 90 srcRect.roundOut(&srcIRect); 91 srcIRect.join(src); 92 *dst = srcIRect; 93 return true; 94 } 95 96 SkFlattenable* SkTileImageFilter::CreateProc(SkReadBuffer& buffer) { 97 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 98 SkRect src, dst; 99 buffer.readRect(&src); 100 buffer.readRect(&dst); 101 return Create(src, dst, common.getInput(0)); 102 } 103 104 void SkTileImageFilter::flatten(SkWriteBuffer& buffer) const { 105 this->INHERITED::flatten(buffer); 106 buffer.writeRect(fSrcRect); 107 buffer.writeRect(fDstRect); 108 } 109 110 #ifndef SK_IGNORE_TO_STRING 111 void SkTileImageFilter::toString(SkString* str) const { 112 str->appendf("SkTileImageFilter: ("); 113 str->append(")"); 114 } 115 #endif 116