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