コード例 #1
0
void LayoutSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode)
{
    if ((m_clients.isEmpty() && m_resourceClients.isEmpty()) || m_isInvalidating)
        return;

    if (m_invalidationMask & mode)
        return;

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

    for (auto* client : m_clients) {
        if (client->isSVGResourceContainer()) {
            toLayoutSVGResourceContainer(client)->removeAllClientsFromCache(markForInvalidation);
            continue;
        }

        if (markForInvalidation)
            markClientForInvalidation(client, mode);

        LayoutSVGResourceContainer::markForLayoutAndParentResourceInvalidation(client, needsLayout);
    }

    markAllResourceClientsForInvalidation();

    m_isInvalidating = false;
}
コード例 #2
0
const LayoutSVGResourceContainer*
LayoutSVGResourcePattern::resolveContentElement() const {
  ASSERT(attributes().patternContentElement());
  LayoutSVGResourceContainer* expectedLayoutObject =
      toLayoutSVGResourceContainer(
          attributes().patternContentElement()->layoutObject());
  // No content inheritance - avoid walking the inheritance chain.
  if (this == expectedLayoutObject)
    return this;
  // Walk the inheritance chain on the LayoutObject-side. If we reach the
  // expected LayoutObject, all is fine. If we don't, there's a cycle that
  // the cycle resolver did break, and the resource will be content-less.
  const LayoutSVGResourceContainer* contentLayoutObject = this;
  while (SVGResources* resources =
             SVGResourcesCache::cachedResourcesForLayoutObject(
                 contentLayoutObject)) {
    LayoutSVGResourceContainer* linkedResource = resources->linkedResource();
    if (!linkedResource)
      break;
    if (linkedResource == expectedLayoutObject)
      return expectedLayoutObject;
    contentLayoutObject = linkedResource;
  }
  // There was a cycle, just use this resource as the "content resource" even
  // though it will be empty (have no children).
  return this;
}
コード例 #3
0
PassRefPtr<const SkPicture> LayoutSVGResourcePattern::asPicture(const FloatRect& tileBounds,
    const AffineTransform& tileTransform) const
{
    ASSERT(!m_shouldCollectPatternAttributes);

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

    FloatRect bounds(FloatPoint(), tileBounds.size());
    SkPictureBuilder pictureBuilder(bounds);

    ASSERT(attributes().patternContentElement());
    LayoutSVGResourceContainer* patternLayoutObject =
        toLayoutSVGResourceContainer(attributes().patternContentElement()->layoutObject());
    ASSERT(patternLayoutObject);
    ASSERT(!patternLayoutObject->needsLayout());

    SubtreeContentTransformScope contentTransformScope(contentTransform);

    {
        TransformRecorder transformRecorder(pictureBuilder.context(), *patternLayoutObject, tileTransform);
        for (LayoutObject* child = patternLayoutObject->firstChild(); child; child = child->nextSibling())
            SVGPaintContext::paintSubtree(&pictureBuilder.context(), child);
    }

    return pictureBuilder.endRecording();
}
コード例 #4
0
void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName) {
  bool isLengthAttr =
      attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
      attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr;

  if (isLengthAttr || attrName == SVGNames::maskUnitsAttr ||
      attrName == SVGNames::maskContentUnitsAttr ||
      SVGTests::isKnownAttribute(attrName)) {
    SVGElement::InvalidationGuard invalidationGuard(this);

    if (isLengthAttr) {
      invalidateSVGPresentationAttributeStyle();
      setNeedsStyleRecalc(LocalStyleChange,
                          StyleChangeReasonForTracing::fromAttribute(attrName));
      updateRelativeLengthsInformation();
    }

    LayoutSVGResourceContainer* layoutObject =
        toLayoutSVGResourceContainer(this->layoutObject());
    if (layoutObject)
      layoutObject->invalidateCacheAndMarkForLayout();

    return;
  }

  SVGElement::svgAttributeChanged(attrName);
}
コード例 #5
0
void PaintLayerFilterInfo::updateReferenceFilterClients(const FilterOperations& operations)
{
    removeReferenceFilterClients();
    for (size_t i = 0; i < operations.size(); ++i) {
        RefPtrWillBeRawPtr<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->layoutObject()->node()->document().getElementById(referenceFilterOperation->fragment());
            if (!isSVGFilterElement(filter))
                continue;
            if (filter->layoutObject())
                toLayoutSVGResourceContainer(filter->layoutObject())->addClientLayer(m_layer);
            else
                toSVGFilterElement(filter)->addClient(m_layer->layoutObject()->node());
            m_internalSVGReferences.append(filter);
        }
    }
}
コード例 #6
0
void SVGResourceClient::addFilterReference(SVGFilterElement* filter)
{
    if (filter->layoutObject())
        toLayoutSVGResourceContainer(filter->layoutObject())->addResourceClient(this);
    else
        filter->addClient(this);
    m_filterReferences.add(filter);
}
コード例 #7
0
bool LayoutSVGResourceGradient::isChildAllowed(LayoutObject* child, const ComputedStyle&) const
{
    if (child->isSVGGradientStop())
        return true;

    if (!child->isSVGResourceContainer())
        return false;

    return toLayoutSVGResourceContainer(child)->isSVGPaintServer();
}
コード例 #8
0
void SVGResourceClient::clearFilterReferences()
{
    for (SVGFilterElement* filter : m_filterReferences) {
        if (filter->layoutObject())
            toLayoutSVGResourceContainer(filter->layoutObject())->removeResourceClient(this);
        else
            filter->removeClient(this);
    }
    m_filterReferences.clear();
}
コード例 #9
0
void PaintLayerFilterInfo::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->layoutObject())
            toLayoutSVGResourceContainer(filter->layoutObject())->removeClientLayer(m_layer);
        else
            toSVGFilterElement(filter)->removeClient(m_layer->layoutObject()->node());
    }
    m_internalSVGReferences.clear();
}
コード例 #10
0
void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName)
{
    if (!isSupportedAttribute(attrName)) {
        SVGGradientElement::svgAttributeChanged(attrName);
        return;
    }

    SVGElement::InvalidationGuard invalidationGuard(this);

    updateRelativeLengthsInformation();

    LayoutSVGResourceContainer* renderer = toLayoutSVGResourceContainer(this->layoutObject());
    if (renderer)
        renderer->invalidateCacheAndMarkForLayout();
}
コード例 #11
0
    ClipPathHelper(GraphicsContext* context, const PaintLayer& paintLayer, PaintLayerPaintingInfo& paintingInfo, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed,
        const LayoutPoint& offsetFromRoot, PaintLayerFlags paintFlags)
        : m_resourceClipper(0), m_paintLayer(paintLayer), m_context(context)
    {
        const ComputedStyle& style = paintLayer.layoutObject()->styleRef();

        // Clip-path, like border radius, must not be applied to the contents of a composited-scrolling container.
        // It must, however, still be applied to the mask layer, so that the compositor can properly mask the
        // scrolling contents and scrollbars.
        if (!paintLayer.layoutObject()->hasClipPath() || (paintLayer.needsCompositedScrolling() && !(paintFlags & PaintLayerPaintingChildClippingMaskPhase)))
            return;

        m_clipperState = SVGClipPainter::ClipperNotApplied;

        paintingInfo.ancestorHasClipPathClipping = true;

        ASSERT(style.clipPath());
        if (style.clipPath()->type() == ClipPathOperation::SHAPE) {
            ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style.clipPath());
            if (clipPath->isValid()) {
                if (!rootRelativeBoundsComputed) {
                    rootRelativeBounds = paintLayer.physicalBoundingBoxIncludingReflectionAndStackingChildren(offsetFromRoot);
                    rootRelativeBoundsComputed = true;
                }
                m_clipPathRecorder.emplace(*context, *paintLayer.layoutObject(), clipPath->path(FloatRect(rootRelativeBounds)));
            }
        } else if (style.clipPath()->type() == ClipPathOperation::REFERENCE) {
            ReferenceClipPathOperation* referenceClipPathOperation = toReferenceClipPathOperation(style.clipPath());
            Document& document = paintLayer.layoutObject()->document();
            // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405)
            Element* element = document.getElementById(referenceClipPathOperation->fragment());
            if (isSVGClipPathElement(element) && element->layoutObject()) {
                if (!rootRelativeBoundsComputed) {
                    rootRelativeBounds = paintLayer.physicalBoundingBoxIncludingReflectionAndStackingChildren(offsetFromRoot);
                    rootRelativeBoundsComputed = true;
                }

                m_resourceClipper = toLayoutSVGResourceClipper(toLayoutSVGResourceContainer(element->layoutObject()));
                if (!SVGClipPainter(*m_resourceClipper).prepareEffect(*paintLayer.layoutObject(), FloatRect(rootRelativeBounds),
                    FloatRect(rootRelativeBounds), context, m_clipperState)) {
                    // No need to post-apply the clipper if this failed.
                    m_resourceClipper = 0;
                }
            }
        }
    }
