This source file includes following definitions.
- m_transform
- getTransformToElement
- isViewportElement
- computeCTM
- getCTM
- getScreenCTM
- getCTMFromJavascript
- getScreenCTMFromJavascript
- animatedLocalTransform
- supplementalTransform
- isSupportedAttribute
- parseAttribute
- svgAttributeChanged
- nearestViewportElement
- farthestViewportElement
- getBBox
- getBBoxFromJavascript
- createRenderer
- toClipPath
#include "config.h"
#include "core/svg/SVGGraphicsElement.h"
#include "SVGNames.h"
#include "core/rendering/svg/RenderSVGPath.h"
#include "core/rendering/svg/RenderSVGResource.h"
#include "core/rendering/svg/SVGPathData.h"
#include "core/svg/SVGElementInstance.h"
#include "platform/transforms/AffineTransform.h"
namespace WebCore {
SVGGraphicsElement::SVGGraphicsElement(const QualifiedName& tagName, Document& document, ConstructionType constructionType)
: SVGElement(tagName, document, constructionType)
, SVGTests(this)
, m_transform(SVGAnimatedTransformList::create(this, SVGNames::transformAttr, SVGTransformList::create()))
{
addToPropertyMap(m_transform);
}
SVGGraphicsElement::~SVGGraphicsElement()
{
}
PassRefPtr<SVGMatrixTearOff> SVGGraphicsElement::getTransformToElement(SVGElement* target, ExceptionState& exceptionState)
{
AffineTransform ctm = getCTM(AllowStyleUpdate);
if (target && target->isSVGGraphicsElement()) {
AffineTransform targetCTM = toSVGGraphicsElement(target)->getCTM(AllowStyleUpdate);
if (!targetCTM.isInvertible()) {
exceptionState.throwDOMException(InvalidStateError, "The target transformation is not invertable.");
return nullptr;
}
ctm = targetCTM.inverse() * ctm;
}
return SVGMatrixTearOff::create(ctm);
}
static bool isViewportElement(const Element& element)
{
return (isSVGSVGElement(element)
|| isSVGSymbolElement(element)
|| isSVGForeignObjectElement(element)
|| isSVGImageElement(element));
}
AffineTransform SVGGraphicsElement::computeCTM(SVGElement::CTMScope mode,
SVGGraphicsElement::StyleUpdateStrategy styleUpdateStrategy, const SVGGraphicsElement* ancestor) const
{
if (styleUpdateStrategy == AllowStyleUpdate)
document().updateLayoutIgnorePendingStylesheets();
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:
done = currentElement != this && isViewportElement(*currentElement);
break;
case AncestorScope:
done = currentElement == ancestor;
break;
default:
ASSERT(mode == ScreenScope);
break;
}
}
return ctm;
}
AffineTransform SVGGraphicsElement::getCTM(StyleUpdateStrategy styleUpdateStrategy)
{
return computeCTM(NearestViewportScope, styleUpdateStrategy);
}
AffineTransform SVGGraphicsElement::getScreenCTM(StyleUpdateStrategy styleUpdateStrategy)
{
return computeCTM(ScreenScope, styleUpdateStrategy);
}
PassRefPtr<SVGMatrixTearOff> SVGGraphicsElement::getCTMFromJavascript()
{
return SVGMatrixTearOff::create(getCTM());
}
PassRefPtr<SVGMatrixTearOff> SVGGraphicsElement::getScreenCTMFromJavascript()
{
return SVGMatrixTearOff::create(getScreenCTM());
}
AffineTransform SVGGraphicsElement::animatedLocalTransform() const
{
AffineTransform matrix;
RenderStyle* style = renderer() ? renderer()->style() : 0;
if (style && style->hasTransform()) {
TransformationMatrix transform;
style->applyTransform(transform, renderer()->objectBoundingBox());
matrix = transform.toAffineTransform();
float zoom = style->effectiveZoom();
if (zoom != 1) {
matrix.setE(matrix.e() / zoom);
matrix.setF(matrix.f() / zoom);
}
} else {
m_transform->currentValue()->concatenate(matrix);
}
if (m_supplementalTransform)
return *m_supplementalTransform * matrix;
return matrix;
}
AffineTransform* SVGGraphicsElement::supplementalTransform()
{
if (!m_supplementalTransform)
m_supplementalTransform = adoptPtr(new AffineTransform);
return m_supplementalTransform.get();
}
bool SVGGraphicsElement::isSupportedAttribute(const QualifiedName& attrName)
{
DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
if (supportedAttributes.isEmpty()) {
SVGTests::addSupportedAttributes(supportedAttributes);
supportedAttributes.add(SVGNames::transformAttr);
}
return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
}
void SVGGraphicsElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
if (!isSupportedAttribute(name)) {
SVGElement::parseAttribute(name, value);
return;
}
SVGParsingError parseError = NoError;
if (name == SVGNames::transformAttr)
m_transform->setBaseValueAsString(value, parseError);
else if (SVGTests::parseAttribute(name, value))
return;
else
ASSERT_NOT_REACHED();
reportAttributeParsingError(parseError, name, value);
}
void SVGGraphicsElement::svgAttributeChanged(const QualifiedName& attrName)
{
if (!isSupportedAttribute(attrName)) {
SVGElement::svgAttributeChanged(attrName);
return;
}
SVGElementInstance::InvalidationGuard invalidationGuard(this);
if (SVGTests::isKnownAttribute(attrName)) {
lazyReattachIfAttached();
return;
}
RenderObject* object = renderer();
if (!object)
return;
if (attrName == SVGNames::transformAttr) {
object->setNeedsTransformUpdate();
RenderSVGResource::markForLayoutAndParentResourceInvalidation(object);
return;
}
ASSERT_NOT_REACHED();
}
SVGElement* SVGGraphicsElement::nearestViewportElement() const
{
for (Element* current = parentOrShadowHostElement(); current; current = current->parentOrShadowHostElement()) {
if (isViewportElement(*current))
return toSVGElement(current);
}
return 0;
}
SVGElement* SVGGraphicsElement::farthestViewportElement() const
{
SVGElement* farthest = 0;
for (Element* current = parentOrShadowHostElement(); current; current = current->parentOrShadowHostElement()) {
if (isViewportElement(*current))
farthest = toSVGElement(current);
}
return farthest;
}
FloatRect SVGGraphicsElement::getBBox()
{
document().updateLayoutIgnorePendingStylesheets();
if (!renderer())
return FloatRect();
return renderer()->objectBoundingBox();
}
PassRefPtr<SVGRectTearOff> SVGGraphicsElement::getBBoxFromJavascript()
{
return SVGRectTearOff::create(SVGRect::create(getBBox()), 0, PropertyIsNotAnimVal);
}
RenderObject* SVGGraphicsElement::createRenderer(RenderStyle*)
{
return new RenderSVGPath(this);
}
void SVGGraphicsElement::toClipPath(Path& path)
{
updatePathFromGraphicsElement(this, path);
path.transform(animatedLocalTransform());
}
}