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