PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(Filter* filter) { SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node()); bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; // Add effects to the builder RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(filter); for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { if (!node->isSVGElement()) continue; SVGElement* element = static_cast<SVGElement*>(node); if (!element->isFilterEffect()) continue; SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element); RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter); if (!effect) { builder->clearEffects(); return 0; } builder->appendEffectToEffectReferences(effect); effectElement->setStandardAttributes(primitiveBoundingBoxMode, effect.get()); builder->add(effectElement->result(), effect); } return builder.release(); }
PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter) { SVGFilterElement* filterElement = toSVGFilterElement(node()); FloatRect targetBoundingBox = filter->targetBoundingBox(); // Add effects to the builder RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(SourceGraphic::create(filter), SourceAlpha::create(filter)); for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { if (!node->isSVGElement()) continue; SVGElement* element = toSVGElement(node); if (!element->isFilterEffect()) continue; SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element); RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter); if (!effect) { builder->clearEffects(); return 0; } builder->appendEffectToEffectReferences(effect, effectElement->renderer()); effectElement->setStandardAttributes(effect.get()); effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits(), targetBoundingBox)); effect->setOperatingColorSpace( effectElement->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB); builder->add(effectElement->result(), effect); } return builder.release(); }
JSValue jsSVGFilterElementClassName(ExecState* exec, const Identifier&, const PropertySlot& slot) { UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(static_cast<JSSVGFilterElement*>(asObject(slot.slotBase()))->impl()); RefPtr<SVGAnimatedString> obj = imp->classNameAnimated(); return toJS(exec, obj.get(), imp); }
JSValue jsSVGFilterElementExternalResourcesRequired(ExecState* exec, const Identifier&, const PropertySlot& slot) { UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(static_cast<JSSVGFilterElement*>(asObject(slot.slotBase()))->impl()); RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated(); return toJS(exec, obj.get(), imp); }
JSValue* JSSVGFilterElementPrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args) { if (!thisObj->inherits(&JSSVGFilterElement::info)) return throwError(exec, TypeError); SVGFilterElement* imp = static_cast<SVGFilterElement*>(static_cast<JSSVGFilterElement*>(thisObj)->impl()); switch (id) { case JSSVGFilterElement::SetFilterResFuncNum: { bool filterResXOk; unsigned filterResX = args[0]->toInt32(exec, filterResXOk); if (!filterResXOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } bool filterResYOk; unsigned filterResY = args[1]->toInt32(exec, filterResYOk); if (!filterResYOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } imp->setFilterRes(filterResX, filterResY); return jsUndefined(); } } return 0; }
PassRefPtr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter) { SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node()); FloatRect targetBoundingBox = filter->targetBoundingBox(); // Add effects to the builder RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(filter); for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { if (!node->isSVGElement()) continue; SVGElement* element = static_cast<SVGElement*>(node); if (!element->isFilterEffect()) continue; SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element); RefPtr<FilterEffect> effect = effectElement->build(builder.get(), filter); if (!effect) { builder->clearEffects(); return 0; } builder->appendEffectToEffectReferences(effect, effectElement->renderer()); effectElement->setStandardAttributes(effect.get()); effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnits(), targetBoundingBox)); builder->add(effectElement->result(), effect); } return builder.release(); }
JSValue jsSVGFilterElementXmlspace(ExecState* exec, JSValue slotBase, const Identifier&) { JSSVGFilterElement* castedThis = static_cast<JSSVGFilterElement*>(asObject(slotBase)); UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThis->impl()); JSValue result = jsString(exec, imp->xmlspace()); return result; }
JSValue jsSVGFilterElementStyle(ExecState* exec, JSValue slotBase, const Identifier&) { JSSVGFilterElement* castedThis = static_cast<JSSVGFilterElement*>(asObject(slotBase)); UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThis->impl()); JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->style())); return result; }
JSValue jsSVGFilterElementPrimitiveUnits(ExecState* exec, JSValue slotBase, const Identifier&) { JSSVGFilterElement* castedThis = static_cast<JSSVGFilterElement*>(asObject(slotBase)); UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThis->impl()); RefPtr<SVGAnimatedEnumeration> obj = imp->primitiveUnitsAnimated(); JSValue result = toJS(exec, castedThis->globalObject(), obj.get()); return result; }
JSValue jsSVGFilterElementExternalResourcesRequired(ExecState* exec, JSValue slotBase, const Identifier&) { JSSVGFilterElement* castedThis = static_cast<JSSVGFilterElement*>(asObject(slotBase)); UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThis->impl()); RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated(); JSValue result = toJS(exec, castedThis->globalObject(), obj.get()); return result; }
JSValue jsSVGFilterElementClassName(ExecState* exec, JSValue slotBase, const Identifier&) { JSSVGFilterElement* castedThis = static_cast<JSSVGFilterElement*>(asObject(slotBase)); UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThis->impl()); RefPtr<SVGAnimatedString> obj = imp->classNameAnimated(); JSValue result = toJS(exec, castedThis->globalObject(), obj.get()); return result; }
GraphicsContext* SVGFilterPainter::prepareEffect(const LayoutObject& object, SVGFilterRecordingContext& recordingContext) { ASSERT(recordingContext.paintingContext()); m_filter.clearInvalidationMask(); if (FilterData* filterData = m_filter.getFilterDataForLayoutObject(&object)) { // If the filterData already exists we do not need to record the content // to be filtered. This can occur if the content was previously recorded // or we are in a cycle. if (filterData->m_state == FilterData::PaintingFilter) filterData->m_state = FilterData::PaintingFilterCycleDetected; if (filterData->m_state == FilterData::RecordingContent) filterData->m_state = FilterData::RecordingContentCycleDetected; return nullptr; } OwnPtrWillBeRawPtr<FilterData> filterData = FilterData::create(); FloatRect referenceBox = object.objectBoundingBox(); SVGFilterElement* filterElement = toSVGFilterElement(m_filter.element()); FloatRect filterRegion = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnits()->currentValue()->enumValue(), referenceBox); if (filterRegion.isEmpty()) return nullptr; // Create the SVGFilter object. bool primitiveBoundingBoxMode = filterElement->primitiveUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; Filter::UnitScaling unitScaling = primitiveBoundingBoxMode ? Filter::BoundingBox : Filter::UserSpace; filterData->filter = Filter::create(referenceBox, filterRegion, 1, unitScaling); filterData->nodeMap = SVGFilterGraphNodeMap::create(); IntRect sourceRegion = enclosingIntRect(intersection(filterRegion, object.strokeBoundingBox())); filterData->filter->sourceGraphic()->setSourceRect(sourceRegion); // Create all relevant filter primitives. SVGFilterBuilder builder(filterData->filter->sourceGraphic(), filterData->nodeMap.get()); builder.buildGraph(filterData->filter.get(), *filterElement, referenceBox); FilterEffect* lastEffect = builder.lastEffect(); if (!lastEffect) return nullptr; lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); filterData->filter->setLastEffect(lastEffect); FilterData* data = filterData.get(); // TODO(pdr): Can this be moved out of painter? m_filter.setFilterDataForLayoutObject(const_cast<LayoutObject*>(&object), filterData.release()); return recordingContext.beginContent(data); }
JSValue JSC_HOST_CALL jsSVGFilterElementPrototypeFunctionGetPresentationAttribute(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UNUSED_PARAM(args); if (!thisValue.isObject(&JSSVGFilterElement::s_info)) return throwError(exec, TypeError); JSSVGFilterElement* castedThisObj = static_cast<JSSVGFilterElement*>(asObject(thisValue)); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThisObj->impl()); const UString& name = args.at(0).toString(exec); JSC::JSValue result = toJS(exec, WTF::getPtr(imp->getPresentationAttribute(name))); return result; }
JSValue JSC_HOST_CALL jsSVGFilterElementPrototypeFunctionSetFilterRes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UNUSED_PARAM(args); if (!thisValue.isObject(&JSSVGFilterElement::s_info)) return throwError(exec, TypeError); JSSVGFilterElement* castedThisObj = static_cast<JSSVGFilterElement*>(asObject(thisValue)); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThisObj->impl()); unsigned filterResX = args.at(0).toInt32(exec); unsigned filterResY = args.at(1).toInt32(exec); imp->setFilterRes(filterResX, filterResY); return jsUndefined(); }
EncodedJSValue JSC_HOST_CALL jsSVGFilterElementPrototypeFunctionGetPresentationAttribute(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&JSSVGFilterElement::s_info)) return throwVMTypeError(exec); JSSVGFilterElement* castedThis = static_cast<JSSVGFilterElement*>(asObject(thisValue)); ASSERT_GC_OBJECT_INHERITS(castedThis, &JSSVGFilterElement::s_info); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThis->impl()); const String& name(ustringToString(exec->argument(0).toString(exec))); if (exec->hadException()) return JSValue::encode(jsUndefined()); JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->getPresentationAttribute(name))); return JSValue::encode(result); }
bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); clearInvalidationMask(); if (m_filter.contains(object)) { FilterData* filterData = m_filter.get(object); if (filterData->state == FilterData::PaintingSource) filterData->state = FilterData::CycleDetected; return false; // Already built, or we're in a cycle. Regardless, just do nothing more now. } OwnPtr<FilterData> filterData(adoptPtr(new FilterData)); FloatRect targetBoundingBox = object->objectBoundingBox(); SVGFilterElement* filterElement = toSVGFilterElement(element()); filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnits()->currentValue()->enumValue(), targetBoundingBox); if (filterData->boundaries.isEmpty()) return false; filterData->drawingRegion = object->strokeBoundingBox(); filterData->drawingRegion.intersect(filterData->boundaries); IntRect intDrawingRegion = enclosingIntRect(filterData->drawingRegion); // Create the SVGFilter object. bool primitiveBoundingBoxMode = filterElement->primitiveUnits()->currentValue()->enumValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; filterData->filter = SVGFilter::create(intDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); // Create all relevant filter primitives. filterData->builder = buildPrimitives(filterData->filter.get()); if (!filterData->builder) return false; FilterEffect* lastEffect = filterData->builder->lastEffect(); if (!lastEffect) return false; lastEffect->determineFilterPrimitiveSubregion(ClipToFilterRegion); FilterData* data = filterData.get(); m_filter.set(object, filterData.release()); beginDeferredFilter(context, data); return true; }
void JSSVGFilterElement::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/) { switch (token) { case XmllangAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); imp->setXmllang(value->toString(exec)); break; } case XmlspaceAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); imp->setXmlspace(value->toString(exec)); break; } } }
EncodedJSValue JSC_HOST_CALL jsSVGFilterElementPrototypeFunctionSetFilterRes(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&JSSVGFilterElement::s_info)) return throwVMTypeError(exec); JSSVGFilterElement* castedThis = static_cast<JSSVGFilterElement*>(asObject(thisValue)); ASSERT_GC_OBJECT_INHERITS(castedThis, &JSSVGFilterElement::s_info); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThis->impl()); unsigned filterResX(exec->argument(0).toUInt32(exec)); if (exec->hadException()) return JSValue::encode(jsUndefined()); unsigned filterResY(exec->argument(1).toUInt32(exec)); if (exec->hadException()) return JSValue::encode(jsUndefined()); imp->setFilterRes(filterResX, filterResY); return JSValue::encode(jsUndefined()); }
void setJSSVGFilterElementXmlspace(ExecState* exec, JSObject* thisObject, JSValue value) { JSSVGFilterElement* castedThis = static_cast<JSSVGFilterElement*>(thisObject); SVGFilterElement* imp = static_cast<SVGFilterElement*>(castedThis->impl()); imp->setXmlspace(ustringToString(value.toString(exec))); }
JSValue jsSVGFilterElementStyle(ExecState* exec, const Identifier&, const PropertySlot& slot) { UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(static_cast<JSSVGFilterElement*>(asObject(slot.slotBase()))->impl()); return toJS(exec, WTF::getPtr(imp->style())); }
void setJSSVGFilterElementXmlspace(ExecState* exec, JSObject* thisObject, JSValue value) { SVGFilterElement* imp = static_cast<SVGFilterElement*>(static_cast<JSSVGFilterElement*>(thisObject)->impl()); imp->setXmlspace(value.toString(exec)); }
void PSVGFEElement::CalculatePrimitiveSubRegion(PSVGFilterElement* pFilterElement, PSVGElement* pReferencingElement, /*in,out*/gm::RectF& subRegion) { ISVGFilterPrimitiveStandardAttributes* pStdAttributes = dynamic_cast<ISVGFilterPrimitiveStandardAttributes*>(m_pNode); ASSERT(pStdAttributes != NULL); SVGFilterElement* psvgFilterElement = static_cast<SVGFilterElement*>(pFilterElement->m_pNode); ISVGLength* xLength = pStdAttributes->get_x()->get_animVal(); ISVGLength* yLength = pStdAttributes->get_y()->get_animVal(); ISVGLength* widthLength = pStdAttributes->get_width()->get_animVal(); ISVGLength* heightLength = pStdAttributes->get_height()->get_animVal(); // RectD filterRegion = pReferencingElement->m_filterRect; // RectD subRegion; if (psvgFilterElement->primitiveUnits_attr().m_animated->m_animVal->m_value == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { gm::RectD rect = pReferencingElement->m_bounds; if (pStdAttributes->get_xAttr()->get_specified()) { if (xLength->get_unitType() == SVG_LENGTHTYPE_PERCENTAGE) subRegion.X = rect.X + (xLength->get_valueInSpecifiedUnits() * rect.Width/100); else subRegion.X = rect.X + (xLength->get_value() * rect.Width); } //else // subRegion.X = filterRegion.X; if (pStdAttributes->get_yAttr()->get_specified()) { if (yLength->get_unitType() == SVG_LENGTHTYPE_PERCENTAGE) subRegion.Y = rect.Y + (yLength->get_valueInSpecifiedUnits() * rect.Height/100); else subRegion.Y = rect.Y + (yLength->get_value() * rect.Height); } //else // subRegion.Y = filterRegion.Y; if (pStdAttributes->get_widthAttr()->get_specified()) { if (widthLength->get_unitType() == SVG_LENGTHTYPE_PERCENTAGE) subRegion.Width = (widthLength->get_valueInSpecifiedUnits() * rect.Width/100); else subRegion.Width = (widthLength->get_value() * rect.Width); } //else // subRegion.Width = filterRegion.Width; if (pStdAttributes->get_heightAttr()->get_specified()) { if (heightLength->get_unitType() == SVG_LENGTHTYPE_PERCENTAGE) subRegion.Height = (heightLength->get_valueInSpecifiedUnits() * rect.Height/100); else subRegion.Height = (heightLength->get_value() * rect.Height); } //else // subRegion.Height = filterRegion.Height; } else { gm::RectD rect = pReferencingElement->GetViewportElement()->GetViewBox(); if (pStdAttributes->get_xAttr()->get_specified()) { if (xLength->get_unitType() == SVG_LENGTHTYPE_PERCENTAGE) subRegion.X = rect.X + (xLength->get_valueInSpecifiedUnits() * rect.Width/100); else subRegion.X = xLength->get_value(); } //else // subRegion.X = filterRegion.X; if (pStdAttributes->get_yAttr()->get_specified()) { if (yLength->get_unitType() == SVG_LENGTHTYPE_PERCENTAGE) subRegion.Y = rect.Y + (yLength->get_valueInSpecifiedUnits() * rect.Height/100); else subRegion.Y = yLength->get_value(); } //else // subRegion.Y = filterRegion.Y; if (pStdAttributes->get_widthAttr()->get_specified()) { if (widthLength->get_unitType() == SVG_LENGTHTYPE_PERCENTAGE) subRegion.Width = (widthLength->get_valueInSpecifiedUnits() * rect.Width/100); else subRegion.Width = widthLength->get_value(); } //else // subRegion.Width = filterRegion.Width; if (pStdAttributes->get_heightAttr()->get_specified()) { if (heightLength->get_unitType() == SVG_LENGTHTYPE_PERCENTAGE) subRegion.Height = (heightLength->get_valueInSpecifiedUnits() * rect.Height/100); else subRegion.Height = heightLength->get_value(); } //else // subRegion.Height = filterRegion.Height; } // return subRegion; }
bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); #ifndef NDEBUG ASSERT(resourceMode == ApplyToDefaultMode); #else UNUSED_PARAM(resourceMode); #endif // Returning false here, to avoid drawings onto the context. We just want to // draw the stored filter output, not the unfiltered object as well. if (m_filter.contains(object)) { FilterData* filterData = m_filter.get(object); if (filterData->builded) return false; delete m_filter.take(object); // Oops, have to rebuild, go through normal code path } OwnPtr<FilterData> filterData(new FilterData); filterData->builder = buildPrimitives(); if (!filterData->builder) return false; FloatRect paintRect = object->strokeBoundingBox(); // Calculate the scale factor for the use of filterRes. // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node()); filterData->boundaries = filterElement->filterBoundingBox(object->objectBoundingBox()); if (filterData->boundaries.isEmpty()) return false; FloatSize scale(1.0f, 1.0f); if (filterElement->hasAttribute(SVGNames::filterResAttr)) { scale.setWidth(filterElement->filterResX() / filterData->boundaries.width()); scale.setHeight(filterElement->filterResY() / filterData->boundaries.height()); } if (scale.isEmpty()) return false; // clip sourceImage to filterRegion FloatRect clippedSourceRect = paintRect; clippedSourceRect.intersect(filterData->boundaries); // scale filter size to filterRes FloatRect tempSourceRect = clippedSourceRect; // scale to big sourceImage size to kMaxFilterSize tempSourceRect.scale(scale.width(), scale.height()); fitsInMaximumImageSize(tempSourceRect.size(), scale); // prepare Filters bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; filterData->filter = SVGFilter::create(paintRect, filterData->boundaries, primitiveBoundingBoxMode); filterData->filter->setFilterResolution(scale); FilterEffect* lastEffect = filterData->builder->lastEffect(); if (!lastEffect) return false; lastEffect->calculateEffectRect(filterData->filter.get()); // At least one FilterEffect has a too big image size, // recalculate the effect sizes with new scale factors. if (!fitsInMaximumImageSize(filterData->filter->maxImageSize(), scale)) { filterData->filter->setFilterResolution(scale); lastEffect->calculateEffectRect(filterData->filter.get()); } clippedSourceRect.scale(scale.width(), scale.height()); // Draw the content of the current element and it's childs to a imageBuffer to get the SourceGraphic. // The size of the SourceGraphic is clipped to the size of the filterRegion. IntRect bufferRect = enclosingIntRect(clippedSourceRect); OwnPtr<ImageBuffer> sourceGraphic(ImageBuffer::create(bufferRect.size(), LinearRGB)); if (!sourceGraphic.get()) return false; GraphicsContext* sourceGraphicContext = sourceGraphic->context(); sourceGraphicContext->translate(-clippedSourceRect.x(), -clippedSourceRect.y()); sourceGraphicContext->scale(scale); sourceGraphicContext->clearRect(FloatRect(FloatPoint(), paintRect.size())); filterData->sourceGraphicBuffer = sourceGraphic.release(); filterData->savedContext = context; context = sourceGraphicContext; ASSERT(!m_filter.contains(object)); m_filter.set(object, filterData.leakPtr()); return true; }
JSValue jsSVGFilterElementXmlspace(ExecState* exec, const Identifier&, const PropertySlot& slot) { UNUSED_PARAM(exec); SVGFilterElement* imp = static_cast<SVGFilterElement*>(static_cast<JSSVGFilterElement*>(asObject(slot.slotBase()))->impl()); return jsString(exec, imp->xmlspace()); }
bool RenderSVGResourceFilter::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(object); ASSERT(context); ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); // Returning false here, to avoid drawings onto the context. We just want to // draw the stored filter output, not the unfiltered object as well. if (m_filter.contains(object)) { FilterData* filterData = m_filter.get(object); if (filterData->builded) return false; delete m_filter.take(object); // Oops, have to rebuild, go through normal code path } OwnPtr<FilterData> filterData(adoptPtr(new FilterData)); FloatRect targetBoundingBox = object->objectBoundingBox(); SVGFilterElement* filterElement = static_cast<SVGFilterElement*>(node()); filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(filterElement, filterElement->filterUnits(), targetBoundingBox); if (filterData->boundaries.isEmpty()) return false; // Determine absolute transformation matrix for filter. AffineTransform absoluteTransform; SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); if (!absoluteTransform.isInvertible()) return false; // Eliminate shear of the absolute transformation matrix, to be able to produce unsheared tile images for feTile. filterData->shearFreeAbsoluteTransform = AffineTransform(absoluteTransform.xScale(), 0, 0, absoluteTransform.yScale(), 0, 0); // Determine absolute boundaries of the filter and the drawing region. FloatRect absoluteFilterBoundaries = filterData->shearFreeAbsoluteTransform.mapRect(filterData->boundaries); FloatRect drawingRegion = object->strokeBoundingBox(); drawingRegion.intersect(filterData->boundaries); FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(drawingRegion); // Create the SVGFilter object. bool primitiveBoundingBoxMode = filterElement->primitiveUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX; filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); // Create all relevant filter primitives. filterData->builder = buildPrimitives(filterData->filter.get()); if (!filterData->builder) return false; // Calculate the scale factor for the use of filterRes. // Also see http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion FloatSize scale(1, 1); if (filterElement->hasAttribute(SVGNames::filterResAttr)) { scale.setWidth(filterElement->filterResX() / absoluteFilterBoundaries.width()); scale.setHeight(filterElement->filterResY() / absoluteFilterBoundaries.height()); } if (scale.isEmpty()) return false; // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize. FloatRect tempSourceRect = absoluteDrawingRegion; tempSourceRect.scale(scale.width(), scale.height()); fitsInMaximumImageSize(tempSourceRect.size(), scale); // Set the scale level in SVGFilter. filterData->filter->setFilterResolution(scale); FilterEffect* lastEffect = filterData->builder->lastEffect(); if (!lastEffect) return false; RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect); FloatRect subRegion = lastEffect->maxEffectRect(); // At least one FilterEffect has a too big image size, // recalculate the effect sizes with new scale factors. if (!fitsInMaximumImageSize(subRegion.size(), scale)) { filterData->filter->setFilterResolution(scale); RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect); } // If the drawingRegion is empty, we have something like <g filter=".."/>. // Even if the target objectBoundingBox() is empty, we still have to draw the last effect result image in postApplyResource. if (drawingRegion.isEmpty()) { ASSERT(!m_filter.contains(object)); filterData->savedContext = context; m_filter.set(object, filterData.leakPtr()); return false; } // Change the coordinate transformation applied to the filtered element to reflect the resolution of the filter. AffineTransform effectiveTransform; effectiveTransform.scale(scale.width(), scale.height()); effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform); OwnPtr<ImageBuffer> sourceGraphic; RenderingMode renderingMode = object->document()->page()->settings()->acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; if (!SVGImageBufferTools::createImageBuffer(drawingRegion, effectiveTransform, sourceGraphic, ColorSpaceLinearRGB, renderingMode)) { ASSERT(!m_filter.contains(object)); filterData->savedContext = context; m_filter.set(object, filterData.leakPtr()); return false; } // Set the rendering mode from the page's settings. filterData->filter->setRenderingMode(renderingMode); GraphicsContext* sourceGraphicContext = sourceGraphic->context(); ASSERT(sourceGraphicContext); filterData->sourceGraphicBuffer = sourceGraphic.release(); filterData->savedContext = context; context = sourceGraphicContext; ASSERT(!m_filter.contains(object)); m_filter.set(object, filterData.leakPtr()); return true; }
JSValue* JSSVGFilterElement::getValueProperty(ExecState* exec, int token) const { switch (token) { case FilterUnitsAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedEnumeration> obj = imp->filterUnitsAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedEnumeration>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedEnumeration>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedEnumeration>(obj.get(), imp); } } return toJS(exec, obj.get()); } case PrimitiveUnitsAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedEnumeration> obj = imp->primitiveUnitsAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedEnumeration>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedEnumeration>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedEnumeration>(obj.get(), imp); } } return toJS(exec, obj.get()); } case XAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedLength> obj = imp->xAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedLength>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedLength>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedLength>(obj.get(), imp); } } return toJS(exec, obj.get()); } case YAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedLength> obj = imp->yAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedLength>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedLength>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedLength>(obj.get(), imp); } } return toJS(exec, obj.get()); } case WidthAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedLength> obj = imp->widthAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedLength>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedLength>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedLength>(obj.get(), imp); } } return toJS(exec, obj.get()); } case HeightAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedLength> obj = imp->heightAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedLength>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedLength>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedLength>(obj.get(), imp); } } return toJS(exec, obj.get()); } case FilterResXAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedInteger> obj = imp->filterResXAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedInteger>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedInteger>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedInteger>(obj.get(), imp); } } return toJS(exec, obj.get()); } case FilterResYAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedInteger> obj = imp->filterResYAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedInteger>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedInteger>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedInteger>(obj.get(), imp); } } return toJS(exec, obj.get()); } case HrefAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedString> obj = imp->hrefAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedString>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedString>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedString>(obj.get(), imp); } } return toJS(exec, obj.get()); } case XmllangAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); return jsString(imp->xmllang()); } case XmlspaceAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); return jsString(imp->xmlspace()); } case ExternalResourcesRequiredAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedBoolean>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedBoolean>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedBoolean>(obj.get(), imp); } } return toJS(exec, obj.get()); } case ClassNameAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); ASSERT(exec && exec->dynamicInterpreter()); RefPtr<SVGAnimatedString> obj = imp->classNameAnimated(); Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame(); if (activeFrame) { SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0); if (extensions) { if (extensions->hasGenericContext<SVGAnimatedString>(obj.get())) ASSERT(extensions->genericContext<SVGAnimatedString>(obj.get()) == imp); else extensions->setGenericContext<SVGAnimatedString>(obj.get(), imp); } } return toJS(exec, obj.get()); } case StyleAttrNum: { SVGFilterElement* imp = static_cast<SVGFilterElement*>(impl()); return toJS(exec, WTF::getPtr(imp->style())); } } return 0; }
PassRefPtr<FilterEffect> ReferenceFilterBuilder::build(Filter* parentFilter, RenderObject* renderer, FilterEffect* previousEffect, const ReferenceFilterOperation* filterOperation) { if (!renderer) return 0; Document* document = &renderer->document(); if (DocumentResourceReference* documentResourceRef = documentResourceReference(filterOperation)) { DocumentResource* cachedSVGDocument = documentResourceRef->document(); // If we have an SVG document, this is an external reference. Otherwise // we look up the referenced node in the current document. if (cachedSVGDocument) document = cachedSVGDocument->document(); } if (!document) return 0; Element* filter = document->getElementById(filterOperation->fragment()); if (!filter) { // Although we did not find the referenced filter, it might exist later // in the document document->accessSVGExtensions()->addPendingResource(filterOperation->fragment(), toElement(renderer->node())); return 0; } if (!filter->isSVGElement() || !filter->hasTagName(SVGNames::filterTag)) return 0; SVGFilterElement* filterElement = toSVGFilterElement(toSVGElement(filter)); // FIXME: Figure out what to do with SourceAlpha. Right now, we're // using the alpha of the original input layer, which is obviously // wrong. We should probably be extracting the alpha from the // previousEffect, but this requires some more processing. // This may need a spec clarification. RefPtr<SVGFilterBuilder> builder = SVGFilterBuilder::create(previousEffect, SourceAlpha::create(parentFilter)); ColorSpace filterColorSpace = ColorSpaceDeviceRGB; bool useFilterColorSpace = getSVGElementColorSpace(filterElement, filterColorSpace); for (Node* node = filterElement->firstChild(); node; node = node->nextSibling()) { if (!node->isSVGElement()) continue; SVGElement* element = toSVGElement(node); if (!element->isFilterEffect()) continue; SVGFilterPrimitiveStandardAttributes* effectElement = static_cast<SVGFilterPrimitiveStandardAttributes*>(element); RefPtr<FilterEffect> effect = effectElement->build(builder.get(), parentFilter); if (!effect) continue; effectElement->setStandardAttributes(effect.get()); effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement->primitiveUnitsCurrentValue(), parentFilter->sourceImageRect())); ColorSpace colorSpace = filterColorSpace; if (useFilterColorSpace || getSVGElementColorSpace(effectElement, colorSpace)) effect->setOperatingColorSpace(colorSpace); builder->add(effectElement->resultCurrentValue(), effect); } return builder->lastEffect(); }