blob: 6b8cffd0da8e91fe26b3dcc4add90a88fea2e9f4 [file] [log] [blame]
/*
* Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "third_party/blink/renderer/core/svg/svg_path_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/svg/svg_mpath_element.h"
#include "third_party/blink/renderer/core/svg/svg_path_query.h"
#include "third_party/blink/renderer/core/svg/svg_path_utilities.h"
#include "third_party/blink/renderer/core/svg/svg_point_tear_off.h"
namespace blink {
inline SVGPathElement::SVGPathElement(Document& document)
: SVGGeometryElement(svg_names::kPathTag, document),
path_(SVGAnimatedPath::Create(this, svg_names::kDAttr, CSSPropertyD)) {
AddToPropertyMap(path_);
}
void SVGPathElement::Trace(blink::Visitor* visitor) {
visitor->Trace(path_);
SVGGeometryElement::Trace(visitor);
}
DEFINE_NODE_FACTORY(SVGPathElement)
Path SVGPathElement::AttributePath() const {
return path_->CurrentValue()->GetStylePath()->GetPath();
}
const StylePath* SVGPathElement::GetStylePath() const {
if (LayoutObject* layout_object = this->GetLayoutObject()) {
const StylePath* style_path = layout_object->StyleRef().SvgStyle().D();
if (style_path)
return style_path;
return StylePath::EmptyPath();
}
return path_->CurrentValue()->GetStylePath();
}
float SVGPathElement::ComputePathLength() const {
return GetStylePath()->length();
}
Path SVGPathElement::AsPath() const {
return GetStylePath()->GetPath();
}
float SVGPathElement::getTotalLength() {
GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
return SVGPathQuery(PathByteStream()).GetTotalLength();
}
SVGPointTearOff* SVGPathElement::getPointAtLength(float length) {
GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
SVGPathQuery path_query(PathByteStream());
if (length < 0) {
length = 0;
} else {
float computed_length = path_query.GetTotalLength();
if (length > computed_length)
length = computed_length;
}
FloatPoint point = path_query.GetPointAtLength(length);
return SVGPointTearOff::CreateDetached(point);
}
void SVGPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
if (attr_name == svg_names::kDAttr) {
InvalidateMPathDependencies();
GeometryPresentationAttributeChanged(attr_name);
return;
}
SVGGeometryElement::SvgAttributeChanged(attr_name);
}
void SVGPathElement::CollectStyleForPresentationAttribute(
const QualifiedName& name,
const AtomicString& value,
MutableCSSPropertyValueSet* style) {
SVGAnimatedPropertyBase* property = PropertyFromAttribute(name);
if (property == path_) {
SVGAnimatedPath* path = this->GetPath();
// If this is a <use> instance, return the referenced path to maximize
// geometry sharing.
if (const SVGElement* element = CorrespondingElement())
path = ToSVGPathElement(element)->GetPath();
AddPropertyToPresentationAttributeStyle(style, property->CssPropertyId(),
path->CssValue());
return;
}
SVGGeometryElement::CollectStyleForPresentationAttribute(name, value, style);
}
void SVGPathElement::InvalidateMPathDependencies() {
// <mpath> can only reference <path> but this dependency is not handled in
// markForLayoutAndParentResourceInvalidation so we update any mpath
// dependencies manually.
if (SVGElementSet* dependencies = SetOfIncomingReferences()) {
for (SVGElement* element : *dependencies) {
if (auto* mpath = ToSVGMPathElementOrNull(*element))
mpath->TargetPathChanged();
}
}
}
Node::InsertionNotificationRequest SVGPathElement::InsertedInto(
ContainerNode& root_parent) {
SVGGeometryElement::InsertedInto(root_parent);
InvalidateMPathDependencies();
return kInsertionDone;
}
void SVGPathElement::RemovedFrom(ContainerNode& root_parent) {
SVGGeometryElement::RemovedFrom(root_parent);
InvalidateMPathDependencies();
}
FloatRect SVGPathElement::GetBBox() {
// We want the exact bounds.
return SVGPathElement::AsPath().BoundingRect();
}
} // namespace blink