Home | History | Annotate | Download | only in filters
      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