diff -r 000000000000 -r 4f2f89ce4247 WebCore/dom/Element.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/dom/Element.h Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,453 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Peter Kelly (pmk@post.com) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. 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. + * + */ + +#ifndef Element_h +#define Element_h + +#include "Document.h" +#include "FragmentScriptingPermission.h" +#include "NamedNodeMap.h" +#include "ScrollTypes.h" + +namespace WebCore { + +class Attribute; +class ClientRect; +class ClientRectList; +class DOMStringMap; +class ElementRareData; +class IntSize; + +class Element : public ContainerNode { +public: + static PassRefPtr create(const QualifiedName&, Document*); + virtual ~Element(); + + DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); + DEFINE_ATTRIBUTE_EVENT_LISTENER(change); + DEFINE_ATTRIBUTE_EVENT_LISTENER(click); + DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dblclick); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragenter); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragover); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragleave); + DEFINE_ATTRIBUTE_EVENT_LISTENER(drop); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(drag); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend); + DEFINE_ATTRIBUTE_EVENT_LISTENER(input); + DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keypress); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseover); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseup); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mousewheel); + DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll); + DEFINE_ATTRIBUTE_EVENT_LISTENER(select); + DEFINE_ATTRIBUTE_EVENT_LISTENER(submit); + + // These four attribute event handler attributes are overridden by HTMLBodyElement + // and HTMLFrameSetElement to forward to the DOMWindow. + DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(blur); + DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(error); + DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(focus); + DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(load); + + // WebKit extensions + DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecut); + DEFINE_ATTRIBUTE_EVENT_LISTENER(cut); + DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecopy); + DEFINE_ATTRIBUTE_EVENT_LISTENER(copy); + DEFINE_ATTRIBUTE_EVENT_LISTENER(beforepaste); + DEFINE_ATTRIBUTE_EVENT_LISTENER(paste); + DEFINE_ATTRIBUTE_EVENT_LISTENER(reset); + DEFINE_ATTRIBUTE_EVENT_LISTENER(search); + DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart); +#if ENABLE(TOUCH_EVENTS) + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend); + DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel); +#endif +#if ENABLE(TRANSFORMACTION_EVENTS) + DEFINE_ATTRIBUTE_EVENT_LISTENER(transformactionstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(transformactionupdate); + DEFINE_ATTRIBUTE_EVENT_LISTENER(transformactionend); +#endif + + virtual PassRefPtr createContextualFragment(const String&, FragmentScriptingPermission = FragmentScriptingAllowed); + + bool hasAttribute(const QualifiedName&) const; + const AtomicString& getAttribute(const QualifiedName&) const; + void setAttribute(const QualifiedName&, const AtomicString& value, ExceptionCode&); + void removeAttribute(const QualifiedName&, ExceptionCode&); + + // Typed getters and setters for language bindings. + int getIntegralAttribute(const QualifiedName& attributeName) const; + void setIntegralAttribute(const QualifiedName& attributeName, int value); + unsigned getUnsignedIntegralAttribute(const QualifiedName& attributeName) const; + void setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value); + + // Call this to get the value of an attribute that is known not to be the style + // attribute or one of the SVG animatable attributes. + bool fastHasAttribute(const QualifiedName&) const; + const AtomicString& fastGetAttribute(const QualifiedName&) const; + + bool hasAttributes() const; + + bool hasAttribute(const String& name) const; + bool hasAttributeNS(const String& namespaceURI, const String& localName) const; + + const AtomicString& getAttribute(const String& name) const; + const AtomicString& getAttributeNS(const String& namespaceURI, const String& localName) const; + + void setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode&); + void setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode&, FragmentScriptingPermission = FragmentScriptingAllowed); + + bool isIdAttributeName(const QualifiedName&) const; + const AtomicString& getIdAttribute() const; + void setIdAttribute(const AtomicString&); + + // Call this to get the value of the id attribute for style resolution purposes. + // The value will already be lowercased if the document is in compatibility mode, + // so this function is not suitable for non-style uses. + const AtomicString& idForStyleResolution() const; + + void scrollIntoView(bool alignToTop = true); + void scrollIntoViewIfNeeded(bool centerIfNeeded = true); + + void scrollByLines(int lines); + void scrollByPages(int pages); + + int offsetLeft(); + int offsetTop(); + int offsetWidth(); + int offsetHeight(); + Element* offsetParent(); + int clientLeft(); + int clientTop(); + int clientWidth(); + int clientHeight(); + virtual int scrollLeft() const; + virtual int scrollTop() const; + virtual void setScrollLeft(int); + virtual void setScrollTop(int); + virtual int scrollWidth() const; + virtual int scrollHeight() const; + + PassRefPtr getClientRects() const; + PassRefPtr getBoundingClientRect() const; + + void removeAttribute(const String& name, ExceptionCode&); + void removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode&); + + PassRefPtr getAttributeNode(const String& name); + PassRefPtr getAttributeNodeNS(const String& namespaceURI, const String& localName); + PassRefPtr setAttributeNode(Attr*, ExceptionCode&); + PassRefPtr setAttributeNodeNS(Attr*, ExceptionCode&); + PassRefPtr removeAttributeNode(Attr*, ExceptionCode&); + + virtual CSSStyleDeclaration* style(); + + const QualifiedName& tagQName() const { return m_tagName; } + String tagName() const { return nodeName(); } + bool hasTagName(const QualifiedName& tagName) const { return m_tagName.matches(tagName); } + + // A fast function for checking the local name against another atomic string. + bool hasLocalName(const AtomicString& other) const { return m_tagName.localName() == other; } + bool hasLocalName(const QualifiedName& other) const { return m_tagName.localName() == other.localName(); } + + const AtomicString& localName() const { return m_tagName.localName(); } + const AtomicString& prefix() const { return m_tagName.prefix(); } + const AtomicString& namespaceURI() const { return m_tagName.namespaceURI(); } + + virtual KURL baseURI() const; + + virtual String nodeName() const; + + PassRefPtr cloneElementWithChildren(); + PassRefPtr cloneElementWithoutChildren(); + + void normalizeAttributes(); + String nodeNamePreservingCase() const; + + // convenience methods which ignore exceptions + void setAttribute(const QualifiedName&, const AtomicString& value); + void setBooleanAttribute(const QualifiedName& name, bool); + // Please don't use setCStringAttribute in performance-sensitive code; + // use a static AtomicString value instead to avoid the conversion overhead. + void setCStringAttribute(const QualifiedName&, const char* cStringValue); + + NamedNodeMap* attributes(bool readonly = false) const; + + // This method is called whenever an attribute is added, changed or removed. + virtual void attributeChanged(Attribute*, bool preserveDecls = false); + + void setAttributeMap(PassRefPtr, FragmentScriptingPermission = FragmentScriptingAllowed); + NamedNodeMap* attributeMap() const { return m_attributeMap.get(); } + + virtual void copyNonAttributeProperties(const Element* /*source*/) { } + + virtual void attach(); + virtual void detach(); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void recalcStyle(StyleChange = NoChange); + + RenderStyle* computedStyle(PseudoId = NOPSEUDO); + + void dispatchAttrRemovalEvent(Attribute*); + void dispatchAttrAdditionEvent(Attribute*); + + virtual void accessKeyAction(bool /*sendToAnyEvent*/) { } + + virtual bool isURLAttribute(Attribute*) const; + + KURL getURLAttribute(const QualifiedName&) const; + KURL getNonEmptyURLAttribute(const QualifiedName&) const; + + virtual const QualifiedName& imageSourceAttributeName() const; + virtual String target() const { return String(); } + + virtual void focus(bool restorePreviousSelection = true); + virtual void updateFocusAppearance(bool restorePreviousSelection); + void blur(); + + String innerText() const; + String outerText() const; + + virtual String title() const; + + String openTagStartToString() const; + + void updateId(const AtomicString& oldId, const AtomicString& newId); + + IntSize minimumSizeForResizing() const; + void setMinimumSizeForResizing(const IntSize&); + + // Use Document::registerForDocumentActivationCallbacks() to subscribe to these + virtual void documentWillBecomeInactive() { } + virtual void documentDidBecomeActive() { } + + // Use Document::registerForMediaVolumeCallbacks() to subscribe to this + virtual void mediaVolumeDidChange() { } + + bool isFinishedParsingChildren() const { return isParsingChildrenFinished(); } + virtual void finishParsingChildren(); + virtual void beginParsingChildren() { clearIsParsingChildrenFinished(); } + + // ElementTraversal API + Element* firstElementChild() const; + Element* lastElementChild() const; + Element* previousElementSibling() const; + Element* nextElementSibling() const; + unsigned childElementCount() const; + + bool webkitMatchesSelector(const String& selectors, ExceptionCode&); + + DOMStringMap* dataset(); + + virtual bool isFormControlElement() const { return false; } + virtual bool isEnabledFormControl() const { return true; } + virtual bool isReadOnlyFormControl() const { return false; } + virtual bool isSpinButtonElement() const { return false; } + virtual bool isTextFormControl() const { return false; } + virtual bool isOptionalFormControl() const { return false; } + virtual bool isRequiredFormControl() const { return false; } + virtual bool isDefaultButtonForForm() const { return false; } + virtual bool willValidate() const { return false; } + virtual bool isValidFormControlElement() { return false; } + + virtual bool formControlValueMatchesRenderer() const { return false; } + virtual void setFormControlValueMatchesRenderer(bool) { } + + virtual const AtomicString& formControlName() const { return nullAtom; } + virtual const AtomicString& formControlType() const { return nullAtom; } + + virtual bool shouldSaveAndRestoreFormControlState() const { return true; } + virtual bool saveFormControlState(String&) const { return false; } + virtual void restoreFormControlState(const String&) { } + + virtual void dispatchFormControlChangeEvent() { } + +#if ENABLE(SVG) + virtual bool childShouldCreateRenderer(Node*) const; +#endif + +protected: + Element(const QualifiedName& tagName, Document* document, ConstructionType type) + : ContainerNode(document, type) + , m_tagName(tagName) + { + } + + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + + // The implementation of Element::attributeChanged() calls the following two functions. + // They are separated to allow a different flow of control in StyledElement::attributeChanged(). + void recalcStyleIfNeededAfterAttributeChanged(Attribute*); + void updateAfterAttributeChanged(Attribute*); + +private: + void scrollByUnits(int units, ScrollGranularity); + + virtual void setPrefix(const AtomicString&, ExceptionCode&); + virtual NodeType nodeType() const; + virtual bool childTypeAllowed(NodeType); + + virtual PassRefPtr createAttribute(const QualifiedName&, const AtomicString& value); + +#ifndef NDEBUG + virtual void formatForDebugger(char* buffer, unsigned length) const; +#endif + + bool pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle); + + void createAttributeMap() const; + + virtual void updateStyleAttribute() const { } + +#if ENABLE(SVG) + virtual void updateAnimatedSVGAttribute(const QualifiedName&) const { } +#endif + + void cancelFocusAppearanceUpdate(); + + virtual const AtomicString& virtualPrefix() const { return prefix(); } + virtual const AtomicString& virtualLocalName() const { return localName(); } + virtual const AtomicString& virtualNamespaceURI() const { return namespaceURI(); } + virtual RenderStyle* virtualComputedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) { return computedStyle(pseudoElementSpecifier); } + + // cloneNode is private so that non-virtual cloneElementWithChildren and cloneElementWithoutChildren + // are used instead. + virtual PassRefPtr cloneNode(bool deep); + + QualifiedName m_tagName; + virtual NodeRareData* createRareData(); + + ElementRareData* rareData() const; + ElementRareData* ensureRareData(); + +private: + mutable RefPtr m_attributeMap; +}; + +inline bool Node::hasTagName(const QualifiedName& name) const +{ + return isElementNode() && static_cast(this)->hasTagName(name); +} + +inline bool Node::hasAttributes() const +{ + return isElementNode() && static_cast(this)->hasAttributes(); +} + +inline NamedNodeMap* Node::attributes() const +{ + return isElementNode() ? static_cast(this)->attributes() : 0; +} + +inline Element* Node::parentElement() const +{ + Node* parent = parentNode(); + return parent && parent->isElementNode() ? static_cast(parent) : 0; +} + +inline NamedNodeMap* Element::attributes(bool readonly) const +{ + if (!isStyleAttributeValid()) + updateStyleAttribute(); + +#if ENABLE(SVG) + if (!areSVGAttributesValid()) + updateAnimatedSVGAttribute(anyQName()); +#endif + + if (!readonly && !m_attributeMap) + createAttributeMap(); + return m_attributeMap.get(); +} + +inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId) +{ + if (!inDocument()) + return; + + if (oldId == newId) + return; + + Document* doc = document(); + if (!oldId.isEmpty()) + doc->removeElementById(oldId, this); + if (!newId.isEmpty()) + doc->addElementById(newId, this); +} + +inline bool Element::fastHasAttribute(const QualifiedName& name) const +{ + return m_attributeMap && m_attributeMap->getAttributeItem(name); +} + +inline const AtomicString& Element::fastGetAttribute(const QualifiedName& name) const +{ + if (m_attributeMap) { + if (Attribute* attribute = m_attributeMap->getAttributeItem(name)) + return attribute->value(); + } + return nullAtom; +} + +inline const AtomicString& Element::idForStyleResolution() const +{ + ASSERT(hasID()); + return m_attributeMap->idForStyleResolution(); +} + +inline bool Element::isIdAttributeName(const QualifiedName& attributeName) const +{ + // FIXME: This check is probably not correct for the case where the document has an id attribute + // with a non-null namespace, because it will return false, a false negative, if the prefixes + // don't match but the local name and namespace both do. However, since this has been like this + // for a while and the code paths may be hot, we'll have to measure performance if we fix it. + return attributeName == document()->idAttributeName(); +} + +inline const AtomicString& Element::getIdAttribute() const +{ + return fastGetAttribute(document()->idAttributeName()); +} + +inline void Element::setIdAttribute(const AtomicString& value) +{ + setAttribute(document()->idAttributeName(), value); +} + +} // namespace + +#endif