blob: adf5c581dbccf18cb827a4bbf83f24c3b6c0469f [file] [log] [blame]
/*
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann
* <zimmermann@kde.org>
* Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
* Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
*
* 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 "core/svg/SVGMarkerElement.h"
#include "core/layout/svg/LayoutSVGResourceMarker.h"
#include "core/svg/SVGAngleTearOff.h"
#include "core/svg_names.h"
namespace blink {
template <>
const SVGEnumerationStringEntries&
GetStaticStringEntries<SVGMarkerUnitsType>() {
DEFINE_STATIC_LOCAL(SVGEnumerationStringEntries, entries, ());
if (entries.IsEmpty()) {
entries.push_back(
std::make_pair(kSVGMarkerUnitsUserSpaceOnUse, "userSpaceOnUse"));
entries.push_back(
std::make_pair(kSVGMarkerUnitsStrokeWidth, "strokeWidth"));
}
return entries;
}
inline SVGMarkerElement::SVGMarkerElement(Document& document)
: SVGElement(SVGNames::markerTag, document),
SVGFitToViewBox(this),
ref_x_(
SVGAnimatedLength::Create(this,
SVGNames::refXAttr,
SVGLength::Create(SVGLengthMode::kWidth))),
ref_y_(
SVGAnimatedLength::Create(this,
SVGNames::refYAttr,
SVGLength::Create(SVGLengthMode::kHeight))),
marker_width_(
SVGAnimatedLength::Create(this,
SVGNames::markerWidthAttr,
SVGLength::Create(SVGLengthMode::kWidth))),
marker_height_(
SVGAnimatedLength::Create(this,
SVGNames::markerHeightAttr,
SVGLength::Create(SVGLengthMode::kHeight))),
orient_angle_(SVGAnimatedAngle::Create(this)),
marker_units_(SVGAnimatedEnumeration<SVGMarkerUnitsType>::Create(
this,
SVGNames::markerUnitsAttr,
kSVGMarkerUnitsStrokeWidth)) {
// Spec: If the markerWidth/markerHeight attribute is not specified, the
// effect is as if a value of "3" were specified.
marker_width_->SetDefaultValueAsString("3");
marker_height_->SetDefaultValueAsString("3");
AddToPropertyMap(ref_x_);
AddToPropertyMap(ref_y_);
AddToPropertyMap(marker_width_);
AddToPropertyMap(marker_height_);
AddToPropertyMap(orient_angle_);
AddToPropertyMap(marker_units_);
}
void SVGMarkerElement::Trace(blink::Visitor* visitor) {
visitor->Trace(ref_x_);
visitor->Trace(ref_y_);
visitor->Trace(marker_width_);
visitor->Trace(marker_height_);
visitor->Trace(orient_angle_);
visitor->Trace(marker_units_);
SVGElement::Trace(visitor);
SVGFitToViewBox::Trace(visitor);
}
DEFINE_NODE_FACTORY(SVGMarkerElement)
AffineTransform SVGMarkerElement::ViewBoxToViewTransform(
float view_width,
float view_height) const {
return SVGFitToViewBox::ViewBoxToViewTransform(
viewBox()->CurrentValue()->Value(), preserveAspectRatio()->CurrentValue(),
view_width, view_height);
}
void SVGMarkerElement::SvgAttributeChanged(const QualifiedName& attr_name) {
bool viewbox_attribute_changed = SVGFitToViewBox::IsKnownAttribute(attr_name);
bool length_attribute_changed = attr_name == SVGNames::refXAttr ||
attr_name == SVGNames::refYAttr ||
attr_name == SVGNames::markerWidthAttr ||
attr_name == SVGNames::markerHeightAttr;
if (length_attribute_changed)
UpdateRelativeLengthsInformation();
if (viewbox_attribute_changed || length_attribute_changed ||
attr_name == SVGNames::markerUnitsAttr ||
attr_name == SVGNames::orientAttr) {
SVGElement::InvalidationGuard invalidation_guard(this);
auto* resource_container = ToLayoutSVGResourceContainer(GetLayoutObject());
if (resource_container) {
// The marker transform depends on both viewbox attributes, and the marker
// size attributes (width, height).
if (viewbox_attribute_changed || length_attribute_changed)
resource_container->SetNeedsTransformUpdate();
resource_container->InvalidateCacheAndMarkForLayout();
}
return;
}
SVGElement::SvgAttributeChanged(attr_name);
}
void SVGMarkerElement::ChildrenChanged(const ChildrenChange& change) {
SVGElement::ChildrenChanged(change);
if (change.by_parser)
return;
if (LayoutObject* object = GetLayoutObject())
object->SetNeedsLayoutAndFullPaintInvalidation(
LayoutInvalidationReason::kChildChanged);
}
void SVGMarkerElement::setOrientToAuto() {
setAttribute(SVGNames::orientAttr, "auto");
}
void SVGMarkerElement::setOrientToAngle(SVGAngleTearOff* angle) {
DCHECK(angle);
SVGAngle* target = angle->Target();
setAttribute(SVGNames::orientAttr, AtomicString(target->ValueAsString()));
}
LayoutObject* SVGMarkerElement::CreateLayoutObject(const ComputedStyle&) {
return new LayoutSVGResourceMarker(this);
}
bool SVGMarkerElement::SelfHasRelativeLengths() const {
return ref_x_->CurrentValue()->IsRelative() ||
ref_y_->CurrentValue()->IsRelative() ||
marker_width_->CurrentValue()->IsRelative() ||
marker_height_->CurrentValue()->IsRelative();
}
bool SVGMarkerElement::LayoutObjectIsNeeded(const ComputedStyle&) {
return IsValid() && HasSVGParent();
}
} // namespace blink