std::unique_ptr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter& filter) const { static const unsigned maxCountChildNodes = 200; if (filterElement().countChildNodes() > maxCountChildNodes) return nullptr; FloatRect targetBoundingBox = filter.targetBoundingBox(); // Add effects to the builder auto builder = std::make_unique<SVGFilterBuilder>(SourceGraphic::create(filter)); for (auto& element : childrenOfType<SVGFilterPrimitiveStandardAttributes>(filterElement())) { RefPtr<FilterEffect> effect = element.build(builder.get(), filter); if (!effect) { builder->clearEffects(); return nullptr; } builder->appendEffectToEffectReferences(effect.copyRef(), element.renderer()); element.setStandardAttributes(effect.get()); effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(&element, filterElement().primitiveUnits(), targetBoundingBox)); if (element.renderer()) effect->setOperatingColorSpace(element.renderer()->style().svgStyle().colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceSRGB); builder->add(element.result(), WTFMove(effect)); } return builder; }
std::unique_ptr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter) { FloatRect targetBoundingBox = filter->targetBoundingBox(); // Add effects to the builder auto builder = std::make_unique<SVGFilterBuilder>(SourceGraphic::create(filter), SourceAlpha::create(filter)); auto children = childrenOfType<SVGFilterPrimitiveStandardAttributes>(filterElement()); for (auto element = children.begin(), end = children.end(); element != end; ++element) { RefPtr<FilterEffect> effect = element->build(builder.get(), filter); if (!effect) { builder->clearEffects(); return nullptr; } builder->appendEffectToEffectReferences(effect, element->renderer()); element->setStandardAttributes(effect.get()); effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(&*element, filterElement().primitiveUnits(), targetBoundingBox)); effect->setOperatingColorSpace(element->renderer()->style()->svgStyle()->colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB); builder->add(element->result(), effect.release()); } return builder; }
// Richtext simplification filter: Remove hard-coded font settings, // <style> elements, <p> attributes other than 'align' and // and unnecessary meta-information. QString simplifyRichTextFilter(const QString &in, bool *isPlainTextPtr = 0) { unsigned elementCount = 0; bool paragraphAlignmentFound = false; QString out; QXmlStreamReader reader(in); QXmlStreamWriter writer(&out); writer.setAutoFormatting(false); writer.setAutoFormattingIndent(0); while (!reader.atEnd()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement: elementCount++; if (filterElement(reader.name())) { const QStringRef name = reader.name(); QXmlStreamAttributes attributes = reader.attributes(); filterAttributes(name, &attributes, ¶graphAlignmentFound); writer.writeStartElement(name.toString()); if (!attributes.isEmpty()) writer.writeAttributes(attributes); } else reader.readElementText(); // Skip away all nested elements and characters. break; case QXmlStreamReader::Characters: if (!isWhiteSpace(reader.text())) writer.writeCharacters(reader.text().toString()); break; case QXmlStreamReader::EndElement: writer.writeEndElement(); break; default: break; } } // Check for plain text (no spans, just <html><head><body><p>) if (isPlainTextPtr) *isPlainTextPtr = !paragraphAlignmentFound && elementCount == 4u; // return out; }
FloatRect RenderSVGResourceFilter::resourceBoundingBox(const RenderObject& object) { return SVGLengthContext::resolveRectangle<SVGFilterElement>(&filterElement(), filterElement().filterUnits(), object.objectBoundingBox()); }
bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const RenderStyle&, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(context); ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); if (m_filter.contains(&renderer)) { FilterData* filterData = m_filter.get(&renderer); if (filterData->state == FilterData::PaintingSource || filterData->state == FilterData::Applying) filterData->state = FilterData::CycleDetected; return false; // Already built, or we're in a cycle, or we're marked for removal. Regardless, just do nothing more now. } auto filterData = std::make_unique<FilterData>(); FloatRect targetBoundingBox = renderer.objectBoundingBox(); filterData->boundaries = SVGLengthContext::resolveRectangle<SVGFilterElement>(&filterElement(), filterElement().filterUnits(), targetBoundingBox); if (filterData->boundaries.isEmpty()) return false; // Determine absolute transformation matrix for filter. AffineTransform absoluteTransform; SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer, 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); filterData->drawingRegion = renderer.strokeBoundingBox(); filterData->drawingRegion.intersect(filterData->boundaries); FloatRect absoluteDrawingRegion = filterData->shearFreeAbsoluteTransform.mapRect(filterData->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); static const unsigned maxTotalOfEffectInputs = 100; FilterEffect* lastEffect = filterData->builder->lastEffect(); if (!lastEffect || lastEffect->totalNumberOfEffectInputs() > maxTotalOfEffectInputs) 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 (filterData->drawingRegion.isEmpty()) { ASSERT(!m_filter.contains(&renderer)); filterData->savedContext = context; m_filter.set(&renderer, WTF::move(filterData)); 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); std::unique_ptr<ImageBuffer> sourceGraphic; RenderingMode renderingMode = renderer.frame().settings().acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; if (!SVGRenderingContext::createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, ColorSpaceLinearRGB, renderingMode)) { ASSERT(!m_filter.contains(&renderer)); filterData->savedContext = context; m_filter.set(&renderer, WTF::move(filterData)); return false; } // Set the rendering mode from the page's settings. filterData->filter->setRenderingMode(renderingMode); GraphicsContext* sourceGraphicContext = sourceGraphic->context(); ASSERT(sourceGraphicContext); filterData->sourceGraphicBuffer = WTF::move(sourceGraphic); filterData->savedContext = context; context = sourceGraphicContext; ASSERT(!m_filter.contains(&renderer)); m_filter.set(&renderer, WTF::move(filterData)); return true; }