コード例 #12
0
void SVGPatternElement::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();

    LayoutSVGResourceContainer* renderer = toLayoutSVGResourceContainer(this->layoutObject());
    if (renderer)
        renderer->invalidateCacheAndMarkForLayout();
}
コード例 #13
0
void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope)
{
    if (!inDocument())
        return;

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

    if (LayoutObject* layoutObject = this->layoutObject()) {
        if (hasRelativeLengths() && layoutObject->isSVGResourceContainer())
            toLayoutSVGResourceContainer(layoutObject)->invalidateCacheAndMarkForLayout(layoutScope);
        else if (selfHasRelativeLengths())
            layoutObject->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::Unknown, MarkContainerChain, layoutScope);
    }

    for (SVGElement* element : m_elementsWithRelativeLengths) {
        if (element != this)
            element->invalidateRelativeLengthClients(layoutScope);
    }
}
コード例 #14
0
void SVGResourcesCycleSolver::resolveCycles()
{
    ASSERT(m_activeResources.isEmpty());

    // If the starting LayoutObject is a resource container itself, then add it
    // to the active set (to break direct self-references.)
    if (m_layoutObject->isSVGResourceContainer())
        m_activeResources.add(toLayoutSVGResourceContainer(m_layoutObject));

    ResourceSet localResources;
    m_resources->buildSetOfResources(localResources);

    // This performs a depth-first search for a back-edge in all the
    // (potentially disjoint) graphs formed by the resources referenced by
    // |m_layoutObject|.
    for (auto* localResource : localResources) {
        if (m_activeResources.contains(localResource) || resourceContainsCycles(localResource))
            breakCycle(localResource);
    }

    m_activeResources.clear();
}
コード例 #15
0
void LayoutSVGResourceContainer::markForLayoutAndParentResourceInvalidation(LayoutObject* object, bool needsLayout)
{
    ASSERT(object);
    ASSERT(object->node());

    if (needsLayout && !object->documentBeingDestroyed())
        object->setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::SvgResourceInvalidated);

    removeFromCacheAndInvalidateDependencies(object, needsLayout);

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

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

        current = current->parent();
    }
}
コード例 #16
0
void writeSVGResourceContainer(TextStream& ts, const LayoutObject& object, int indent)
{
    writeStandardPrefix(ts, object, indent);

    Element* element = toElement(object.node());
    const AtomicString& id = element->getIdAttribute();
    writeNameAndQuotedValue(ts, "id", id);

    LayoutSVGResourceContainer* resource = toLayoutSVGResourceContainer(const_cast<LayoutObject*>(&object));
    ASSERT(resource);

    if (resource->resourceType() == MaskerResourceType) {
        LayoutSVGResourceMasker* masker = toLayoutSVGResourceMasker(resource);
        writeNameValuePair(ts, "maskUnits", masker->maskUnits());
        writeNameValuePair(ts, "maskContentUnits", masker->maskContentUnits());
        ts << "\n";
    } else if (resource->resourceType() == FilterResourceType) {
        LayoutSVGResourceFilter* filter = toLayoutSVGResourceFilter(resource);
        writeNameValuePair(ts, "filterUnits", filter->filterUnits());
        writeNameValuePair(ts, "primitiveUnits", filter->primitiveUnits());
        ts << "\n";
        // Creating a placeholder filter which is passed to the builder.
        FloatRect dummyRect;
        IntRect dummyIntRect;
        RefPtrWillBeRawPtr<SVGFilter> dummyFilter = SVGFilter::create(dummyIntRect, dummyRect, dummyRect, true);
        if (RefPtrWillBeRawPtr<SVGFilterBuilder> builder = filter->buildPrimitives(dummyFilter.get())) {
            if (FilterEffect* lastEffect = builder->lastEffect())
                lastEffect->externalRepresentation(ts, indent + 1);
        }
    } else if (resource->resourceType() == ClipperResourceType) {
        writeNameValuePair(ts, "clipPathUnits", toLayoutSVGResourceClipper(resource)->clipPathUnits());
        ts << "\n";
    } else if (resource->resourceType() == MarkerResourceType) {
        LayoutSVGResourceMarker* marker = toLayoutSVGResourceMarker(resource);
        writeNameValuePair(ts, "markerUnits", marker->markerUnits());
        ts << " [ref at " << marker->referencePoint() << "]";
        ts << " [angle=";
        if (marker->angle() == -1)
            ts << marker->orientType() << "]\n";
        else
            ts << marker->angle() << "]\n";
    } else if (resource->resourceType() == PatternResourceType) {
        LayoutSVGResourcePattern* pattern = static_cast<LayoutSVGResourcePattern*>(resource);

        // Dump final results that are used for layout. No use in asking SVGPatternElement for its patternUnits(), as it may
        // link to other patterns using xlink:href, we need to build the full inheritance chain, aka. collectPatternProperties()
        PatternAttributes attributes;
        toSVGPatternElement(pattern->element())->collectPatternAttributes(attributes);

        writeNameValuePair(ts, "patternUnits", attributes.patternUnits());
        writeNameValuePair(ts, "patternContentUnits", attributes.patternContentUnits());

        AffineTransform transform = attributes.patternTransform();
        if (!transform.isIdentity())
            ts << " [patternTransform=" << transform << "]";
        ts << "\n";
    } else if (resource->resourceType() == LinearGradientResourceType) {
        LayoutSVGResourceLinearGradient* gradient = static_cast<LayoutSVGResourceLinearGradient*>(resource);

        // Dump final results that are used for layout. No use in asking SVGGradientElement for its gradientUnits(), as it may
        // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties()
        LinearGradientAttributes attributes;
        toSVGLinearGradientElement(gradient->element())->collectGradientAttributes(attributes);
        writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.gradientUnits());

        ts << " [start=" << gradient->startPoint(attributes) << "] [end=" << gradient->endPoint(attributes) << "]\n";
    }  else if (resource->resourceType() == RadialGradientResourceType) {
        LayoutSVGResourceRadialGradient* gradient = toLayoutSVGResourceRadialGradient(resource);

        // Dump final results that are used for layout. No use in asking SVGGradientElement for its gradientUnits(), as it may
        // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties()
        RadialGradientAttributes attributes;
        toSVGRadialGradientElement(gradient->element())->collectGradientAttributes(attributes);
        writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.gradientUnits());

        FloatPoint focalPoint = gradient->focalPoint(attributes);
        FloatPoint centerPoint = gradient->centerPoint(attributes);
        float radius = gradient->radius(attributes);
        float focalRadius = gradient->focalRadius(attributes);

        ts << " [center=" << centerPoint << "] [focal=" << focalPoint << "] [radius=" << radius << "] [focalRadius=" << focalRadius << "]\n";
    } else {
        ts << "\n";
    }
    writeChildren(ts, object, indent);
}