void SVGSVGElement::collectStyleForPresentationAttribute( const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style) { SVGAnimatedPropertyBase* property = propertyFromAttribute(name); if (property == m_x) { addPropertyToPresentationAttributeStyle(style, CSSPropertyX, m_x->cssValue()); } else if (property == m_y) { addPropertyToPresentationAttributeStyle(style, CSSPropertyY, m_y->cssValue()); } else if (isOutermostSVGSVGElement() && (property == m_width || property == m_height)) { if (property == m_width) { addPropertyToPresentationAttributeStyle(style, CSSPropertyWidth, m_width->cssValue()); } else if (property == m_height) { addPropertyToPresentationAttributeStyle(style, CSSPropertyHeight, m_height->cssValue()); } } else { SVGGraphicsElement::collectStyleForPresentationAttribute(name, value, style); } }
RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*) { if (isOutermostSVGSVGElement()) return new (arena) RenderSVGRoot(this); return new (arena) RenderSVGViewportContainer(this); }
RenderPtr<RenderElement> SVGSVGElement::createElementRenderer(PassRef<RenderStyle> style) { if (isOutermostSVGSVGElement()) return createRenderer<RenderSVGRoot>(*this, std::move(style)); return createRenderer<RenderSVGViewportContainer>(*this, std::move(style)); }
LayoutObject* SVGSVGElement::createLayoutObject(const ComputedStyle&) { if (isOutermostSVGSVGElement()) return new LayoutSVGRoot(this); return new LayoutSVGViewportContainer(this); }
String SVGElement::title() const { // According to spec, we should not return titles when hovering over root <svg> elements (those // <title> elements are the title of the document, not a tooltip) so we instantly return. if (isOutermostSVGSVGElement()) return String(); // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title. if (isInShadowTree()) { Element* shadowHostElement = toShadowRoot(treeScope().rootNode()).host(); // At this time, SVG nodes are not allowed in non-<use> shadow trees, so any shadow root we do // have should be a use. The assert and following test is here to catch future shadow DOM changes // that do enable SVG in a shadow tree. ASSERT(!shadowHostElement || isSVGUseElement(*shadowHostElement)); if (isSVGUseElement(shadowHostElement)) { SVGUseElement& useElement = toSVGUseElement(*shadowHostElement); // If the <use> title is not empty we found the title to use. String useTitle(useElement.title()); if (!useTitle.isEmpty()) return useTitle; } } // If we aren't an instance in a <use> or the <use> title was not found, then find the first // <title> child of this element. // If a title child was found, return the text contents. if (Element* titleElement = Traversal<SVGTitleElement>::firstChild(*this)) return titleElement->innerText(); // Otherwise return a null/empty string. return String(); }
Frame* SVGSVGElement::frameForCurrentScale() const { // The behavior of currentScale() is undefined when we're dealing with non-standalone SVG documents. // If the document is embedded, the scaling is handled by the host renderer. if (!inDocument() || !isOutermostSVGSVGElement()) return nullptr; Frame* frame = document().frame(); return frame && frame->isMainFrame() ? frame : nullptr; }
bool SVGSVGElement::isPresentationAttribute(const QualifiedName& name) const { if (isOutermostSVGSVGElement() && (name == SVGNames::widthAttr || name == SVGNames::heightAttr)) return true; else if (name == SVGNames::xAttr || name == SVGNames::yAttr) return true; return SVGGraphicsElement::isPresentationAttribute(name); }
void SVGSVGElement::finishParsingChildren() { SVGGraphicsElement::finishParsingChildren(); // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent. if (isOutermostSVGSVGElement()) return; // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>) // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish sendSVGLoadEventIfPossible(); }
AffineTransform SVGSVGElement::localCoordinateSpaceTransform( SVGElement::CTMScope mode) const { AffineTransform viewBoxTransform; if (!hasEmptyViewBox()) { FloatSize size = currentViewportSize(); viewBoxTransform = viewBoxToViewTransform(size.width(), size.height()); } AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); transform.translate(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext)); } else if (mode == SVGElement::ScreenScope) { if (LayoutObject* layoutObject = this->layoutObject()) { FloatPoint location; float zoomFactor = 1; // At the SVG/HTML boundary (aka LayoutSVGRoot), we apply the // localToBorderBoxTransform to map an element from SVG viewport // coordinates to CSS box coordinates. LayoutSVGRoot's localToAbsolute // method expects CSS box coordinates. We also need to adjust for the // zoom level factored into CSS coordinates (bug #96361). if (layoutObject->isSVGRoot()) { location = toLayoutSVGRoot(layoutObject) ->localToBorderBoxTransform() .mapPoint(location); zoomFactor = 1 / layoutObject->style()->effectiveZoom(); } // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. location = layoutObject->localToAbsolute(location, UseTransforms); location.scale(zoomFactor, zoomFactor); // Be careful here! localToBorderBoxTransform() included the x/y offset // coming from the viewBoxToViewTransform(), so we have to subtract it // here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document().view()) { LayoutSize scrollOffset(view->getScrollOffset()); scrollOffset.scale(zoomFactor); transform.translate(-scrollOffset.width(), -scrollOffset.height()); } } } return transform.multiply(viewBoxTransform); }
float SVGSVGElement::currentScale() const { if (!inDocument() || !isOutermostSVGSVGElement()) return 1; Frame* frame = document().frame(); if (!frame) return 1; // The behaviour of currentScale() is undefined, when we're dealing with non-standalone SVG documents. // If the svg is embedded, the scaling is handled by the host renderer, so when asking from inside // the SVG document, a scale value of 1 seems reasonable, as it doesn't know anything about the parent scale. return frame->tree().parent() ? 1 : frame->pageZoomFactor(); }
void SVGSVGElement::setCurrentScale(float scale) { if (!inDocument() || !isOutermostSVGSVGElement()) return; Frame* frame = document().frame(); if (!frame) return; // The behaviour of setCurrentScale() is undefined, when we're dealing with non-standalone SVG documents. // We choose the ignore this call, it's pretty useless to support calling setCurrentScale() from within // an embedded SVG document, for the same reasons as in currentScale() - needs resolution by SVG WG. if (frame->tree().parent()) return; frame->setPageZoomFactor(scale); }
AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const { AffineTransform viewBoxTransform; if (!hasEmptyViewBox()) { FloatSize size = currentViewportSize(); viewBoxTransform = viewBoxToViewTransform(size.width(), size.height()); } AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); transform.translate(x().value(lengthContext), y().value(lengthContext)); } else if (mode == SVGLocatable::ScreenScope) { if (auto* renderer = this->renderer()) { FloatPoint location; float zoomFactor = 1; // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. // RenderSVGRoot's localToAbsolute method expects CSS box coordinates. // We also need to adjust for the zoom level factored into CSS coordinates (bug #96361). if (is<RenderSVGRoot>(*renderer)) { location = downcast<RenderSVGRoot>(*renderer).localToBorderBoxTransform().mapPoint(location); zoomFactor = 1 / renderer->style().effectiveZoom(); } // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. location = renderer->localToAbsolute(location, UseTransforms); location.scale(zoomFactor); // Be careful here! localToBorderBoxTransform() included the x/y offset coming from the viewBoxToViewTransform(), // so we have to subtract it here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document().view()) { LayoutPoint scrollPosition = view->scrollPosition(); scrollPosition.scale(zoomFactor); transform.translate(-scrollPosition.x(), -scrollPosition.y()); } } } return transform.multiply(viewBoxTransform); }
AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const { AffineTransform viewBoxTransform; if (hasAttribute(SVGNames::viewBoxAttr)) { FloatSize size = currentViewportSize(); viewBoxTransform = viewBoxToViewTransform(size.width(), size.height()); } AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); transform.translate(x().value(lengthContext), y().value(lengthContext)); } else if (mode == SVGLocatable::ScreenScope) { if (RenderObject* renderer = this->renderer()) { FloatPoint location; // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. // RenderSVGRoot's localToAbsolute method expects CSS box coordinates. if (renderer->isSVGRoot()) location = toRenderSVGRoot(renderer)->localToBorderBoxTransform().mapPoint(location); // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. location = renderer->localToAbsolute(location, false, true); // Be careful here! localToBorderBoxTransform() included the x/y offset coming from the viewBoxToViewTransform(), // so we have to subtract it here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document()->view()) { LayoutSize scrollOffset = view->scrollOffset(); transform.translate(-scrollOffset.width(), -scrollOffset.height()); } } } return transform.multiply(viewBoxTransform); }
String SVGElement::title() const { // According to spec, we should not return titles when hovering over root <svg> elements (those // <title> elements are the title of the document, not a tooltip) so we instantly return. if (isOutermostSVGSVGElement()) return String(); if (inUseShadowTree()) { String useTitle(shadowHost()->title()); if (!useTitle.isEmpty()) return useTitle; } // If we aren't an instance in a <use> or the <use> title was not found, then find the first // <title> child of this element. // If a title child was found, return the text contents. if (Element* titleElement = Traversal<SVGTitleElement>::firstChild(*this)) return titleElement->innerText(); // Otherwise return a null/empty string. return String(); }
bool SVGSVGElement::isPresentationAttribute(const QualifiedName& name) const { if ((name == SVGNames::widthAttr || name == SVGNames::heightAttr) && !isOutermostSVGSVGElement()) return false; return SVGGraphicsElement::isPresentationAttribute(name); }
RenderPtr<RenderElement> SVGSVGElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&) { if (isOutermostSVGSVGElement()) return createRenderer<RenderSVGRoot>(*this, WTFMove(style)); return createRenderer<RenderSVGViewportContainer>(*this, WTFMove(style)); }