void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode)
{
    if ((m_clients.isEmpty() && m_clientLayers.isEmpty()) || m_isInvalidating)
        return;

    if (m_invalidationMask & mode)
        return;

    m_invalidationMask |= mode;
    m_isInvalidating = true;
    bool needsLayout = mode == LayoutAndBoundariesInvalidation;
    bool markForInvalidation = mode != ParentOnlyInvalidation;

    HashSet<RenderObject*>::iterator end = m_clients.end();
    for (HashSet<RenderObject*>::iterator it = m_clients.begin(); it != end; ++it) {
        RenderObject* client = *it;
        if (client->isSVGResourceContainer()) {
            toRenderSVGResourceContainer(client)->removeAllClientsFromCache(markForInvalidation);
            continue;
        }

        if (markForInvalidation)
            markClientForInvalidation(client, mode);

        RenderSVGResource::markForLayoutAndParentResourceInvalidation(client, needsLayout);
    }

    markAllClientLayersForInvalidation();

    m_isInvalidating = false;
}
Exemplo n.º 2
0
void RenderLayerFilterInfo::updateReferenceFilterClients(const FilterOperations& operations)
{
    removeReferenceFilterClients();
    for (size_t i = 0; i < operations.size(); ++i) {
        RefPtr<FilterOperation> filterOperation = operations.operations().at(i);
        if (filterOperation->type() != FilterOperation::REFERENCE)
            continue;
        ReferenceFilterOperation* referenceFilterOperation = toReferenceFilterOperation(filterOperation.get());
        DocumentResourceReference* documentReference = ReferenceFilterBuilder::documentResourceReference(referenceFilterOperation);
        DocumentResource* cachedSVGDocument = documentReference ? documentReference->document() : 0;

        if (cachedSVGDocument) {
            // Reference is external; wait for notifyFinished().
            cachedSVGDocument->addClient(this);
            m_externalSVGReferences.append(cachedSVGDocument);
        } else {
            // Reference is internal; add layer as a client so we can trigger
            // filter paint invalidation on SVG attribute change.
            Element* filter = m_layer->renderer()->node()->document().getElementById(referenceFilterOperation->fragment());
            if (!isSVGFilterElement(filter))
                continue;
            if (filter->renderer())
                toRenderSVGResourceContainer(filter->renderer())->addClientRenderLayer(m_layer);
            else
                toSVGFilterElement(filter)->addClient(m_layer->renderer()->node());
            m_internalSVGReferences.append(filter);
        }
    }
}
Exemplo n.º 3
0
PassRefPtr<DisplayList> RenderSVGResourcePattern::asDisplayList(const FloatRect& tileBounds,
    const AffineTransform& tileTransform) const
{
    ASSERT(!m_shouldCollectPatternAttributes);

    AffineTransform contentTransform;
    if (m_attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
        contentTransform = tileTransform;

    // Draw the content into a DisplayList.
    GraphicsContext recordingContext(nullptr);
    recordingContext.beginRecording(FloatRect(FloatPoint(), tileBounds.size()));
    recordingContext.concatCTM(tileTransform);

    ASSERT(m_attributes.patternContentElement());
    RenderSVGResourceContainer* patternRenderer =
        toRenderSVGResourceContainer(m_attributes.patternContentElement()->renderer());
    ASSERT(patternRenderer);
    ASSERT(!patternRenderer->needsLayout());

    SubtreeContentTransformScope contentTransformScope(contentTransform);
    for (RenderObject* child = patternRenderer->firstChild(); child; child = child->nextSibling())
        SVGRenderingContext::renderSubtree(&recordingContext, child);

    return recordingContext.endRecording();
}
Exemplo n.º 4
0
void SVGFilterElement::setFilterRes(unsigned filterResX, unsigned filterResY)
{
    setFilterResXBaseValue(filterResX);
    setFilterResYBaseValue(filterResY);

    RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
    if (renderer)
        renderer->invalidateCacheAndMarkForLayout();
}
Exemplo n.º 5
0
void SVGResourcesCycleSolver::resolveCycles()
{
    ASSERT(m_allResources.isEmpty());

#if DEBUG_CYCLE_DETECTION > 0
    fprintf(stderr, "\nBefore cycle detection:\n");
    m_resources.dump(&m_renderer);
#endif

    // Stash all resources into a HashSet for the ease of traversing.
    HashSet<RenderSVGResourceContainer*> localResources;
    m_resources.buildSetOfResources(localResources);
    ASSERT(!localResources.isEmpty());

    // Add all parent resource containers to the HashSet.
    HashSet<RenderSVGResourceContainer*> ancestorResources;
    for (auto& resource : ancestorsOfType<RenderSVGResourceContainer>(m_renderer))
        ancestorResources.add(&resource);

#if DEBUG_CYCLE_DETECTION > 0
    fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n");
    {
        fprintf(stderr, "Local resources:\n");
        for (auto* resource : localResources)
            fprintf(stderr, "|> %s: object=%p (node=%p)\n", resource->renderName(), resource, resource->node());

        fprintf(stderr, "Parent resources:\n");
        for (auto* resource : ancestorResources)
            fprintf(stderr, "|> %s: object=%p (node=%p)\n", resource->renderName(), resource, resource->node());
    }
#endif

    // Build combined set of local and parent resources.
    m_allResources = localResources;
    for (auto* resource : ancestorResources)
        m_allResources.add(resource);

    // If we're a resource, add ourselves to the HashSet.
    if (m_renderer.isSVGResourceContainer())
        m_allResources.add(&toRenderSVGResourceContainer(m_renderer));

    ASSERT(!m_allResources.isEmpty());

    // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer'
    // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it.
    for (auto* resource : localResources) {
        if (ancestorResources.contains(resource) || resourceContainsCycles(*resource))
            breakCycle(*resource);
    }

#if DEBUG_CYCLE_DETECTION > 0
    fprintf(stderr, "\nAfter cycle detection:\n");
    m_resources.dump(m_renderer);
#endif

    m_allResources.clear();
}
Exemplo n.º 6
0
void SVGClipPathElement::svgAttributeChanged(const QualifiedName& attrName)
{
    if (!isSupportedAttribute(attrName)) {
        SVGGraphicsElement::svgAttributeChanged(attrName);
        return;
    }

    SVGElement::InvalidationGuard invalidationGuard(this);

    RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
    if (renderer)
        renderer->invalidateCacheAndMarkForLayout();
}
Exemplo n.º 7
0
void RenderLayerFilterInfo::removeReferenceFilterClients()
{
    for (size_t i = 0; i < m_externalSVGReferences.size(); ++i)
        m_externalSVGReferences.at(i)->removeClient(this);
    m_externalSVGReferences.clear();
    for (size_t i = 0; i < m_internalSVGReferences.size(); ++i) {
        Element* filter = m_internalSVGReferences.at(i).get();
        if (filter->renderer())
            toRenderSVGResourceContainer(filter->renderer())->removeClientRenderLayer(m_layer);
        else
            toSVGFilterElement(filter)->removeClient(m_layer->renderer()->node());
    }
    m_internalSVGReferences.clear();
}
Exemplo n.º 8
0
void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName)
{
    if (!isSupportedAttribute(attrName)) {
        SVGGradientElement::svgAttributeChanged(attrName);
        return;
    }

    SVGElement::InvalidationGuard invalidationGuard(this);

    updateRelativeLengthsInformation();

    RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
    if (renderer)
        renderer->invalidateCacheAndMarkForLayout();
}
Exemplo n.º 9
0
void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
    RenderObject::styleDidChange(diff, oldStyle);
    if (!diff.hasDifference())
        return;

    // <stop> elements should only be allowed to make renderers under gradient elements
    // but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient.
    SVGGradientElement* gradient = gradientElement();
    if (!gradient)
        return;

    RenderObject* renderer = gradient->renderer();
    if (!renderer)
        return;

    RenderSVGResourceContainer* container = toRenderSVGResourceContainer(renderer);
    container->removeAllClientsFromCache();
}
Exemplo n.º 10
0
void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName)
{
    if (!isSupportedAttribute(attrName)) {
        SVGElement::svgAttributeChanged(attrName);
        return;
    }

    SVGElement::InvalidationGuard invalidationGuard(this);

    if (attrName == SVGNames::xAttr
        || attrName == SVGNames::yAttr
        || attrName == SVGNames::widthAttr
        || attrName == SVGNames::heightAttr)
        updateRelativeLengthsInformation();

    RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
    if (renderer)
        renderer->invalidateCacheAndMarkForLayout();
}
Exemplo n.º 11
0
void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope)
{
    if (!inDocument())
        return;

    ASSERT(!m_inRelativeLengthClientsInvalidation);
#if ENABLE(ASSERT)
    TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true);
