sk_sp<SkImageFilter> FEImage::createImageFilterForLayoutObject(const LayoutObject& layoutObject) { FloatRect dstRect = filterPrimitiveSubregion(); AffineTransform transform; SVGElement* contextNode = toSVGElement(layoutObject.node()); if (contextNode->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(viewportSize)) transform = makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), dstRect); } else { transform.translate(dstRect.x(), dstRect.y()); } SkPictureBuilder filterPicture(dstRect); { TransformRecorder transformRecorder(filterPicture.context(), layoutObject, transform); SVGPaintContext::paintSubtree(filterPicture.context(), &layoutObject); } return SkPictureImageFilter::Make(toSkSp(filterPicture.endRecording()), dstRect); }
inline SVGElement* SVGSMILElement::eventBaseFor(const Condition& condition) { Element* eventBase = condition.baseID().isEmpty() ? targetElement() : treeScope().getElementById(AtomicString(condition.baseID())); if (eventBase && eventBase->isSVGElement()) return toSVGElement(eventBase); return nullptr; }
void KeyframeEffect::applyEffects() { ASSERT(isInEffect()); ASSERT(animation()); if (!m_target || !m_model) return; // Cancel composited animation of transform if a motion path has been introduced on the element. if (m_target->computedStyle() && m_target->computedStyle()->hasMotionPath() && animation()->hasActiveAnimationsOnCompositor() && animation()->affects(*m_target, CSSPropertyTransform)) { animation()->cancelAnimationOnCompositor(); } double iteration = currentIteration(); ASSERT(iteration >= 0); OwnPtrWillBeRawPtr<WillBeHeapVector<RefPtrWillBeMember<Interpolation>>> interpolations = m_sampledEffect ? m_sampledEffect->mutableInterpolations() : nullptr; // FIXME: Handle iteration values which overflow int. m_model->sample(static_cast<int>(iteration), timeFraction(), iterationDuration(), interpolations); if (m_sampledEffect) { m_sampledEffect->setInterpolations(interpolations.release()); } else if (interpolations && !interpolations->isEmpty()) { OwnPtrWillBeRawPtr<SampledEffect> sampledEffect = SampledEffect::create(this, interpolations.release()); m_sampledEffect = sampledEffect.get(); ensureAnimationStack(m_target).add(sampledEffect.release()); } else { return; } m_target->setNeedsAnimationStyleRecalc(); if (m_target->isSVGElement()) m_sampledEffect->applySVGUpdate(toSVGElement(*m_target)); }
AffineTransform SVGGraphicsElement::computeCTM(SVGElement::CTMScope mode, SVGGraphicsElement::StyleUpdateStrategy styleUpdateStrategy, const SVGGraphicsElement* ancestor) const { if (styleUpdateStrategy == AllowStyleUpdate) document().updateStyleAndLayoutIgnorePendingStylesheets(); AffineTransform ctm; bool done = false; for (const Element* currentElement = this; currentElement && !done; currentElement = currentElement->parentOrShadowHostElement()) { if (!currentElement->isSVGElement()) break; ctm = toSVGElement(currentElement)->localCoordinateSpaceTransform(mode).multiply(ctm); switch (mode) { case NearestViewportScope: // Stop at the nearest viewport ancestor. done = currentElement != this && isViewportElement(*currentElement); break; case AncestorScope: // Stop at the designated ancestor. done = currentElement == ancestor; break; default: ASSERT(mode == ScreenScope); break; } } return ctm; }
void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object) { ASSERT(context); ASSERT(style); ASSERT(object); ASSERT(object->node()); ASSERT(object->node()->isSVGElement()); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); context->setStrokeThickness(svgStyle->strokeWidth()->value(lengthContext)); context->setLineCap(svgStyle->capStyle()); context->setLineJoin(svgStyle->joinStyle()); context->setMiterLimit(svgStyle->strokeMiterLimit()); RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); if (dashes->isEmpty()) return; DashArray dashArray; SVGLengthList::ConstIterator it = dashes->begin(); SVGLengthList::ConstIterator itEnd = dashes->end(); for (; it != itEnd; ++it) dashArray.append(it->value(lengthContext)); context->setLineDash(dashArray, svgStyle->strokeDashOffset()->value(lengthContext)); }
bool CSSCursorImageValue::updateIfSVGCursorIsUsed(Element* element) { if (!element || !element->isSVGElement()) return false; if (!isSVGCursor()) return false; String url = toCSSImageValue(m_imageValue.get())->url(); if (SVGCursorElement* cursorElement = resourceReferencedByCursorElement(url, element->treeScope())) { // FIXME: This will override hot spot specified in CSS, which is probably incorrect. SVGLengthContext lengthContext(0); m_hotSpotSpecified = true; float x = roundf(cursorElement->x()->currentValue()->value(lengthContext)); m_hotSpot.setX(static_cast<int>(x)); float y = roundf(cursorElement->y()->currentValue()->value(lengthContext)); m_hotSpot.setY(static_cast<int>(y)); if (cachedImageURL() != element->document().completeURL(cursorElement->href()->currentValue()->value())) clearImageResource(); SVGElement* svgElement = toSVGElement(element); #if !ENABLE(OILPAN) m_referencedElements.add(svgElement); #endif svgElement->setCursorImageValue(this); cursorElement->addClient(svgElement); return true; } return false; }
static PassRefPtrWillBeRawPtr<Node> cloneNodeAndAssociate(Node& toClone) { RefPtrWillBeRawPtr<Node> clone = toClone.cloneNode(false); if (!clone->isSVGElement()) return clone.release(); SVGElement& svgElement = toSVGElement(toClone); ASSERT(!svgElement.correspondingElement()); toSVGElement(clone.get())->setCorrespondingElement(&svgElement); if (EventTargetData* data = toClone.eventTargetData()) data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(clone.get()); TrackExceptionState exceptionState; for (RefPtrWillBeRawPtr<Node> node = toClone.firstChild(); node && !exceptionState.hadException(); node = node->nextSibling()) clone->appendChild(cloneNodeAndAssociate(*node), exceptionState); return clone.release(); }
void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle* style, const RenderObject* object) { ASSERT(context); ASSERT(style); ASSERT(object); ASSERT(object->node()); ASSERT(object->node()->isSVGElement()); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); context->setStrokeThickness(svgStyle->strokeWidth().value(lengthContext)); context->setLineCap(svgStyle->capStyle()); context->setLineJoin(svgStyle->joinStyle()); if (svgStyle->joinStyle() == MiterJoin) context->setMiterLimit(svgStyle->strokeMiterLimit()); const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); if (dashes.isEmpty()) context->setStrokeStyle(SolidStroke); else { DashArray dashArray; const Vector<SVGLength>::const_iterator end = dashes.end(); for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) dashArray.append((*it).value(lengthContext)); context->setLineDash(dashArray, svgStyle->strokeDashOffset().value(lengthContext)); } }
RenderObject* SVGAElement::createRenderer(RenderStyle*) { if (parentNode() && parentNode()->isSVGElement() && toSVGElement(parentNode())->isTextContent()) return new RenderSVGInline(this); return new RenderSVGTransformableContainer(this); }
PassRefPtr<SkImageFilter> FEImage::createImageFilterForRenderer(RenderObject* renderer, SkiaImageFilterBuilder* builder) { FloatRect dstRect = filterPrimitiveSubregion(); AffineTransform transform; SVGElement* contextNode = toSVGElement(renderer->node()); if (contextNode->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(viewportSize)) transform = makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), dstRect); } else { transform.translate(dstRect.x(), dstRect.y()); } GraphicsContext* context = builder->context(); if (!context) return adoptRef(SkBitmapSource::Create(SkBitmap())); AffineTransform contentTransformation; context->save(); context->beginRecording(FloatRect(FloatPoint(), dstRect.size())); context->concatCTM(transform); SVGRenderingContext::renderSubtree(context, renderer, contentTransformation); RefPtr<DisplayList> displayList = context->endRecording(); context->restore(); RefPtr<SkImageFilter> result = adoptRef(SkPictureImageFilter::Create(displayList->picture(), dstRect)); return result.release(); }
bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundingBox, const FloatPoint& nodeAtPoint) { FloatPoint point = nodeAtPoint; if (!SVGRenderSupport::pointInClippingArea(this, point)) return false; SVGClipPathElement* clipPathElement = static_cast<SVGClipPathElement*>(node()); if (clipPathElement->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); point = transform.inverse().mapPoint(point); } point = clipPathElement->animatedLocalTransform().inverse().mapPoint(point); for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { RenderObject* renderer = childNode->renderer(); if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGStyledElement() || !renderer) continue; if (!renderer->isSVGShape() && !renderer->isSVGText() && !childNode->hasTagName(SVGNames::useTag)) continue; IntPoint hitPoint; HitTestResult result(hitPoint); if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent | HitTestRequest::DisallowShadowContent), result, point, HitTestForeground)) return true; } return false; }
void SVGRenderSupport::applyStrokeStyleToStrokeData(StrokeData* strokeData, const RenderStyle* style, const RenderObject* object) { ASSERT(strokeData); ASSERT(style); ASSERT(object); ASSERT(object->node()); ASSERT(object->node()->isSVGElement()); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); SVGLengthContext lengthContext(toSVGElement(object->node())); strokeData->setThickness(svgStyle->strokeWidth()->value(lengthContext)); strokeData->setLineCap(svgStyle->capStyle()); strokeData->setLineJoin(svgStyle->joinStyle()); strokeData->setMiterLimit(svgStyle->strokeMiterLimit()); RefPtr<SVGLengthList> dashes = svgStyle->strokeDashArray(); if (dashes->isEmpty()) return; DashArray dashArray; size_t length = dashes->length(); for (size_t i = 0; i < length; ++i) dashArray.append(dashes->at(i)->value(lengthContext)); strokeData->setLineDash(dashArray, svgStyle->strokeDashOffset()->value(lengthContext)); }
RenderPtr<RenderElement> SVGAElement::createElementRenderer(PassRef<RenderStyle> style) { if (parentNode() && parentNode()->isSVGElement() && toSVGElement(parentNode())->isTextContent()) return createRenderer<RenderSVGInline>(*this, WTF::move(style)); return createRenderer<RenderSVGTransformableContainer>(*this, WTF::move(style)); }
void SVGMPathElement::buildPendingResource() { clearResourceReferences(); if (!inDocument()) return; String id; Element* target = SVGURIReference::targetElementFromIRIString(href(), document(), &id); if (!target) { // Do not register as pending if we are already pending this resource. if (document().accessSVGExtensions()->isPendingResource(this, id)) return; if (!id.isEmpty()) { document().accessSVGExtensions()->addPendingResource(id, this); ASSERT(hasPendingResources()); } } else if (target->isSVGElement()) { // Register us with the target in the dependencies map. Any change of hrefElement // that leads to relayout/repainting now informs us, so we can react to it. document().accessSVGExtensions()->addElementReferencingTarget(this, toSVGElement(target)); } targetPathChanged(); }
void KeyframeEffect::applyEffects() { ASSERT(isInEffect()); ASSERT(animation()); if (!m_target || !m_model) return; if (hasIncompatibleStyle()) animation()->cancelAnimationOnCompositor(); double iteration = currentIteration(); ASSERT(iteration >= 0); bool changed = false; if (m_sampledEffect) { changed = m_model->sample(clampTo<int>(iteration, 0), timeFraction(), iterationDuration(), m_sampledEffect->mutableInterpolations()); } else { Vector<RefPtr<Interpolation>> interpolations; m_model->sample(clampTo<int>(iteration, 0), timeFraction(), iterationDuration(), interpolations); if (!interpolations.isEmpty()) { SampledEffect* sampledEffect = SampledEffect::create(this); sampledEffect->mutableInterpolations().swap(interpolations); m_sampledEffect = sampledEffect; ensureAnimationStack(m_target).add(sampledEffect); changed = true; } else { return; } } if (changed) { m_target->setNeedsAnimationStyleRecalc(); if (RuntimeEnabledFeatures::webAnimationsSVGEnabled() && m_target->isSVGElement()) toSVGElement(*m_target).setWebAnimationsPending(); } }
void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const RenderStyle& style, const RenderElement& renderer) { ASSERT(context); ASSERT(renderer.element()); ASSERT(renderer.element()->isSVGElement()); const SVGRenderStyle& svgStyle = style.svgStyle(); SVGLengthContext lengthContext(toSVGElement(renderer.element())); context->setStrokeThickness(svgStyle.strokeWidth().value(lengthContext)); context->setLineCap(svgStyle.capStyle()); context->setLineJoin(svgStyle.joinStyle()); if (svgStyle.joinStyle() == MiterJoin) context->setMiterLimit(svgStyle.strokeMiterLimit()); const Vector<SVGLength>& dashes = svgStyle.strokeDashArray(); if (dashes.isEmpty()) context->setStrokeStyle(SolidStroke); else { DashArray dashArray; dashArray.reserveInitialCapacity(dashes.size()); for (unsigned i = 0, size = dashes.size(); i < size; ++i) dashArray.uncheckedAppend(dashes[i].value(lengthContext)); context->setLineDash(dashArray, svgStyle.strokeDashOffset().value(lengthContext)); } }
bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstance* targetInstance, SVGElement*& newTarget) { ASSERT(referencedDocument()); Element* targetElement = SVGURIReference::targetElementFromIRIString(use->href(), *referencedDocument()); newTarget = 0; if (targetElement && targetElement->isSVGElement()) newTarget = toSVGElement(targetElement); if (!newTarget) return false; // Shortcut for self-references if (newTarget == this) return true; AtomicString targetId = newTarget->getIdAttribute(); SVGElementInstance* instance = targetInstance->parentNode(); while (instance) { SVGElement* element = instance->correspondingElement(); if (element->hasID() && element->getIdAttribute() == targetId && &element->document() == &newTarget->document()) return true; instance = instance->parentNode(); } return false; }
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(); }
void SVGUseElement::buildPendingResource() { if (inUseShadowTree()) return; clearShadowTree(); cancelShadowTreeRecreation(); if (!referencedScope() || !inDocument()) return; AtomicString id; Element* target = SVGURIReference::targetElementFromIRIString(hrefString(), treeScope(), &id, externalDocument()); if (!target || !target->inDocument()) { // If we can't find the target of an external element, just give up. // We can't observe if the target somewhen enters the external document, nor should we do it. if (externalDocument()) return; if (id.isEmpty()) return; referencedScope()->document().accessSVGExtensions().addPendingResource(id, this); ASSERT(hasPendingResources()); return; } if (target->isSVGElement()) { buildShadowAndInstanceTree(toSVGElement(target)); invalidateDependentShadowTrees(); } ASSERT(!m_needsShadowTreeRecreation); }
static inline const AtomicString& linkAttribute(const Element& element) { DCHECK(element.isLink()); if (element.isHTMLElement()) return element.fastGetAttribute(HTMLNames::hrefAttr); DCHECK(element.isSVGElement()); return SVGURIReference::legacyHrefString(toSVGElement(element)); }
void SVGUseElement::expandUseElementsInShadowTree(Node* element) { // Why expand the <use> elements in the shadow tree here, and not just // do this directly in buildShadowTree, if we encounter a <use> element? // // Short answer: Because we may miss to expand some elements. Ie. if a <symbol> // contains <use> tags, we'd miss them. So once we're done with settin' up the // actual shadow tree (after the special case modification for svg/symbol) we have // to walk it completely and expand all <use> elements. if (element->hasTagName(SVGNames::useTag)) { SVGUseElement* use = toSVGUseElement(element); ASSERT(!use->cachedDocumentIsStillLoading()); ASSERT(referencedDocument()); Element* targetElement = SVGURIReference::targetElementFromIRIString(use->href(), *referencedDocument()); SVGElement* target = 0; if (targetElement && targetElement->isSVGElement()) target = toSVGElement(targetElement); // Don't ASSERT(target) here, it may be "pending", too. // Setup sub-shadow tree root node RefPtr<SVGGElement> cloneParent = SVGGElement::create(SVGNames::gTag, *referencedDocument()); use->cloneChildNodes(cloneParent.get()); // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element. transferUseAttributesToReplacedElement(use, cloneParent.get()); if (target && !isDisallowedElement(*target)) { RefPtr<Element> newChild = target->cloneElementWithChildren(); ASSERT(newChild->isSVGElement()); cloneParent->appendChild(newChild.release()); } // We don't walk the target tree element-by-element, and clone each element, // but instead use cloneElementWithChildren(). This is an optimization for the common // case where <use> doesn't contain disallowed elements (ie. <foreignObject>). // Though if there are disallowed elements in the subtree, we have to remove them. // For instance: <use> on <g> containing <foreignObject> (indirect case). if (subtreeContainsDisallowedElement(*cloneParent)) removeDisallowedElementsFromSubtree(*cloneParent); RefPtr<Node> replacingElement(cloneParent.get()); // Replace <use> with referenced content. ASSERT(use->parentNode()); use->parentNode()->replaceChild(cloneParent.release(), use); // Expand the siblings because the *element* is replaced and we will // lose the sibling chain when we are back from recursion. element = replacingElement.get(); for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling()) expandUseElementsInShadowTree(sibling.get()); } for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) expandUseElementsInShadowTree(child.get()); }
static void writeStyle(TextStream& ts, const RenderObject& object) { const RenderStyle* style = object.style(); const SVGRenderStyle* svgStyle = style->svgStyle(); if (!object.localTransform().isIdentity()) writeNameValuePair(ts, "transform", object.localTransform()); writeIfNotDefault(ts, "image rendering", style->imageRendering(), RenderStyle::initialImageRendering()); writeIfNotDefault(ts, "opacity", style->opacity(), RenderStyle::initialOpacity()); if (object.isSVGShape()) { const RenderSVGShape& shape = static_cast<const RenderSVGShape&>(object); ASSERT(shape.node()); ASSERT(shape.node()->isSVGElement()); Color fallbackColor; if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), fallbackColor)) { TextStreamSeparator s(" "); ts << " [stroke={" << s; writeSVGPaintingResource(ts, strokePaintingResource); SVGLengthContext lengthContext(toSVGElement(shape.node())); double dashOffset = svgStyle->strokeDashOffset().value(lengthContext); double strokeWidth = svgStyle->strokeWidth().value(lengthContext); const Vector<SVGLength>& dashes = svgStyle->strokeDashArray(); DashArray dashArray; const Vector<SVGLength>::const_iterator end = dashes.end(); for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) dashArray.append((*it).value(lengthContext)); writeIfNotDefault(ts, "opacity", svgStyle->strokeOpacity(), 1.0f); writeIfNotDefault(ts, "stroke width", strokeWidth, 1.0); writeIfNotDefault(ts, "miter limit", svgStyle->strokeMiterLimit(), 4.0f); writeIfNotDefault(ts, "line cap", svgStyle->capStyle(), ButtCap); writeIfNotDefault(ts, "line join", svgStyle->joinStyle(), MiterJoin); writeIfNotDefault(ts, "dash offset", dashOffset, 0.0); if (!dashArray.isEmpty()) writeNameValuePair(ts, "dash array", dashArray); ts << "}]"; } if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(const_cast<RenderSVGShape*>(&shape), shape.style(), fallbackColor)) { TextStreamSeparator s(" "); ts << " [fill={" << s; writeSVGPaintingResource(ts, fillPaintingResource); writeIfNotDefault(ts, "opacity", svgStyle->fillOpacity(), 1.0f); writeIfNotDefault(ts, "fill rule", svgStyle->fillRule(), RULE_NONZERO); ts << "}]"; } writeIfNotDefault(ts, "clip rule", svgStyle->clipRule(), RULE_NONZERO); } writeIfNotEmpty(ts, "start marker", svgStyle->markerStartResource()); writeIfNotEmpty(ts, "middle marker", svgStyle->markerMidResource()); writeIfNotEmpty(ts, "end marker", svgStyle->markerEndResource()); }
void writeSVGGradientStop(TextStream& ts, const RenderSVGGradientStop& stop, int indent) { writeStandardPrefix(ts, stop, indent); SVGStopElement* stopElement = toSVGStopElement(toSVGElement(stop.element())); ASSERT(stopElement); ts << " [offset=" << stopElement->offset() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n"; }
SVGElement* SVGGraphicsElement::nearestViewportElement() const { for (Element* current = parentOrShadowHostElement(); current; current = current->parentOrShadowHostElement()) { if (isViewportElement(*current)) return toSVGElement(current); } return nullptr; }
SVGElement* SVGGraphicsElement::farthestViewportElement() const { SVGElement* farthest = 0; for (Element* current = parentOrShadowHostElement(); current; current = current->parentOrShadowHostElement()) { if (isViewportElement(*current)) farthest = toSVGElement(current); } return farthest; }
static bool hasValidPredecessor(const Node* node) { ASSERT(node); for (node = node->previousSibling(); node; node = node->previousSibling()) { if (node->isSVGElement() && toSVGElement(node)->isValid()) return true; } return false; }
SVGElement* SVGViewSpec::viewTarget() const { if (!m_contextElement) return 0; Element* element = m_contextElement->treeScope().getElementById(m_viewTargetString); if (!element || !element->isSVGElement()) return 0; return toSVGElement(element); }
SVGElement* SVGLocatable::farthestViewportElement(const SVGElement* element) { ASSERT(element); SVGElement* farthest = 0; for (Element* current = element->parentOrShadowHostElement(); current; current = current->parentOrShadowHostElement()) { if (isViewportElement(current)) farthest = toSVGElement(current); } return farthest; }
SVGElement* SVGLocatable::nearestViewportElement(const SVGElement* element) { ASSERT(element); for (Element* current = element->parentOrShadowHostElement(); current; current = current->parentOrShadowHostElement()) { if (isViewportElement(current)) return toSVGElement(current); } return 0; }
void KeyframeEffectReadOnly::attach(Animation* animation) { if (m_target) { m_target->ensureElementAnimations().animations().add(animation); m_target->setNeedsAnimationStyleRecalc(); if (RuntimeEnabledFeatures::webAnimationsSVGEnabled() && m_target->isSVGElement()) toSVGElement(m_target)->setWebAnimationsPending(); } AnimationEffectReadOnly::attach(animation); }