Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2005 Eric Seidel <eric (at) webkit.org>
      5  * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org>
      6  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  */
     23 
     24 #include "config.h"
     25 
     26 #include "core/rendering/svg/RenderSVGResourceFilter.h"
     27 
     28 #include "core/page/Page.h"
     29 #include "core/page/Settings.h"
     30 #include "core/platform/graphics/filters/SourceAlpha.h"
     31 #include "core/platform/graphics/filters/SourceGraphic.h"
     32 #include "core/rendering/svg/RenderSVGResourceFilterPrimitive.h"
     33 #include "core/rendering/svg/SVGRenderingContext.h"
     34 #include "core/svg/SVGFilterPrimitiveStandardAttributes.h"
     35 
     36 using namespace std;
     37 
     38 namespace WebCore {
     39 
     40 RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType;
     41 
     42 RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement* node)
     43     : RenderSVGResourceContainer(node)
     44 {
     45 }
     46 
     47 RenderSVGResourceFilter::~RenderSVGResourceFilter()
     48 {
     49     if (m_filter.isEmpty())
     50         return;
     51 
     52     deleteAllValues(m_filter);
     53     m_filter.clear();
     54 }
     55 
     56 void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation)
     57 {
     58     if (!m_filter.isEmpty()) {
     59         deleteAllValues(m_filter);
     60         m_filter.clear();
     61     }
     62 
     63     markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
     64 }
     65 
     66 void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool markForInvalidation)
     67 {
     68     ASSERT(client);
     69 
     70     if (FilterData* filterData = m_filter.get(client)) {
     71         if (filterData->savedContext)
     72             filterData->state = FilterData::MarkedForRemoval;
     73         else
     74             delete m_filter.take(client);
     75     }
     76 
     77     markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
     78 }
     79 
     80 PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter)
     81 {
     82     SVGFilterElement* filterElement = toSVGFilterElement(node());
     83     FloatRect targetBoundingBox = filter->targetBoundingBox();
     84 
     85     // Add effects to the builder
     86     RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(SourceGraphic::create(filter), SourceAlpha::create(filter));
     87     for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) {
     88         if (!node->isSVGElement())
     89             continue;
     90 
     91         SVGElement* element = toSVGElement(node);
     92         if (!element->isFilterEffect() || !element->renderer())
     93             continue;
     94 
     95         SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element);
     96         RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter);
     97         if (!effect) {
     98             builder->clearEffects();
     99             return 0;
    100         }
    101         builder->appendEffectToEffectReferences(effect, effectElement->renderer());
    102         effectElement->setStandardAttributes(effect.get());
    103         effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), targetBoundingBox));
    104         effect->setOperatingColorSpace(
    105             effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB);
    106         builder->add(effectElement->resultCurrentValue(), effect);
    107     }
    108     return builder.release();
    109 }
    110 
    111 bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale)
    112 {
    113     bool matchesFilterSize = true;
    114     if (size.width() > kMaxFilterSize) {
    115         scale.setWidth(scale.width() * kMaxFilterSize / size.width());
    116         matchesFilterSize = false;
    117     }
    118     if (size.height() > kMaxFilterSize) {
    119         scale.setHeight(scale.height() * kMaxFilterSize / size.height());
    120         matchesFilterSize = false;
    121     }
    122 
    123     return matchesFilterSize;
    124 }
    125 
    126 bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
    127 {
    128     ASSERT(object);
    129     ASSERT(context);
    130     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
    131 
    132     if (m_filter.contains(object)) {
    133         FilterData* filterData = m_filter.get(object);
    134         if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying)
    135             filterData->state = FilterData::CycleDetected;
    136         return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now.
    137     }
    138 
    139     OwnPtr<FilterData> filterData(adoptPtr(new FilterData));
    140     FloatRect targetBoundingBox = object->objectBoundingBox();
    141 
    142     SVGFilterElement* filterElement = toSVGFilterElement(node());
    143     filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnitsCurrentValue(), targetBoundingBox);
    144     if (filterData->boundaries.isEmpty())
    145         return false;
    146 
    147     // Determine absolute transformation matrix for filter.
    148     AffineTransform absoluteTransform;
    149     SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
    150     if (!absoluteTransform.isInvertible())
    151         return false;
    152 
    153     // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile.
    154     filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), 0, 0);
    155 
    156     // Determine absolute boundaries of the filter and the drawing region.
    157     FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries);
    158     filterData->drawingRegion = object->strokeBoundingBox();
    159     filterData->drawingRegion.intersect(filterData->boundaries);
    160     FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(filterData->drawingRegion);
    161 
    162     // Create the SVGFilter object.
    163     bool primitiveBoundingBoxMode = filterElement->primitiveUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
    164     filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode);
    165 
    166     // Create all relevant filter primitives.
    167     filterData->builder = buildPrimitives(filterData->filter.get());
    168     if (!filterData->builder)
    169         return false;
    170 
    171     // Calculate the scale factor for the use of filterRes.
    172     // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
    173     FloatSize scale(1, 1);
    174     if (filterElement->hasAttribute(SVGNames::filterResAttr)) {
    175         scale.setWidth(filterElement->filterResXCurrentValue() / absoluteFilterBoundaries.width());
    176         scale.setHeight(filterElement->filterResYCurrentValue() / absoluteFilterBoundaries.height());
    177     }
    178 
    179     if (scale.isEmpty())
    180         return false;
    181 
    182     // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize.
    183     FloatRect tempSourceRect = absoluteDrawingRegion;
    184     tempSourceRect.scale(scale.width(), scale.height());
    185     fitsInMaximumImageSize(tempSourceRect.size(), scale);
    186 
    187     // Set the scale level in SVGFilter.
    188     filterData->filter->setFilterResolution(scale);
    189 
    190     FilterEffect* lastEffect = filterData->builder->lastEffect();
    191     if (!lastEffect)
    192         return false;
    193 
    194     RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect);
    195     FloatRect subRegion = lastEffect->maxEffectRect();
    196     // At least one FilterEffect has a too big image size,
    197     // recalculate the effect sizes with new scale factors.
    198     if (!fitsInMaximumImageSize(subRegion.size(), scale)) {
    199         filterData->filter->setFilterResolution(scale);
    200         RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect);
    201     }
    202 
    203     // If the drawingRegion is empty, we have something like <g filter=".."/>.
    204     // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource.
    205     if (filterData->drawingRegion.isEmpty()) {
    206         ASSERT(!m_filter.contains(object));
    207         filterData->savedContext = context;
    208         m_filter.set(object, filterData.leakPtr());
    209         return false;
    210     }
    211 
    212     // Change the coordinate transformation applied to the filtered element to reflect the resolution of the filter.
    213     AffineTransform effectiveTransform;
    214     effectiveTransform.scale(scale.width(), scale.height());
    215     effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform);
    216 
    217     OwnPtr<ImageBuffer> sourceGraphic;
    218     RenderingMode renderingMode = object->document()->page()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated;
    219     if (!SVGRenderingContext::createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, renderingMode)) {
    220         ASSERT(!m_filter.contains(object));
    221         filterData->savedContext = context;
    222         m_filter.set(object, filterData.leakPtr());
    223         return false;
    224     }
    225 
    226     // Set the rendering mode from the page's settings.
    227     filterData->filter->setRenderingMode(renderingMode);
    228 
    229     GraphicsContext* sourceGraphicContext = sourceGraphic->context();
    230     ASSERT(sourceGraphicContext);
    231 
    232     filterData->sourceGraphicBuffer = sourceGraphic.release();
    233     filterData->savedContext = context;
    234 
    235     context = sourceGraphicContext;
    236 
    237     ASSERT(!m_filter.contains(object));
    238     m_filter.set(object, filterData.leakPtr());
    239 
    240     return true;
    241 }
    242 
    243 void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path*, const RenderSVGShape*)
    244 {
    245     ASSERT(object);
    246     ASSERT(context);
    247     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
    248 
    249     FilterData* filterData = m_filter.get(object);
    250     if (!filterData)
    251         return;
    252 
    253     switch (filterData->state) {
    254     case FilterData::MarkedForRemoval:
    255         delete m_filter.take(object);
    256         return;
    257 
    258     case FilterData::CycleDetected:
    259     case FilterData::Applying:
    260         // We have a cycle if we are already applying the data.
    261         // This can occur due to FeImage referencing a source that makes use of the FEImage itself.
    262         // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack
    263         // will continue correctly.
    264         filterData->state = FilterData::PaintingSource;
    265         return;
    266 
    267     case FilterData::PaintingSource:
    268         if (!filterData->savedContext) {
    269             removeClientFromCache(object);
    270             return;
    271         }
    272 
    273         context = filterData->savedContext;
    274         filterData->savedContext = 0;
    275         break;
    276 
    277     case FilterData::Built: { } // Empty
    278     }
    279 
    280     FilterEffect* lastEffect = filterData->builder->lastEffect();
    281 
    282     if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPrimitiveSubregion().isEmpty()) {
    283         // This is the real filtering of the object. It just needs to be called on the
    284         // initial filtering process. We just take the stored filter result on a
    285         // second drawing.
    286         if (filterData->state != FilterData::Built)
    287             filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.release());
    288 
    289         // Always true if filterData is just built (filterData->state == FilterData::Built).
    290         if (!lastEffect->hasResult()) {
    291             filterData->state = FilterData::Applying;
    292             lastEffect->apply();
    293             lastEffect->correctFilterResultIfNeeded();
    294             lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB);
    295         }
    296         filterData->state = FilterData::Built;
    297 
    298         ImageBuffer* resultImage = lastEffect->asImageBuffer();
    299         if (resultImage) {
    300             context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse());
    301 
    302             context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height()));
    303             context->drawImageBuffer(resultImage, lastEffect->absolutePaintRect());
    304             context->scale(filterData->filter->filterResolution());
    305 
    306             context->concatCTM(filterData->shearFreeAbsoluteTransform);
    307         }
    308     }
    309     filterData->sourceGraphicBuffer.clear();
    310 }
    311 
    312 FloatRect RenderSVGResourceFilter::resourceBoundingBox(RenderObject* object)
    313 {
    314     if (SVGFilterElement* element = toSVGFilterElement(node()))
    315         return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, element->filterUnitsCurrentValue(), object->objectBoundingBox());
    316 
    317     return FloatRect();
    318 }
    319 
    320 void RenderSVGResourceFilter::primitiveAttributeChanged(RenderObject* object, const QualifiedName& attribute)
    321 {
    322     HashMap<RenderObject*, FilterData*>::iterator it = m_filter.begin();
    323     HashMap<RenderObject*, FilterData*>::iterator end = m_filter.end();
    324     SVGFilterPrimitiveStandardAttributes* primitve = static_cast<SVGFilterPrimitiveStandardAttributes*>(object->node());
    325 
    326     for (; it != end; ++it) {
    327         FilterData* filterData = it->value;
    328         if (filterData->state != FilterData::Built)
    329             continue;
    330 
    331         SVGFilterBuilder* builder = filterData->builder.get();
    332         FilterEffect* effect = builder->effectByRenderer(object);
    333         if (!effect)
    334             continue;
    335         // Since all effects shares the same attribute value, all
    336         // or none of them will be changed.
    337         if (!primitve->setFilterEffectAttribute(effect, attribute))
    338             return;
    339         builder->clearResultsRecursive(effect);
    340 
    341         // Repaint the image on the screen.
    342         markClientForInvalidation(it->key, RepaintInvalidation);
    343     }
    344     markAllClientLayersForInvalidation();
    345 }
    346 
    347 FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const
    348 {
    349     FilterData* filterData = m_filter.get(object);
    350     return filterData ? filterData->drawingRegion : FloatRect();
    351 }
    352 
    353 }
    354