Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: Source/core/rendering/svg/RenderSVGResourceMasker.cpp

Issue 23643003: ImageBuffer-less SVG masking and clipping. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Removed Linux rebaselines. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. 2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
3 * 3 *
4 * This library is free software; you can redistribute it and/or 4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public 5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either 6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version. 7 * version 2 of the License, or (at your option) any later version.
8 * 8 *
9 * This library is distributed in the hope that it will be useful, 9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details. 12 * Library General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU Library General Public License 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 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, 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA. 17 * Boston, MA 02110-1301, USA.
18 */ 18 */
19 19
20 #include "config.h" 20 #include "config.h"
21 21
22 #include "core/rendering/svg/RenderSVGResourceMasker.h" 22 #include "core/rendering/svg/RenderSVGResourceMasker.h"
23 23
24 #include "core/platform/graphics/FloatRect.h" 24 #include "core/platform/graphics/FloatRect.h"
25 #include "core/platform/graphics/GraphicsContext.h" 25 #include "core/platform/graphics/GraphicsContext.h"
26 #include "core/platform/graphics/GraphicsContextStateSaver.h"
26 #include "core/platform/graphics/ImageBuffer.h" 27 #include "core/platform/graphics/ImageBuffer.h"
28 #include "core/platform/graphics/skia/SkiaUtils.h"
27 #include "core/platform/graphics/transforms/AffineTransform.h" 29 #include "core/platform/graphics/transforms/AffineTransform.h"
28 #include "core/rendering/svg/RenderSVGResource.h" 30 #include "core/rendering/svg/RenderSVGResource.h"
29 #include "core/rendering/svg/SVGRenderingContext.h" 31 #include "core/rendering/svg/SVGRenderingContext.h"
30 #include "core/svg/SVGElement.h" 32 #include "core/svg/SVGElement.h"
31 #include "core/svg/SVGMaskElement.h" 33 #include "core/svg/SVGMaskElement.h"
32 #include "core/svg/SVGUnitTypes.h" 34 #include "core/svg/SVGUnitTypes.h"
35 #include "third_party/skia/include/core/SkColorFilter.h"
36 #include "third_party/skia/include/effects/SkLumaXfermode.h"
37 #include "third_party/skia/include/effects/SkTableColorFilter.h"
pdr. 2013/08/28 03:32:36 Including Skia and using SkRect types in rendering
Stephen White 2013/08/28 14:11:10 +1
f(malita) 2013/08/28 19:54:38 Skia types are already leaked into the world due t
33 38
34 #include "wtf/UnusedParam.h" 39 #include "wtf/UnusedParam.h"
35 #include "wtf/Vector.h" 40 #include "wtf/Vector.h"
36 41
37 namespace WebCore { 42 namespace WebCore {
38 43
39 RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceTy pe; 44 RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceTy pe;
40 45
41 RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node) 46 RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node)
42 : RenderSVGResourceContainer(node) 47 : RenderSVGResourceContainer(node)
43 { 48 {
44 } 49 }
45 50
46 RenderSVGResourceMasker::~RenderSVGResourceMasker() 51 RenderSVGResourceMasker::~RenderSVGResourceMasker()
47 { 52 {
48 if (m_masker.isEmpty())
49 return;
50
51 deleteAllValues(m_masker);
52 m_masker.clear();
53 } 53 }
54 54
55 void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation ) 55 void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation )
56 { 56 {
57 m_maskContentBoundaries = FloatRect(); 57 m_maskContentBoundaries = FloatRect();
58 if (!m_masker.isEmpty()) {
59 deleteAllValues(m_masker);
60 m_masker.clear();
61 }
62
63 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval idation : ParentOnlyInvalidation); 58 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval idation : ParentOnlyInvalidation);
64 } 59 }
65 60
66 void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool m arkForInvalidation) 61 void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool m arkForInvalidation)
67 { 62 {
68 ASSERT(client); 63 ASSERT(client);
69
70 if (m_masker.contains(client))
71 delete m_masker.take(client);
72
73 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati on : ParentOnlyInvalidation); 64 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati on : ParentOnlyInvalidation);
74 } 65 }
75 66
76 bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) 67 bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*,
68 GraphicsContext*& context, unsigned short resourceMode)
77 { 69 {
78 ASSERT(object); 70 ASSERT(object);
79 ASSERT(context); 71 ASSERT(context);
72 ASSERT(style());
80 ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); 73 ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
81 74 ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout());
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(obje ct, absoluteTransform);
90 75
91 FloatRect repaintRect = object->repaintRectInLocalCoordinates(); 76 FloatRect repaintRect = object->repaintRectInLocalCoordinates();
77 if (repaintRect.isEmpty() || !node()->hasChildNodes())
78 return false;
92 79
93 if (!maskerData->maskImage && !repaintRect.isEmpty()) { 80 SkRect rect = WebCoreFloatRectToSKRect(repaintRect);
94 SVGMaskElement* maskElement = toSVGMaskElement(node()); 81 const SVGRenderStyle* svgStyle = style()->svgStyle();
95 if (!maskElement) 82 ASSERT(svgStyle);
96 return false; 83 ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB
84 ? ColorSpaceLinearRGB
85 : ColorSpaceDeviceRGB;
86 RefPtr<SkColorFilter> colorSpaceConverter = ImageBuffer::createColorSpaceFil ter(
87 ColorSpaceDeviceRGB, colorSpace);
97 88
98 ASSERT(style()); 89 // Mask layer start.
99 const SVGRenderStyle* svgStyle = style()->svgStyle(); 90 context->saveLayer(&rect, 0);
100 ASSERT(svgStyle);
101 ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB;
102 if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransfo rm, maskerData->maskImage, Unaccelerated))
103 return false;
104 91
105 if (!drawContentIntoMaskImage(maskerData, colorSpace, maskElement, objec t)) { 92 if (colorSpaceConverter) {
106 maskerData->maskImage.clear(); 93 // TODO: investigate handling color space conversion via an inline paint color filter.
107 } 94 // That would allow us to avoid this extra saveLayer, but requires the color filter
95 // to be part of GraphicsContext's state (and be applied in setupP aintCommon()).
96 SkPaint converterPaint;
97 converterPaint.setColorFilter(colorSpaceConverter.get());
98
99 // Color converter layer start.
100 context->saveLayer(&rect, &converterPaint);
108 } 101 }
109 102
110 if (!maskerData->maskImage) 103 drawMaskContent(context, object->objectBoundingBox());
111 return false;
112 104
113 SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRe ct, maskerData->maskImage, missingMaskerData); 105 if (colorSpaceConverter)
114 return true; 106 context->restoreLayer();
115 }
116 107
117 bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, C olorSpace colorSpace, const SVGMaskElement* maskElement, RenderObject* object) 108 // Use a transfer mode appropriate for mask-type.
118 { 109 RefPtr<SkXfermode> xferMode = svgStyle->maskType() == MT_LUMINANCE
119 GraphicsContext* maskImageContext = maskerData->maskImage->context(); 110 ? adoptRef(SkLumaMaskXfermode::Create(SkXfermode::kSrcIn_Mode))
120 ASSERT(maskImageContext); 111 : adoptRef(SkXfermode::Create(SkXfermode::kSrcIn_Mode));
112 SkPaint contentPaint;
113 contentPaint.setXfermode(xferMode.get());
121 114
122 // Eventually adjust the mask image context according to the target objectBo undingBox. 115 // Content layer start.
123 AffineTransform maskContentTransformation; 116 context->saveLayer(&rect, &contentPaint);
124 if (maskElement->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TY PE_OBJECTBOUNDINGBOX) {
125 FloatRect objectBoundingBox = object->objectBoundingBox();
126 maskContentTransformation.translate(objectBoundingBox.x(), objectBoundin gBox.y());
127 maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), obj ectBoundingBox.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.ge t(), 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 117
152 return true; 118 return true;
153 } 119 }
154 120
121 void RenderSVGResourceMasker::postApplyResource(RenderObject*, GraphicsContext*& context,
122 unsigned short resourceMode, const Path*, const RenderSVGShape*)
123 {
124 ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
125
126 // Transfer content layer -> mask layer (SrcIn)
127 context->restoreLayer();
128 // Transfer mask layer -> bg layer (SrcOver)
129 context->restoreLayer();
130 }
131
132 void RenderSVGResourceMasker::drawMaskContent(GraphicsContext* context, const Fl oatRect& targetBoundingBox)
133 {
134 ASSERT(context);
135
136 // Adjust the mask image context according to the target objectBoundingBox.
137 AffineTransform maskContentTransformation;
138 GraphicsContextStateSaver maskContentSaver(*context, false);
139 if (toSVGMaskElement(node())->maskContentUnitsCurrentValue() == SVGUnitTypes ::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
140 maskContentSaver.save();
141 maskContentTransformation = makeMapBetweenRects(FloatRect(0, 0, 1, 1), t argetBoundingBox);
pdr. 2013/08/28 03:32:36 Ditto
f(malita) 2013/08/28 19:54:38 Done.
142 context->concatCTM(maskContentTransformation);
143 }
144
145 for (Node* childNode = node()->firstChild(); childNode; childNode = childNod e->nextSibling()) {
146 RenderObject* renderer = childNode->renderer();
147 if (!childNode->isSVGElement() || !renderer)
148 continue;
149 RenderStyle* style = renderer->style();
150 if (!style || style->display() == NONE || style->visibility() != VISIBLE )
151 continue;
152
153 SVGRenderingContext::renderSubtree(context, renderer, maskContentTransfo rmation);
154 }
155 }
156
155 void RenderSVGResourceMasker::calculateMaskContentRepaintRect() 157 void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
156 { 158 {
157 for (Node* childNode = node()->firstChild(); childNode; childNode = childNod e->nextSibling()) { 159 for (Node* childNode = node()->firstChild(); childNode; childNode = childNod e->nextSibling()) {
158 RenderObject* renderer = childNode->renderer(); 160 RenderObject* renderer = childNode->renderer();
159 if (!childNode->isSVGElement() || !renderer) 161 if (!childNode->isSVGElement() || !renderer)
160 continue; 162 continue;
161 RenderStyle* style = renderer->style(); 163 RenderStyle* style = renderer->style();
162 if (!style || style->display() == NONE || style->visibility() != VISIBLE ) 164 if (!style || style->display() == NONE || style->visibility() != VISIBLE )
163 continue; 165 continue;
164 m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect (renderer->repaintRectInLocalCoordinates())); 166 m_maskContentBoundaries.unite(renderer->localToParentTransform().mapRect (renderer->repaintRectInLocalCoordinates()));
(...skipping 21 matching lines...) Expand all
186 transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); 188 transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
187 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h eight()); 189 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h eight());
188 maskRect = transform.mapRect(maskRect); 190 maskRect = transform.mapRect(maskRect);
189 } 191 }
190 192
191 maskRect.intersect(maskBoundaries); 193 maskRect.intersect(maskBoundaries);
192 return maskRect; 194 return maskRect;
193 } 195 }
194 196
195 } 197 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698