This source file includes following definitions.
- create
- baseVal
- m_lengthAdjust
- getNumberOfChars
- getComputedTextLength
- getSubStringLength
- getStartPositionOfChar
- getEndPositionOfChar
- getExtentOfChar
- getRotationOfChar
- getCharNumAtPosition
- selectSubString
- isSupportedAttribute
- isPresentationAttribute
- collectStyleForPresentationAttribute
- parseAttribute
- svgAttributeChanged
- selfHasRelativeLengths
- elementFromRenderer
#include "config.h"
#include "core/svg/SVGTextContentElement.h"
#include "CSSPropertyNames.h"
#include "CSSValueKeywords.h"
#include "SVGNames.h"
#include "XMLNames.h"
#include "bindings/v8/ExceptionMessages.h"
#include "bindings/v8/ExceptionState.h"
#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "core/editing/FrameSelection.h"
#include "core/frame/LocalFrame.h"
#include "core/rendering/RenderObject.h"
#include "core/rendering/svg/RenderSVGResource.h"
#include "core/rendering/svg/SVGTextQuery.h"
#include "core/svg/SVGElementInstance.h"
namespace WebCore {
template<> const SVGEnumerationStringEntries& getStaticStringEntries<SVGLengthAdjustType>()
{
DEFINE_STATIC_LOCAL(SVGEnumerationStringEntries, entries, ());
if (entries.isEmpty()) {
entries.append(std::make_pair(SVGLengthAdjustUnknown, emptyString()));
entries.append(std::make_pair(SVGLengthAdjustSpacing, "spacing"));
entries.append(std::make_pair(SVGLengthAdjustSpacingAndGlyphs, "spacingAndGlyphs"));
}
return entries;
}
class SVGAnimatedTextLength FINAL : public SVGAnimatedLength {
public:
static PassRefPtr<SVGAnimatedTextLength> create(SVGTextContentElement* contextElement)
{
return adoptRef(new SVGAnimatedTextLength(contextElement));
}
virtual SVGLengthTearOff* baseVal() OVERRIDE
{
SVGTextContentElement* textContentElement = toSVGTextContentElement(contextElement());
if (!textContentElement->textLengthIsSpecifiedByUser())
baseValue()->newValueSpecifiedUnits(LengthTypeNumber, textContentElement->getComputedTextLength());
return SVGAnimatedLength::baseVal();
}
private:
SVGAnimatedTextLength(SVGTextContentElement* contextElement)
: SVGAnimatedLength(contextElement, SVGNames::textLengthAttr, SVGLength::create(LengthModeOther), ForbidNegativeLengths)
{
}
};
SVGTextContentElement::SVGTextContentElement(const QualifiedName& tagName, Document& document)
: SVGGraphicsElement(tagName, document)
, m_textLength(SVGAnimatedTextLength::create(this))
, m_textLengthIsSpecifiedByUser(false)
, m_lengthAdjust(SVGAnimatedEnumeration<SVGLengthAdjustType>::create(this, SVGNames::lengthAdjustAttr, SVGLengthAdjustSpacing))
{
ScriptWrappable::init(this);
addToPropertyMap(m_textLength);
addToPropertyMap(m_lengthAdjust);
}
unsigned SVGTextContentElement::getNumberOfChars()
{
document().updateLayoutIgnorePendingStylesheets();
return SVGTextQuery(renderer()).numberOfCharacters();
}
float SVGTextContentElement::getComputedTextLength()
{
document().updateLayoutIgnorePendingStylesheets();
return SVGTextQuery(renderer()).textLength();
}
float SVGTextContentElement::getSubStringLength(unsigned charnum, unsigned nchars, ExceptionState& exceptionState)
{
document().updateLayoutIgnorePendingStylesheets();
unsigned numberOfChars = getNumberOfChars();
if (charnum >= numberOfChars) {
exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("charnum", charnum, getNumberOfChars()));
return 0.0f;
}
if (nchars > numberOfChars - charnum)
nchars = numberOfChars - charnum;
return SVGTextQuery(renderer()).subStringLength(charnum, nchars);
}
PassRefPtr<SVGPointTearOff> SVGTextContentElement::getStartPositionOfChar(unsigned charnum, ExceptionState& exceptionState)
{
document().updateLayoutIgnorePendingStylesheets();
if (charnum > getNumberOfChars()) {
exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("charnum", charnum, getNumberOfChars()));
return nullptr;
}
FloatPoint point = SVGTextQuery(renderer()).startPositionOfCharacter(charnum);
return SVGPointTearOff::create(SVGPoint::create(point), 0, PropertyIsNotAnimVal);
}
PassRefPtr<SVGPointTearOff> SVGTextContentElement::getEndPositionOfChar(unsigned charnum, ExceptionState& exceptionState)
{
document().updateLayoutIgnorePendingStylesheets();
if (charnum > getNumberOfChars()) {
exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("charnum", charnum, getNumberOfChars()));
return nullptr;
}
FloatPoint point = SVGTextQuery(renderer()).endPositionOfCharacter(charnum);
return SVGPointTearOff::create(SVGPoint::create(point), 0, PropertyIsNotAnimVal);
}
PassRefPtr<SVGRectTearOff> SVGTextContentElement::getExtentOfChar(unsigned charnum, ExceptionState& exceptionState)
{
document().updateLayoutIgnorePendingStylesheets();
if (charnum > getNumberOfChars()) {
exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("charnum", charnum, getNumberOfChars()));
return nullptr;
}
FloatRect rect = SVGTextQuery(renderer()).extentOfCharacter(charnum);
return SVGRectTearOff::create(SVGRect::create(rect), 0, PropertyIsNotAnimVal);
}
float SVGTextContentElement::getRotationOfChar(unsigned charnum, ExceptionState& exceptionState)
{
document().updateLayoutIgnorePendingStylesheets();
if (charnum > getNumberOfChars()) {
exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("charnum", charnum, getNumberOfChars()));
return 0.0f;
}
return SVGTextQuery(renderer()).rotationOfCharacter(charnum);
}
int SVGTextContentElement::getCharNumAtPosition(PassRefPtr<SVGPointTearOff> point, ExceptionState& exceptionState)
{
document().updateLayoutIgnorePendingStylesheets();
return SVGTextQuery(renderer()).characterNumberAtPosition(point->target()->value());
}
void SVGTextContentElement::selectSubString(unsigned charnum, unsigned nchars, ExceptionState& exceptionState)
{
unsigned numberOfChars = getNumberOfChars();
if (charnum >= numberOfChars) {
exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("charnum", charnum, getNumberOfChars()));
return;
}
if (nchars > numberOfChars - charnum)
nchars = numberOfChars - charnum;
ASSERT(document().frame());
VisiblePosition start(firstPositionInNode(const_cast<SVGTextContentElement*>(this)));
for (unsigned i = 0; i < charnum; ++i)
start = start.next();
VisiblePosition end(start);
for (unsigned i = 0; i < nchars; ++i)
end = end.next();
document().frame()->selection().setSelection(VisibleSelection(start, end));
}
bool SVGTextContentElement::isSupportedAttribute(const QualifiedName& attrName)
{
DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
if (supportedAttributes.isEmpty()) {
supportedAttributes.add(SVGNames::lengthAdjustAttr);
supportedAttributes.add(SVGNames::textLengthAttr);
supportedAttributes.add(XMLNames::spaceAttr);
}
return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
}
bool SVGTextContentElement::isPresentationAttribute(const QualifiedName& name) const
{
if (name.matches(XMLNames::spaceAttr))
return true;
return SVGGraphicsElement::isPresentationAttribute(name);
}
void SVGTextContentElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
{
if (!isSupportedAttribute(name))
SVGGraphicsElement::collectStyleForPresentationAttribute(name, value, style);
else if (name.matches(XMLNames::spaceAttr)) {
DEFINE_STATIC_LOCAL(const AtomicString, preserveString, ("preserve", AtomicString::ConstructFromLiteral));
if (value == preserveString)
addPropertyToPresentationAttributeStyle(style, CSSPropertyWhiteSpace, CSSValuePre);
else
addPropertyToPresentationAttributeStyle(style, CSSPropertyWhiteSpace, CSSValueNowrap);
}
}
void SVGTextContentElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
SVGParsingError parseError = NoError;
if (!isSupportedAttribute(name))
SVGGraphicsElement::parseAttribute(name, value);
else if (name == SVGNames::lengthAdjustAttr) {
m_lengthAdjust->setBaseValueAsString(value, parseError);
} else if (name == SVGNames::textLengthAttr) {
m_textLength->setBaseValueAsString(value, parseError);
} else if (name.matches(XMLNames::spaceAttr)) {
} else
ASSERT_NOT_REACHED();
reportAttributeParsingError(parseError, name, value);
}
void SVGTextContentElement::svgAttributeChanged(const QualifiedName& attrName)
{
if (!isSupportedAttribute(attrName)) {
SVGGraphicsElement::svgAttributeChanged(attrName);
return;
}
if (attrName == SVGNames::textLengthAttr)
m_textLengthIsSpecifiedByUser = true;
SVGElementInstance::InvalidationGuard invalidationGuard(this);
if (RenderObject* renderer = this->renderer())
RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
}
bool SVGTextContentElement::selfHasRelativeLengths() const
{
return true;
}
SVGTextContentElement* SVGTextContentElement::elementFromRenderer(RenderObject* renderer)
{
if (!renderer)
return 0;
if (!renderer->isSVGText() && !renderer->isSVGInline())
return 0;
SVGElement* element = toSVGElement(renderer->node());
ASSERT(element);
return isSVGTextContentElement(*element) ? toSVGTextContentElement(element) : 0;
}
}