1 /* 2 * Copyright (C) 2008 Alex Mathews <possessedpenguinbob (at) gmail.com> 3 * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org> 4 * Copyright (C) 2013 Google Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22 #include "config.h" 23 24 #include "core/platform/graphics/filters/FETile.h" 25 26 #include "SkFlattenableBuffers.h" 27 #include "SkImageFilter.h" 28 29 #include "core/platform/graphics/GraphicsContext.h" 30 #include "core/platform/graphics/Pattern.h" 31 #include "core/platform/graphics/filters/Filter.h" 32 #include "core/platform/graphics/filters/SkiaImageFilterBuilder.h" 33 #include "core/platform/graphics/transforms/AffineTransform.h" 34 #include "core/platform/text/TextStream.h" 35 #include "core/rendering/RenderTreeAsText.h" 36 #include "core/rendering/svg/SVGRenderingContext.h" 37 #include "third_party/skia/include/core/SkDevice.h" 38 39 namespace WebCore { 40 41 class TileImageFilter : public SkImageFilter { 42 public: 43 TileImageFilter(const SkRect& srcRect, const SkRect& dstRect, SkImageFilter* input) 44 : SkImageFilter(input) 45 , m_srcRect(srcRect) 46 , m_dstRect(dstRect) 47 { 48 } 49 50 virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* dst, SkIPoint* offset) 51 { 52 SkBitmap source = src; 53 SkImageFilter* input = getInput(0); 54 SkIPoint localOffset = SkIPoint::Make(0, 0); 55 if (input && !input->filterImage(proxy, src, ctm, &source, &localOffset)) 56 return false; 57 58 if (!m_srcRect.width() || !m_srcRect.height() || !m_dstRect.width() || !m_dstRect.height()) 59 return false; 60 61 SkIRect srcRect; 62 m_srcRect.roundOut(&srcRect); 63 SkBitmap subset; 64 if (!source.extractSubset(&subset, srcRect)) 65 return false; 66 67 SkAutoTUnref<SkDevice> device(proxy->createDevice(m_dstRect.width(), m_dstRect.height())); 68 SkIRect bounds; 69 source.getBounds(&bounds); 70 SkCanvas canvas(device); 71 SkPaint paint; 72 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 73 74 SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); 75 paint.setShader(shader); 76 SkRect dstRect = m_dstRect; 77 dstRect.offset(localOffset.fX, localOffset.fY); 78 canvas.drawRect(dstRect, paint); 79 *dst = device->accessBitmap(false); 80 return true; 81 } 82 83 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(TileImageFilter) 84 85 protected: 86 explicit TileImageFilter(SkFlattenableReadBuffer& buffer) 87 : SkImageFilter(buffer) 88 { 89 buffer.readRect(&m_srcRect); 90 buffer.readRect(&m_dstRect); 91 } 92 93 virtual void flatten(SkFlattenableWriteBuffer& buffer) const 94 { 95 this->SkImageFilter::flatten(buffer); 96 buffer.writeRect(m_srcRect); 97 buffer.writeRect(m_dstRect); 98 } 99 100 private: 101 SkRect m_srcRect; 102 SkRect m_dstRect; 103 }; 104 105 FETile::FETile(Filter* filter) 106 : FilterEffect(filter) 107 { 108 } 109 110 PassRefPtr<FETile> FETile::create(Filter* filter) 111 { 112 return adoptRef(new FETile(filter)); 113 } 114 115 void FETile::applySoftware() 116 { 117 FilterEffect* in = inputEffect(0); 118 119 ImageBuffer* resultImage = createImageBufferResult(); 120 if (!resultImage) 121 return; 122 123 setIsAlphaImage(in->isAlphaImage()); 124 125 // Source input needs more attention. It has the size of the filterRegion but gives the 126 // size of the cutted sourceImage back. This is part of the specification and optimization. 127 FloatRect tileRect = in->maxEffectRect(); 128 FloatPoint inMaxEffectLocation = tileRect.location(); 129 FloatPoint maxEffectLocation = maxEffectRect().location(); 130 if (in->filterEffectType() == FilterEffectTypeSourceInput) { 131 Filter* filter = this->filter(); 132 tileRect = filter->absoluteFilterRegion(); 133 tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); 134 } 135 136 OwnPtr<ImageBuffer> tileImage; 137 if (!SVGRenderingContext::createImageBufferForPattern(tileRect, tileRect, tileImage, filter()->renderingMode())) 138 return; 139 140 GraphicsContext* tileImageContext = tileImage->context(); 141 tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); 142 tileImageContext->drawImageBuffer(in->asImageBuffer(), in->absolutePaintRect().location()); 143 144 RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(CopyBackingStore), true, true); 145 146 AffineTransform patternTransform; 147 patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); 148 pattern->setPatternSpaceTransform(patternTransform); 149 GraphicsContext* filterContext = resultImage->context(); 150 filterContext->setFillPattern(pattern); 151 filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); 152 } 153 154 PassRefPtr<SkImageFilter> FETile::createImageFilter(SkiaImageFilterBuilder* builder) 155 { 156 RefPtr<SkImageFilter> input(builder->build(inputEffect(0), operatingColorSpace())); 157 FloatRect srcRect = inputEffect(0) ? inputEffect(0)->effectBoundaries() : FloatRect(); 158 return adoptRef(new TileImageFilter(srcRect, effectBoundaries(), input.get())); 159 } 160 161 TextStream& FETile::externalRepresentation(TextStream& ts, int indent) const 162 { 163 writeIndent(ts, indent); 164 ts << "[feTile"; 165 FilterEffect::externalRepresentation(ts); 166 ts << "]\n"; 167 inputEffect(0)->externalRepresentation(ts, indent + 1); 168 169 return ts; 170 } 171 172 } // namespace WebCore 173