OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> | 2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> |
3 * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> |
4 * Copyright (C) 2005 Eric Seidel <eric@webkit.org> | 4 * Copyright (C) 2005 Eric Seidel <eric@webkit.org> |
5 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> | 5 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> |
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
62 void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation ) | 62 void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation ) |
63 { | 63 { |
64 m_filter.clear(); | 64 m_filter.clear(); |
65 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval idation : ParentOnlyInvalidation); | 65 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval idation : ParentOnlyInvalidation); |
66 } | 66 } |
67 | 67 |
68 void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool m arkForInvalidation) | 68 void RenderSVGResourceFilter::removeClientFromCache(RenderObject* client, bool m arkForInvalidation) |
69 { | 69 { |
70 ASSERT(client); | 70 ASSERT(client); |
71 | 71 |
72 if (FilterData* filterData = m_filter.get(client)) { | 72 if (m_filter.get(client)) |
73 if (filterData->savedContext) | 73 m_filter.remove(client); |
f(malita)
2014/09/23 21:54:54
We can drop the conditional and just remove() to a
Stephen White
2014/09/23 22:01:59
Done.
| |
74 filterData->state = FilterData::MarkedForRemoval; | |
f(malita)
2014/09/23 21:54:54
I believe this was the only setter for MarkedForRe
| |
75 else | |
76 m_filter.remove(client); | |
77 } | |
78 | 74 |
79 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati on : ParentOnlyInvalidation); | 75 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati on : ParentOnlyInvalidation); |
80 } | 76 } |
81 | 77 |
82 PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter) | 78 PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter) |
83 { | 79 { |
84 SVGFilterElement* filterElement = toSVGFilterElement(element()); | 80 SVGFilterElement* filterElement = toSVGFilterElement(element()); |
85 FloatRect targetBoundingBox = filter->targetBoundingBox(); | 81 FloatRect targetBoundingBox = filter->targetBoundingBox(); |
86 | 82 |
87 // Add effects to the builder | 83 // Add effects to the builder |
(...skipping 11 matching lines...) Expand all Loading... | |
99 builder->appendEffectToEffectReferences(effect, effectElement->renderer( )); | 95 builder->appendEffectToEffectReferences(effect, effectElement->renderer( )); |
100 effectElement->setStandardAttributes(effect.get()); | 96 effectElement->setStandardAttributes(effect.get()); |
101 effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilter PrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits()->cur rentValue()->enumValue(), targetBoundingBox)); | 97 effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilter PrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits()->cur rentValue()->enumValue(), targetBoundingBox)); |
102 effect->setOperatingColorSpace( | 98 effect->setOperatingColorSpace( |
103 effectElement->renderer()->style()->svgStyle().colorInterpolationFil ters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB); | 99 effectElement->renderer()->style()->svgStyle().colorInterpolationFil ters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB); |
104 builder->add(AtomicString(effectElement->result()->currentValue()->value ()), effect); | 100 builder->add(AtomicString(effectElement->result()->currentValue()->value ()), effect); |
105 } | 101 } |
106 return builder.release(); | 102 return builder.release(); |
107 } | 103 } |
108 | 104 |
109 void RenderSVGResourceFilter::adjustScaleForMaximumImageSize(const FloatSize& si ze, FloatSize& filterScale) | |
110 { | |
111 FloatSize scaledSize(size); | |
112 scaledSize.scale(filterScale.width(), filterScale.height()); | |
113 float scaledArea = scaledSize.width() * scaledSize.height(); | |
114 | |
115 if (scaledArea <= FilterEffect::maxFilterArea()) | |
116 return; | |
117 | |
118 // If area of scaled size is bigger than the upper limit, adjust the scale | |
119 // to fit. | |
120 filterScale.scale(sqrt(FilterEffect::maxFilterArea() / scaledArea)); | |
121 } | |
122 | |
123 static bool createImageBuffer(const Filter* filter, OwnPtr<ImageBuffer>& imageBu ffer) | |
124 { | |
125 IntRect paintRect = filter->sourceImageRect(); | |
126 // Don't create empty ImageBuffers. | |
127 if (paintRect.isEmpty()) | |
128 return false; | |
129 | |
130 OwnPtr<ImageBufferSurface> surface = adoptPtr(new UnacceleratedImageBufferSu rface(paintRect.size())); | |
131 if (!surface->isValid()) | |
132 return false; | |
133 OwnPtr<ImageBuffer> image = ImageBuffer::create(surface.release()); | |
134 if (!image) | |
135 return false; | |
136 | |
137 GraphicsContext* imageContext = image->context(); | |
138 ASSERT(imageContext); | |
139 | |
140 imageContext->translate(-paintRect.x(), -paintRect.y()); | |
141 imageContext->concatCTM(filter->absoluteTransform()); | |
142 imageBuffer = image.release(); | |
143 return true; | |
144 } | |
145 | |
146 static void beginDeferredFilter(GraphicsContext* context, FilterData* filterData ) | 105 static void beginDeferredFilter(GraphicsContext* context, FilterData* filterData ) |
147 { | 106 { |
148 context->beginRecording(filterData->boundaries); | 107 context->beginRecording(filterData->boundaries); |
149 // We pass the boundaries to SkPictureImageFilter so it knows the | 108 // We pass the boundaries to SkPictureImageFilter so it knows the |
150 // world-space position of the filter primitives. It gets them | 109 // world-space position of the filter primitives. It gets them |
151 // from the DisplayList, which also applies the inverse translate | 110 // from the DisplayList, which also applies the inverse translate |
152 // to the origin. So we apply the forward translate here to avoid | 111 // to the origin. So we apply the forward translate here to avoid |
153 // it being applied twice. | 112 // it being applied twice. |
154 // FIXME: we should fix SkPicture to handle this offset itself, or | 113 // FIXME: we should fix SkPicture to handle this offset itself, or |
155 // make the translate optional on SkPictureImageFilter. | 114 // make the translate optional on SkPictureImageFilter. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 } | 185 } |
227 | 186 |
228 bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) | 187 bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) |
229 { | 188 { |
230 ASSERT(object); | 189 ASSERT(object); |
231 ASSERT(context); | 190 ASSERT(context); |
232 ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); | 191 ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); |
233 | 192 |
234 clearInvalidationMask(); | 193 clearInvalidationMask(); |
235 | 194 |
236 bool deferredFiltersEnabled = object->document().settings()->deferredFilters Enabled(); | |
237 if (m_filter.contains(object)) { | 195 if (m_filter.contains(object)) { |
238 FilterData* filterData = m_filter.get(object); | 196 FilterData* filterData = m_filter.get(object); |
239 if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying) | 197 if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying) |
240 filterData->state = FilterData::CycleDetected; | 198 filterData->state = FilterData::CycleDetected; |
241 return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now. | 199 return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now. |
242 } | 200 } |
243 | 201 |
244 OwnPtr<FilterData> filterData(adoptPtr(new FilterData)); | 202 OwnPtr<FilterData> filterData(adoptPtr(new FilterData)); |
245 FloatRect targetBoundingBox = object->objectBoundingBox(); | 203 FloatRect targetBoundingBox = object->objectBoundingBox(); |
246 | 204 |
247 SVGFilterElement* filterElement = toSVGFilterElement(element()); | 205 SVGFilterElement* filterElement = toSVGFilterElement(element()); |
248 filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement >(filterElement, filterElement->filterUnits()->currentValue()->enumValue(), targ etBoundingBox); | 206 filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement >(filterElement, filterElement->filterUnits()->currentValue()->enumValue(), targ etBoundingBox); |
249 if (filterData->boundaries.isEmpty()) | 207 if (filterData->boundaries.isEmpty()) |
250 return false; | 208 return false; |
251 | 209 |
252 // Determine absolute transformation matrix for filter. | 210 // Determine absolute transformation matrix for filter. |
253 AffineTransform absoluteTransform; | 211 AffineTransform absoluteTransform; |
254 SVGRenderingContext::calculateDeviceSpaceTransformation(object, absoluteTran sform); | 212 SVGRenderingContext::calculateDeviceSpaceTransformation(object, absoluteTran sform); |
255 if (!absoluteTransform.isInvertible()) | 213 if (!absoluteTransform.isInvertible()) |
256 return false; | 214 return false; |
257 | 215 |
258 // Filters cannot handle a full transformation, only scales in each directio n. | |
259 FloatSize filterScale; | |
260 | |
261 // Calculate the scale factor for the filter. | |
262 // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion | |
263 if (filterElement->hasAttribute(SVGNames::filterResAttr)) { | |
264 // If resolution is specified, scale to match it. | |
265 filterScale = FloatSize( | |
266 filterElement->filterResX()->currentValue()->value() / filterData->b oundaries.width(), | |
267 filterElement->filterResY()->currentValue()->value() / filterData->b oundaries.height()); | |
268 } else { | |
269 // Otherwise, use the scale of the absolute transform. | |
270 filterScale = FloatSize(absoluteTransform.xScale(), absoluteTransform.yS cale()); | |
271 } | |
272 // The size of the scaled filter boundaries shouldn't be bigger than kMaxFil terSize. | |
273 // Intermediate filters are limited by the filter boundaries so they can't b e bigger than this. | |
274 adjustScaleForMaximumImageSize(filterData->boundaries.size(), filterScale); | |
275 | |
276 filterData->drawingRegion = object->strokeBoundingBox(); | 216 filterData->drawingRegion = object->strokeBoundingBox(); |
277 filterData->drawingRegion.intersect(filterData->boundaries); | 217 filterData->drawingRegion.intersect(filterData->boundaries); |
278 FloatRect absoluteDrawingRegion = filterData->drawingRegion; | 218 IntRect intDrawingRegion = enclosingIntRect(filterData->drawingRegion); |
279 if (!deferredFiltersEnabled) | |
280 absoluteDrawingRegion.scale(filterScale.width(), filterScale.height()); | |
281 | |
282 IntRect intDrawingRegion = enclosingIntRect(absoluteDrawingRegion); | |
283 | 219 |
284 // Create the SVGFilter object. | 220 // Create the SVGFilter object. |
285 bool primitiveBoundingBoxMode = filterElement->primitiveUnits()->currentValu e()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; | 221 bool primitiveBoundingBoxMode = filterElement->primitiveUnits()->currentValu e()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; |
286 filterData->shearFreeAbsoluteTransform = AffineTransform(); | 222 filterData->filter = SVGFilter::create(intDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); |
287 if (!deferredFiltersEnabled) | |
288 filterData->shearFreeAbsoluteTransform.scale(filterScale.width(), filter Scale.height()); | |
289 filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransfor m, intDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundin gBoxMode); | |
290 | 223 |
291 // Create all relevant filter primitives. | 224 // Create all relevant filter primitives. |
292 filterData->builder = buildPrimitives(filterData->filter.get()); | 225 filterData->builder = buildPrimitives(filterData->filter.get()); |
293 if (!filterData->builder) | 226 if (!filterData->builder) |
294 return false; | 227 return false; |
295 | 228 |
296 FilterEffect* lastEffect = filterData->builder->lastEffect(); | 229 FilterEffect* lastEffect = filterData->builder->lastEffect(); |
297 if (!lastEffect) | 230 if (!lastEffect) |
298 return false; | 231 return false; |
299 | 232 |
300 lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); | 233 lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); |
301 | 234 |
302 if (deferredFiltersEnabled) { | 235 FilterData* data = filterData.get(); |
303 FilterData* data = filterData.get(); | |
304 m_filter.set(object, filterData.release()); | |
305 beginDeferredFilter(context, data); | |
306 return true; | |
307 } | |
308 | |
309 // If the drawingRegion is empty, we have something like <g filter=".."/>. | |
310 // Even if the target objectBoundingBox() is empty, we still have to draw th e last effect result image in postApplyResource. | |
311 if (filterData->drawingRegion.isEmpty()) { | |
312 ASSERT(!m_filter.contains(object)); | |
313 filterData->savedContext = context; | |
314 m_filter.set(object, filterData.release()); | |
315 return false; | |
316 } | |
317 | |
318 OwnPtr<ImageBuffer> sourceGraphic; | |
319 if (!createImageBuffer(filterData->filter.get(), sourceGraphic)) { | |
320 ASSERT(!m_filter.contains(object)); | |
321 filterData->savedContext = context; | |
322 m_filter.set(object, filterData.release()); | |
323 return false; | |
324 } | |
325 | |
326 GraphicsContext* sourceGraphicContext = sourceGraphic->context(); | |
327 ASSERT(sourceGraphicContext); | |
328 | |
329 filterData->sourceGraphicBuffer = sourceGraphic.release(); | |
330 filterData->savedContext = context; | |
331 | |
332 context = sourceGraphicContext; | |
333 | |
334 ASSERT(!m_filter.contains(object)); | |
335 m_filter.set(object, filterData.release()); | 236 m_filter.set(object, filterData.release()); |
336 | 237 beginDeferredFilter(context, data); |
337 return true; | 238 return true; |
338 } | 239 } |
339 | 240 |
340 void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo ntext*& context) | 241 void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo ntext*& context) |
341 { | 242 { |
342 ASSERT(object); | 243 ASSERT(object); |
343 ASSERT(context); | 244 ASSERT(context); |
344 | 245 |
345 FilterData* filterData = m_filter.get(object); | 246 FilterData* filterData = m_filter.get(object); |
346 if (!filterData) | 247 if (!filterData) |
347 return; | 248 return; |
348 | 249 |
349 bool deferredFiltersEnabled = object->document().settings()->deferredFilters Enabled(); | |
350 | |
351 switch (filterData->state) { | 250 switch (filterData->state) { |
352 case FilterData::MarkedForRemoval: | |
353 m_filter.remove(object); | |
354 return; | |
355 | |
356 case FilterData::CycleDetected: | 251 case FilterData::CycleDetected: |
357 case FilterData::Applying: | 252 case FilterData::Applying: |
358 // We have a cycle if we are already applying the data. | 253 // We have a cycle if we are already applying the data. |
359 // This can occur due to FeImage referencing a source that makes use of the FEImage itself. | 254 // This can occur due to FeImage referencing a source that makes use of the FEImage itself. |
360 // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack | 255 // This is the first place we've hit the cycle, so set the state back to PaintingSource so the return stack |
361 // will continue correctly. | 256 // will continue correctly. |
362 filterData->state = FilterData::PaintingSource; | 257 filterData->state = FilterData::PaintingSource; |
363 return; | 258 return; |
364 | 259 |
365 case FilterData::PaintingSource: | 260 case FilterData::PaintingSource: |
366 if (deferredFiltersEnabled) { | 261 endDeferredFilter(context, filterData); |
367 endDeferredFilter(context, filterData); | |
368 } else { | |
369 if (!filterData->savedContext) { | |
370 removeClientFromCache(object); | |
371 return; | |
372 } | |
373 | |
374 context = filterData->savedContext; | |
375 filterData->savedContext = 0; | |
376 } | |
377 break; | 262 break; |
378 | 263 |
379 case FilterData::Built: { } // Empty | 264 case FilterData::Built: { } // Empty |
380 } | 265 } |
381 | 266 |
382 if (deferredFiltersEnabled) { | 267 drawDeferredFilter(context, filterData, toSVGFilterElement(element())); |
383 drawDeferredFilter(context, filterData, toSVGFilterElement(element())); | 268 filterData->state = FilterData::Built; |
384 filterData->state = FilterData::Built; | |
385 return; | |
386 } | |
387 | |
388 FilterEffect* lastEffect = filterData->builder->lastEffect(); | |
389 | |
390 if (lastEffect && !filterData->boundaries.isEmpty() && !lastEffect->filterPr imitiveSubregion().isEmpty()) { | |
391 // This is the real filtering of the object. It just needs to be called on the | |
392 // initial filtering process. We just take the stored filter result on a | |
393 // second drawing. | |
394 if (filterData->state != FilterData::Built) | |
395 filterData->filter->setSourceImage(filterData->sourceGraphicBuffer.r elease()); | |
396 | |
397 // Always true if filterData is just built (filterData->state == FilterD ata::Built). | |
398 if (!lastEffect->hasResult()) { | |
399 filterData->state = FilterData::Applying; | |
400 lastEffect->apply(); | |
401 lastEffect->correctFilterResultIfNeeded(); | |
402 lastEffect->transformResultColorSpace(ColorSpaceDeviceRGB); | |
403 } | |
404 filterData->state = FilterData::Built; | |
405 | |
406 ImageBuffer* resultImage = lastEffect->asImageBuffer(); | |
407 if (resultImage) { | |
408 context->drawImageBuffer(resultImage, filterData->filter->mapAbsolut eRectToLocalRect(lastEffect->absolutePaintRect())); | |
409 } | |
410 } | |
411 filterData->sourceGraphicBuffer.clear(); | |
412 } | 269 } |
413 | 270 |
414 FloatRect RenderSVGResourceFilter::resourceBoundingBox(const RenderObject* objec t) | 271 FloatRect RenderSVGResourceFilter::resourceBoundingBox(const RenderObject* objec t) |
415 { | 272 { |
416 if (SVGFilterElement* element = toSVGFilterElement(this->element())) | 273 if (SVGFilterElement* element = toSVGFilterElement(this->element())) |
417 return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, ele ment->filterUnits()->currentValue()->enumValue(), object->objectBoundingBox()); | 274 return SVGLengthContext::resolveRectangle<SVGFilterElement>(element, ele ment->filterUnits()->currentValue()->enumValue(), object->objectBoundingBox()); |
418 | 275 |
419 return FloatRect(); | 276 return FloatRect(); |
420 } | 277 } |
421 | 278 |
(...skipping 24 matching lines...) Expand all Loading... | |
446 markAllClientLayersForInvalidation(); | 303 markAllClientLayersForInvalidation(); |
447 } | 304 } |
448 | 305 |
449 FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const | 306 FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const |
450 { | 307 { |
451 FilterData* filterData = m_filter.get(object); | 308 FilterData* filterData = m_filter.get(object); |
452 return filterData ? filterData->drawingRegion : FloatRect(); | 309 return filterData ? filterData->drawingRegion : FloatRect(); |
453 } | 310 } |
454 | 311 |
455 } | 312 } |
OLD | NEW |