Chromium Code Reviews| 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 |