blob: f4729f3fc12bdd2dde7c896ca2f053035ba70253 [file] [log] [blame]
/*
* Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
* Copyright (C) 2009 Google, Inc.
*
* 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/layout/svg/LayoutSVGTransformableContainer.h"
#include "core/layout/svg/SVGLayoutSupport.h"
#include "core/svg/SVGGElement.h"
#include "core/svg/SVGGraphicsElement.h"
#include "core/svg/SVGUseElement.h"
namespace blink {
LayoutSVGTransformableContainer::LayoutSVGTransformableContainer(
SVGGraphicsElement* node)
: LayoutSVGContainer(node), m_needsTransformUpdate(true) {}
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;
}
bool LayoutSVGTransformableContainer::isChildAllowed(
LayoutObject* child,
const ComputedStyle& style) const {
ASSERT(element());
if (isSVGSwitchElement(*element())) {
Node* node = child->node();
// Reject non-SVG/non-valid elements.
if (!node->isSVGElement() || !toSVGElement(node)->isValid())
return false;
// Reject this child if it isn't the first valid node.
if (hasValidPredecessor(node))
return false;
} else if (isSVGAElement(*element())) {
// http://www.w3.org/2003/01/REC-SVG11-20030114-errata#linking-text-environment
// The 'a' element may contain any element that its parent may contain,
// except itself.
if (isSVGAElement(*child->node()))
return false;
if (parent() && parent()->isSVG())
return parent()->isChildAllowed(child, style);
}
return LayoutSVGContainer::isChildAllowed(child, style);
}
void LayoutSVGTransformableContainer::setNeedsTransformUpdate() {
setMayNeedPaintInvalidationSubtree();
m_needsTransformUpdate = true;
}
SVGTransformChange LayoutSVGTransformableContainer::calculateLocalTransform() {
SVGGraphicsElement* element = toSVGGraphicsElement(this->element());
ASSERT(element);
// If we're either the layoutObject for a <use> element, or for any <g>
// element inside the shadow tree, that was created during the use/symbol/svg
// expansion in SVGUseElement. These containers need to respect the
// translations induced by their corresponding use elements x/y attributes.
SVGUseElement* useElement = nullptr;
if (isSVGUseElement(*element)) {
useElement = toSVGUseElement(element);
} else if (isSVGGElement(*element) &&
toSVGGElement(element)->inUseShadowTree()) {
SVGElement* correspondingElement = element->correspondingElement();
if (isSVGUseElement(correspondingElement))
useElement = toSVGUseElement(correspondingElement);
}
if (useElement) {
SVGLengthContext lengthContext(element);
FloatSize translation(
useElement->x()->currentValue()->value(lengthContext),
useElement->y()->currentValue()->value(lengthContext));
// TODO(fs): Signal this on style update instead. (Since these are
// suppose to be presentation attributes now, this does feel a bit
// broken...)
if (translation != m_additionalTranslation)
setNeedsTransformUpdate();
m_additionalTranslation = translation;
}
if (!m_needsTransformUpdate)
return SVGTransformChange::None;
SVGTransformChangeDetector changeDetector(m_localTransform);
m_localTransform = element->calculateAnimatedLocalTransform();
m_localTransform.translate(m_additionalTranslation.width(),
m_additionalTranslation.height());
m_needsTransformUpdate = false;
return changeDetector.computeChange(m_localTransform);
}
} // namespace blink