Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  */
     19 
     20 #include "config.h"
     21 
     22 #include "core/rendering/svg/RenderSVGResourceMasker.h"
     23 
     24 #include "core/platform/graphics/FloatRect.h"
     25 #include "core/platform/graphics/GraphicsContext.h"
     26 #include "core/platform/graphics/ImageBuffer.h"
     27 #include "core/platform/graphics/transforms/AffineTransform.h"
     28 #include "core/rendering/svg/RenderSVGResource.h"
     29 #include "core/rendering/svg/SVGRenderingContext.h"
     30 #include "core/svg/SVGElement.h"
     31 #include "core/svg/SVGMaskElement.h"
     32 #include "core/svg/SVGUnitTypes.h"
     33 
     34 #include "wtf/UnusedParam.h"
     35 #include "wtf/Vector.h"
     36 
     37 namespace WebCore {
     38 
     39 RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceType;
     40 
     41 RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node)
     42     : RenderSVGResourceContainer(node)
     43 {
     44 }
     45 
     46 RenderSVGResourceMasker::~RenderSVGResourceMasker()
     47 {
     48     if (m_masker.isEmpty())
     49         return;
     50 
     51     deleteAllValues(m_masker);
     52     m_masker.clear();
     53 }
     54 
     55 void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation)
     56 {
     57     m_maskContentBoundaries = FloatRect();
     58     if (!m_masker.isEmpty()) {
     59         deleteAllValues(m_masker);
     60         m_masker.clear();
     61     }
     62 
     63     markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
     64 }
     65 
     66 void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool markForInvalidation)
     67 {
     68     ASSERT(client);
     69 
     70     if (m_masker.contains(client))
     71         delete m_masker.take(client);
     72 
     73     markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
     74 }
     75 
     76 bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
     77 {
     78     ASSERT(object);
     79     ASSERT(context);
     80     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
     81 
     82     bool missingMaskerData = !m_masker.contains(object);
     83     if (missingMaskerData)
     84         m_masker.set(object, new MaskerData);
     85 
     86     MaskerData* maskerData = m_masker.get(object);
     87 
     88     AffineTransform absoluteTransform;
     89     SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
     90 
     91     FloatRect repaintRect = object->repaintRectInLocalCoordinates();
     92 
     93     if (!maskerData->maskImage && !repaintRect.isEmpty()) {
     94         SVGMaskElement* maskElement = toSVGMaskElement(node());
     95         if (!maskElement)
     96             return false;
     97 
     98         ASSERT(style());
     99         const SVGRenderStyle* svgStyle = style()->svgStyle();
    100         ASSERT(svgStyle);
    101         ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB;
    102         if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, maskerData->maskImage, Unaccelerated))
    103             return false;
    104 
    105         if (!drawContentIntoMaskImage(maskerData, colorSpace, maskElement, object)) {
    106             maskerData->maskImage.clear();
    107         }
    108     }
    109 
    110     if (!maskerData->maskImage)
    111         return false;
    112 
    113     SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData);
    114     return true;
    115 }
    116 
    117 bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, const SVGMaskElement* maskElement, RenderObject* object)
    118 {
    119     GraphicsContext* maskImageContext = maskerData->maskImage->context();
    120     ASSERT(maskImageContext);
    121 
    122     // Eventually adjust the mask image context according to the target objectBoundingBox.
    123     AffineTransform maskContentTransformation;
    124     if (maskElement->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    125         FloatRect objectBoundingBox = object->objectBoundingBox();
    126         maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y());
    127         maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
    128         maskImageContext->concatCTM(maskContentTransformation);
    129     }
    130 
    131     // Draw the content into the ImageBuffer.
    132     for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) {
    133         RenderObject* renderer = node->renderer();
    134         if (!node->isSVGElement() || !renderer)
    135             continue;
    136         if (renderer->needsLayout())
    137             return false;
    138         RenderStyle* style = renderer->style();
    139         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
    140             continue;
    141         SVGRenderingContext::renderSubtreeToImageBuffer(maskerData->maskImage.get(), renderer, maskContentTransformation);
    142     }
    143 
    144     maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, colorSpace);
    145 
    146     ASSERT(style());
    147     ASSERT(style()->svgStyle());
    148     // Create the luminance mask.
    149     if (style()->svgStyle()->maskType() == MT_LUMINANCE)
    150         maskerData->maskImage->convertToLuminanceMask();
    151 
    152     return true;
    153 }
    154 
    155 void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
    156 {
    157     for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
    158         RenderObject* renderer = childNode->renderer();
    159         if (!childNode->isSVGElement() || !renderer)
    160             continue;
    161         RenderStyle* style = renderer->style();
    162         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
    163              continue;
    164         m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates()));
    165     }
    166 }
    167 
    168 FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object)
    169 {
    170     SVGMaskElement* maskElement = toSVGMaskElement(node());
    171     ASSERT(maskElement);
    172 
    173     FloatRect objectBoundingBox = object->objectBoundingBox();
    174     FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(maskElement, maskElement->maskUnitsCurrentValue(), objectBoundingBox);
    175 
    176     // Resource was not layouted yet. Give back clipping rect of the mask.
    177     if (selfNeedsLayout())
    178         return maskBoundaries;
    179 
    180     if (m_maskContentBoundaries.isEmpty())
    181         calculateMaskContentRepaintRect();
    182 
    183     FloatRect maskRect = m_maskContentBoundaries;
    184     if (maskElement->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    185         AffineTransform transform;
    186         transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
    187         transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
    188         maskRect = transform.mapRect(maskRect);
    189     }
    190 
    191     maskRect.intersect(maskBoundaries);
    192     return maskRect;
    193 }
    194 
    195 }
    196