#endif

    RenderObject* renderer = this->renderer();
    if (renderer && selfHasRelativeLengths()) {
        if (renderer->isSVGResourceContainer())
            toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope);
        else
            renderer->setNeedsLayoutAndFullPaintInvalidation(MarkContainingBlockChain, layoutScope);
    }

    WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator end = m_elementsWithRelativeLengths.end();
    for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) {
        if (*it != this)
            (*it)->invalidateRelativeLengthClients(layoutScope);
    }
}
Exemplo n.º 12
0
void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* object, bool needsLayout)
{
    ASSERT(object);
    ASSERT(object->node());

    if (needsLayout && !object->documentBeingDestroyed())
        object->setNeedsLayoutAndFullRepaint();

    removeFromCacheAndInvalidateDependencies(object, needsLayout);

    // Invalidate resources in ancestor chain, if needed.
    RenderObject* current = object->parent();
    while (current) {
        removeFromCacheAndInvalidateDependencies(current, needsLayout);

        if (current->isSVGResourceContainer()) {
            // This will process the rest of the ancestors.
            toRenderSVGResourceContainer(current)->removeAllClientsFromCache();
            break;
        }

        current = current->parent();
    }
}
Exemplo n.º 13
0
void SVGResourcesCycleSolver::resolveCycles()
{
    ASSERT(m_allResources.isEmpty());

#if DEBUG_CYCLE_DETECTION > 0
    fprintf(stderr, "\nBefore cycle detection:\n");
    m_resources->dump(m_renderer);
#endif

    // Stash all resources into a HashSet for the ease of traversing.
    HashSet<RenderSVGResourceContainer*> localResources;
    m_resources->buildSetOfResources(localResources);
    ASSERT(!localResources.isEmpty());

    // Add all parent resource containers to the HashSet.
    HashSet<RenderSVGResourceContainer*> parentResources;
    RenderObject* parent = m_renderer->parent();
    while (parent) {
        if (parent->isSVGResourceContainer())
            parentResources.add(toRenderSVGResourceContainer(parent));
        parent = parent->parent();
    }

#if DEBUG_CYCLE_DETECTION > 0
    fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n");
    {
        fprintf(stderr, "Local resources:\n");
        HashSet<RenderSVGResourceContainer*>::iterator end = localResources.end();
        for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it)
            fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node());

        fprintf(stderr, "Parent resources:\n");
        end = parentResources.end();
        for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it)
            fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node());
    }
#endif

    // Build combined set of local and parent resources.
    m_allResources = localResources;
    HashSet<RenderSVGResourceContainer*>::iterator end = parentResources.end();
    for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it)
        m_allResources.add(*it);

    // If we're a resource, add ourselves to the HashSet.
    if (m_renderer->isSVGResourceContainer())
        m_allResources.add(toRenderSVGResourceContainer(m_renderer));

    ASSERT(!m_allResources.isEmpty());

    // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer'
    // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it.
    end = localResources.end();
    for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) {
        RenderSVGResourceContainer* resource = *it;
        if (parentResources.contains(resource) || resourceContainsCycles(resource))
            breakCycle(resource);
    }

#if DEBUG_CYCLE_DETECTION > 0
    fprintf(stderr, "\nAfter cycle detection:\n");
    m_resources->dump(m_renderer);
#endif

    m_allResources.clear();
}