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/rendering/svg/RenderSVGResource.h"
     25 #include "core/rendering/svg/SVGRenderingContext.h"
     26 #include "core/svg/SVGElement.h"
     27 #include "platform/graphics/DisplayList.h"
     28 #include "platform/graphics/GraphicsContextStateSaver.h"
     29 #include "platform/transforms/AffineTransform.h"
     30 #include "wtf/Vector.h"
     31 
     32 namespace WebCore {
     33 
     34 const RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceType;
     35 
     36 RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node)
     37     : RenderSVGResourceContainer(node)
     38 {
     39 }
     40 
     41 RenderSVGResourceMasker::~RenderSVGResourceMasker()
     42 {
     43 }
     44 
     45 void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation)
     46 {
     47     m_maskContentDisplayList.clear();
     48     m_maskContentBoundaries = FloatRect();
     49     markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
     50 }
     51 
     52 void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool markForInvalidation)
     53 {
     54     ASSERT(client);
     55     markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
     56 }
     57 
     58 bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*,
     59     GraphicsContext*& context, unsigned short resourceMode)
     60 {
     61     ASSERT(object);
     62     ASSERT(context);
     63     ASSERT(style());
     64     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
     65     ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout());
     66 
     67     clearInvalidationMask();
     68 
     69     FloatRect repaintRect = object->repaintRectInLocalCoordinates();
     70     if (repaintRect.isEmpty() || !element()->hasChildNodes())
     71         return false;
     72 
     73     // Content layer start.
     74     context->beginTransparencyLayer(1, &repaintRect);
     75 
     76     return true;
     77 }
     78 
     79 void RenderSVGResourceMasker::postApplyResource(RenderObject* object, GraphicsContext*& context,
     80     unsigned short resourceMode, const Path*, const RenderSVGShape*)
     81 {
     82     ASSERT(object);
     83     ASSERT(context);
     84     ASSERT(style());
     85     ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
     86     ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout());
     87 
     88     FloatRect repaintRect = object->repaintRectInLocalCoordinates();
     89 
     90     const SVGRenderStyle* svgStyle = style()->svgStyle();
     91     ASSERT(svgStyle);
     92     ColorFilter maskLayerFilter = svgStyle->maskType() == MT_LUMINANCE
     93         ? ColorFilterLuminanceToAlpha : ColorFilterNone;
     94     ColorFilter maskContentFilter = svgStyle->colorInterpolation() == CI_LINEARRGB
     95         ? ColorFilterSRGBToLinearRGB : ColorFilterNone;
     96 
     97     // Mask layer start.
     98     context->beginLayer(1, CompositeDestinationIn, &repaintRect, maskLayerFilter);
     99     {
    100         // Draw the mask with color conversion (when needed).
    101         GraphicsContextStateSaver maskContentSaver(*context);
    102         context->setColorFilter(maskContentFilter);
    103 
    104         drawMaskForRenderer(context, object->objectBoundingBox());
    105     }
    106 
    107     // Transfer mask layer -> content layer (DstIn)
    108     context->endLayer();
    109     // Transfer content layer -> backdrop (SrcOver)
    110     context->endLayer();
    111 }
    112 
    113 void RenderSVGResourceMasker::drawMaskForRenderer(GraphicsContext* context, const FloatRect& targetBoundingBox)
    114 {
    115     ASSERT(context);
    116 
    117     AffineTransform contentTransformation;
    118     SVGUnitTypes::SVGUnitType contentUnits = toSVGMaskElement(element())->maskContentUnitsCurrentValue();
    119     if (contentUnits == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    120         contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y());
    121         contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
    122         context->concatCTM(contentTransformation);
    123     }
    124 
    125     if (!m_maskContentDisplayList)
    126         m_maskContentDisplayList = asDisplayList(context, contentTransformation);
    127     ASSERT(m_maskContentDisplayList);
    128     context->drawDisplayList(m_maskContentDisplayList.get());
    129 }
    130 
    131 PassRefPtr<DisplayList> RenderSVGResourceMasker::asDisplayList(GraphicsContext* context,
    132     const AffineTransform& contentTransform)
    133 {
    134     ASSERT(context);
    135 
    136     context->beginRecording(repaintRectInLocalCoordinates());
    137     for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) {
    138         RenderObject* renderer = childNode->renderer();
    139         if (!childNode->isSVGElement() || !renderer)
    140             continue;
    141         RenderStyle* style = renderer->style();
    142         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
    143             continue;
    144 
    145         SVGRenderingContext::renderSubtree(context, renderer, contentTransform);
    146     }
    147 
    148     return context->endRecording();
    149 }
    150 
    151 void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
    152 {
    153     for (Node* childNode = element()->firstChild(); childNode; childNode = childNode->nextSibling()) {
    154         RenderObject* renderer = childNode->renderer();
    155         if (!childNode->isSVGElement() || !renderer)
    156             continue;
    157         RenderStyle* style = renderer->style();
    158         if (!style || style->display() == NONE || style->visibility() != VISIBLE)
    159              continue;
    160         m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates()));
    161     }
    162 }
    163 
    164 FloatRect RenderSVGResourceMasker::resourceBoundingBox(RenderObject* object)
    165 {
    166     SVGMaskElement* maskElement = toSVGMaskElement(element());
    167     ASSERT(maskElement);
    168 
    169     FloatRect objectBoundingBox = object->objectBoundingBox();
    170     FloatRect maskBoundaries = SVGLengthContext::resolveRectangle<SVGMaskElement>(maskElement, maskElement->maskUnitsCurrentValue(), objectBoundingBox);
    171 
    172     // Resource was not layouted yet. Give back clipping rect of the mask.
    173     if (selfNeedsLayout())
    174         return maskBoundaries;
    175 
    176     if (m_maskContentBoundaries.isEmpty())
    177         calculateMaskContentRepaintRect();
    178 
    179     FloatRect maskRect = m_maskContentBoundaries;
    180     if (maskElement->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    181         AffineTransform transform;
    182         transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
    183         transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
    184         maskRect = transform.mapRect(maskRect);
    185     }
    186 
    187     maskRect.intersect(maskBoundaries);
    188     return maskRect;
    189 }
    190 
    191 }
    192