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) Research In Motion Limited 2010. 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 #if ENABLE(FILTERS)
     25 #include "FilterEffect.h"
     26 
     27 #include "Filter.h"
     28 #include "ImageBuffer.h"
     29 #include "TextStream.h"
     30 #include <wtf/ByteArray.h>
     31 
     32 namespace WebCore {
     33 
     34 FilterEffect::FilterEffect(Filter* filter)
     35     : m_alphaImage(false)
     36     , m_filter(filter)
     37     , m_hasX(false)
     38     , m_hasY(false)
     39     , m_hasWidth(false)
     40     , m_hasHeight(false)
     41 {
     42     ASSERT(m_filter);
     43 }
     44 
     45 FilterEffect::~FilterEffect()
     46 {
     47 }
     48 
     49 inline bool isFilterSizeValid(IntRect rect)
     50 {
     51     if (rect.width() < 0 || rect.width() > kMaxFilterSize
     52         || rect.height() < 0 || rect.height() > kMaxFilterSize)
     53         return false;
     54     return true;
     55 }
     56 
     57 void FilterEffect::determineAbsolutePaintRect()
     58 {
     59     m_absolutePaintRect = IntRect();
     60     unsigned size = m_inputEffects.size();
     61     for (unsigned i = 0; i < size; ++i)
     62         m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect());
     63 
     64     // SVG specification wants us to clip to primitive subregion.
     65     m_absolutePaintRect.intersect(enclosingIntRect(m_maxEffectRect));
     66 }
     67 
     68 IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const
     69 {
     70     ASSERT(hasResult());
     71     IntPoint location = m_absolutePaintRect.location();
     72     location.move(-effectRect.x(), -effectRect.y());
     73     return IntRect(location, m_absolutePaintRect.size());
     74 }
     75 
     76 IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const
     77 {
     78     return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(),
     79                             srcRect.y() - m_absolutePaintRect.y()), srcRect.size());
     80 }
     81 
     82 FilterEffect* FilterEffect::inputEffect(unsigned number) const
     83 {
     84     ASSERT(number < m_inputEffects.size());
     85     return m_inputEffects.at(number).get();
     86 }
     87 
     88 void FilterEffect::clearResult()
     89 {
     90     if (m_imageBufferResult)
     91         m_imageBufferResult.clear();
     92     if (m_unmultipliedImageResult)
     93         m_unmultipliedImageResult.clear();
     94     if (m_premultipliedImageResult)
     95         m_premultipliedImageResult.clear();
     96 }
     97 
     98 ImageBuffer* FilterEffect::asImageBuffer()
     99 {
    100     if (!hasResult())
    101         return 0;
    102     if (m_imageBufferResult)
    103         return m_imageBufferResult.get();
    104     m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
    105     IntRect destinationRect(IntPoint(), m_absolutePaintRect.size());
    106     if (m_premultipliedImageResult)
    107         m_imageBufferResult->putPremultipliedImageData(m_premultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
    108     else
    109         m_imageBufferResult->putUnmultipliedImageData(m_unmultipliedImageResult.get(), destinationRect.size(), destinationRect, IntPoint());
    110     return m_imageBufferResult.get();
    111 }
    112 
    113 PassRefPtr<ByteArray> FilterEffect::asUnmultipliedImage(const IntRect& rect)
    114 {
    115     ASSERT(isFilterSizeValid(rect));
    116     RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
    117     copyUnmultipliedImage(imageData.get(), rect);
    118     return imageData.release();
    119 }
    120 
    121 PassRefPtr<ByteArray> FilterEffect::asPremultipliedImage(const IntRect& rect)
    122 {
    123     ASSERT(isFilterSizeValid(rect));
    124     RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
    125     copyPremultipliedImage(imageData.get(), rect);
    126     return imageData.release();
    127 }
    128 
    129 inline void FilterEffect::copyImageBytes(ByteArray* source, ByteArray* destination, const IntRect& rect)
    130 {
    131     // Initialize the destination to transparent black, if not entirely covered by the source.
    132     if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > m_absolutePaintRect.width() || rect.maxY() > m_absolutePaintRect.height())
    133         memset(destination->data(), 0, destination->length());
    134 
    135     // Early return if the rect does not intersect with the source.
    136     if (rect.maxX() <= 0 || rect.maxY() <= 0 || rect.x() >= m_absolutePaintRect.width() || rect.y() >= m_absolutePaintRect.height())
    137         return;
    138 
    139     int xOrigin = rect.x();
    140     int xDest = 0;
    141     if (xOrigin < 0) {
    142         xDest = -xOrigin;
    143         xOrigin = 0;
    144     }
    145     int xEnd = rect.maxX();
    146     if (xEnd > m_absolutePaintRect.width())
    147         xEnd = m_absolutePaintRect.width();
    148 
    149     int yOrigin = rect.y();
    150     int yDest = 0;
    151     if (yOrigin < 0) {
    152         yDest = -yOrigin;
    153         yOrigin = 0;
    154     }
    155     int yEnd = rect.maxY();
    156     if (yEnd > m_absolutePaintRect.height())
    157         yEnd = m_absolutePaintRect.height();
    158 
    159     int size = (xEnd - xOrigin) * 4;
    160     int destinationScanline = rect.width() * 4;
    161     int sourceScanline = m_absolutePaintRect.width() * 4;
    162     unsigned char *destinationPixel = destination->data() + ((yDest * rect.width()) + xDest) * 4;
    163     unsigned char *sourcePixel = source->data() + ((yOrigin * m_absolutePaintRect.width()) + xOrigin) * 4;
    164 
    165     while (yOrigin < yEnd) {
    166         memcpy(destinationPixel, sourcePixel, size);
    167         destinationPixel += destinationScanline;
    168         sourcePixel += sourceScanline;
    169         ++yOrigin;
    170     }
    171 }
    172 
    173 void FilterEffect::copyUnmultipliedImage(ByteArray* destination, const IntRect& rect)
    174 {
    175     ASSERT(hasResult());
    176 
    177     if (!m_unmultipliedImageResult) {
    178         // We prefer a conversion from the image buffer.
    179         if (m_imageBufferResult)
    180             m_unmultipliedImageResult = m_imageBufferResult->getUnmultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
    181         else {
    182             ASSERT(isFilterSizeValid(m_absolutePaintRect));
    183             m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
    184             unsigned char* sourceComponent = m_premultipliedImageResult->data();
    185             unsigned char* destinationComponent = m_unmultipliedImageResult->data();
    186             unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
    187             while (sourceComponent < end) {
    188                 int alpha = sourceComponent[3];
    189                 if (alpha) {
    190                     destinationComponent[0] = static_cast<int>(sourceComponent[0]) * 255 / alpha;
    191                     destinationComponent[1] = static_cast<int>(sourceComponent[1]) * 255 / alpha;
    192                     destinationComponent[2] = static_cast<int>(sourceComponent[2]) * 255 / alpha;
    193                 } else {
    194                     destinationComponent[0] = 0;
    195                     destinationComponent[1] = 0;
    196                     destinationComponent[2] = 0;
    197                 }
    198                 destinationComponent[3] = alpha;
    199                 sourceComponent += 4;
    200                 destinationComponent += 4;
    201             }
    202         }
    203     }
    204     copyImageBytes(m_unmultipliedImageResult.get(), destination, rect);
    205 }
    206 
    207 void FilterEffect::copyPremultipliedImage(ByteArray* destination, const IntRect& rect)
    208 {
    209     ASSERT(hasResult());
    210 
    211     if (!m_premultipliedImageResult) {
    212         // We prefer a conversion from the image buffer.
    213         if (m_imageBufferResult)
    214             m_premultipliedImageResult = m_imageBufferResult->getPremultipliedImageData(IntRect(IntPoint(), m_absolutePaintRect.size()));
    215         else {
    216             ASSERT(isFilterSizeValid(m_absolutePaintRect));
    217             m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
    218             unsigned char* sourceComponent = m_unmultipliedImageResult->data();
    219             unsigned char* destinationComponent = m_premultipliedImageResult->data();
    220             unsigned char* end = sourceComponent + (m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
    221             while (sourceComponent < end) {
    222                 int alpha = sourceComponent[3];
    223                 destinationComponent[0] = static_cast<int>(sourceComponent[0]) * alpha / 255;
    224                 destinationComponent[1] = static_cast<int>(sourceComponent[1]) * alpha / 255;
    225                 destinationComponent[2] = static_cast<int>(sourceComponent[2]) * alpha / 255;
    226                 destinationComponent[3] = alpha;
    227                 sourceComponent += 4;
    228                 destinationComponent += 4;
    229             }
    230         }
    231     }
    232     copyImageBytes(m_premultipliedImageResult.get(), destination, rect);
    233 }
    234 
    235 ImageBuffer* FilterEffect::createImageBufferResult()
    236 {
    237     // Only one result type is allowed.
    238     ASSERT(!hasResult());
    239     determineAbsolutePaintRect();
    240     if (m_absolutePaintRect.isEmpty())
    241         return 0;
    242     m_imageBufferResult = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB);
    243     if (!m_imageBufferResult)
    244         return 0;
    245     ASSERT(m_imageBufferResult->context());
    246     return m_imageBufferResult.get();
    247 }
    248 
    249 ByteArray* FilterEffect::createUnmultipliedImageResult()
    250 {
    251     // Only one result type is allowed.
    252     ASSERT(!hasResult());
    253     ASSERT(isFilterSizeValid(m_absolutePaintRect));
    254 
    255     determineAbsolutePaintRect();
    256     if (m_absolutePaintRect.isEmpty())
    257         return 0;
    258     m_unmultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
    259     return m_unmultipliedImageResult.get();
    260 }
    261 
    262 ByteArray* FilterEffect::createPremultipliedImageResult()
    263 {
    264     // Only one result type is allowed.
    265     ASSERT(!hasResult());
    266     ASSERT(isFilterSizeValid(m_absolutePaintRect));
    267 
    268     determineAbsolutePaintRect();
    269     if (m_absolutePaintRect.isEmpty())
    270         return 0;
    271     m_premultipliedImageResult = ByteArray::create(m_absolutePaintRect.width() * m_absolutePaintRect.height() * 4);
    272     return m_premultipliedImageResult.get();
    273 }
    274 
    275 TextStream& FilterEffect::externalRepresentation(TextStream& ts, int) const
    276 {
    277     // FIXME: We should dump the subRegions of the filter primitives here later. This isn't
    278     // possible at the moment, because we need more detailed informations from the target object.
    279     return ts;
    280 }
    281 
    282 } // namespace WebCore
    283 
    284 #endif // ENABLE(FILTERS)
    285