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;
}
Exemple #2
0
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;
}
Exemple #3
0
// 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, &paragraphAlignmentFound);
				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;
}