diff options
Diffstat (limited to 'WebCore/dom')
49 files changed, 837 insertions, 384 deletions
diff --git a/WebCore/dom/CharacterData.cpp b/WebCore/dom/CharacterData.cpp index f5adb6c..9670988 100644 --- a/WebCore/dom/CharacterData.cpp +++ b/WebCore/dom/CharacterData.cpp @@ -29,13 +29,6 @@ namespace WebCore { -CharacterData::CharacterData(Document* document, const String& text, ConstructionType type) - : Node(document, type) - , m_data(text.impl() ? text.impl() : StringImpl::empty()) -{ - ASSERT(type == CreateOther || type == CreateText); -} - void CharacterData::setData(const String& data, ExceptionCode&) { StringImpl* dataImpl = data.impl() ? data.impl() : StringImpl::empty(); diff --git a/WebCore/dom/CharacterData.h b/WebCore/dom/CharacterData.h index 6c31933..5ca4b75 100644 --- a/WebCore/dom/CharacterData.h +++ b/WebCore/dom/CharacterData.h @@ -43,7 +43,12 @@ public: StringImpl* dataImpl() { return m_data.get(); } protected: - CharacterData(Document*, const String&, ConstructionType); + CharacterData(Document* document, const String& text, ConstructionType type) + : Node(document, type) + , m_data(text.impl() ? text.impl() : StringImpl::empty()) + { + ASSERT(type == CreateComment || type == CreateText); + } virtual bool rendererIsNeeded(RenderStyle*); diff --git a/WebCore/dom/ClassNodeList.cpp b/WebCore/dom/ClassNodeList.cpp index a7aefba..d482359 100644 --- a/WebCore/dom/ClassNodeList.cpp +++ b/WebCore/dom/ClassNodeList.cpp @@ -35,12 +35,18 @@ namespace WebCore { -ClassNodeList::ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames, DynamicNodeList::Caches* caches) - : DynamicNodeList(rootNode, caches) +ClassNodeList::ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames) + : DynamicNodeList(rootNode) , m_classNames(classNames, m_rootNode->document()->inCompatMode()) + , m_originalClassNames(classNames) { } +ClassNodeList::~ClassNodeList() +{ + m_rootNode->removeCachedClassNodeList(this, m_originalClassNames); +} + bool ClassNodeList::nodeMatches(Element* testNode) const { if (!testNode->hasClass()) diff --git a/WebCore/dom/ClassNodeList.h b/WebCore/dom/ClassNodeList.h index c519b3e..ea048a2 100644 --- a/WebCore/dom/ClassNodeList.h +++ b/WebCore/dom/ClassNodeList.h @@ -37,17 +37,20 @@ namespace WebCore { class ClassNodeList : public DynamicNodeList { public: - static PassRefPtr<ClassNodeList> create(PassRefPtr<Node> rootNode, const String& classNames, Caches* caches) + static PassRefPtr<ClassNodeList> create(PassRefPtr<Node> rootNode, const String& classNames) { - return adoptRef(new ClassNodeList(rootNode, classNames, caches)); + return adoptRef(new ClassNodeList(rootNode, classNames)); } + virtual ~ClassNodeList(); + private: - ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames, Caches*); + ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames); virtual bool nodeMatches(Element*) const; SpaceSplitString m_classNames; + String m_originalClassNames; }; } // namespace WebCore diff --git a/WebCore/dom/Comment.cpp b/WebCore/dom/Comment.cpp index 3dcde38..00f1724 100644 --- a/WebCore/dom/Comment.cpp +++ b/WebCore/dom/Comment.cpp @@ -22,10 +22,12 @@ #include "config.h" #include "Comment.h" +#include "Document.h" + namespace WebCore { inline Comment::Comment(Document* document, const String& text) - : CharacterData(document, text, CreateOther) + : CharacterData(document, text, CreateComment) { } diff --git a/WebCore/dom/Comment.h b/WebCore/dom/Comment.h index 680ffae..a0210c4 100644 --- a/WebCore/dom/Comment.h +++ b/WebCore/dom/Comment.h @@ -37,7 +37,6 @@ private: virtual String nodeName() const; virtual NodeType nodeType() const; virtual PassRefPtr<Node> cloneNode(bool deep); - virtual bool isCommentNode() const { return true; } virtual bool childTypeAllowed(NodeType); }; diff --git a/WebCore/dom/ContainerNode.cpp b/WebCore/dom/ContainerNode.cpp index f42b9cf..b063998 100644 --- a/WebCore/dom/ContainerNode.cpp +++ b/WebCore/dom/ContainerNode.cpp @@ -616,7 +616,7 @@ void ContainerNode::detach() { for (Node* child = m_firstChild; child; child = child->nextSibling()) child->detach(); - setChildNeedsStyleRecalc(false); + clearChildNeedsStyleRecalc(); Node::detach(); } @@ -633,7 +633,7 @@ void ContainerNode::removedFromDocument() Node::removedFromDocument(); if (document()->cssTarget() == this) document()->setCSSTarget(0); - setInDocument(false); + clearInDocument(); removedFromTree(false); for (Node* child = m_firstChild; child; child = child->nextSibling()) child->removedFromDocument(); diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp index ffbfd24..c6920bf 100644 --- a/WebCore/dom/Document.cpp +++ b/WebCore/dom/Document.cpp @@ -78,6 +78,7 @@ #include "HTMLParser.h" #include "HTMLStyleElement.h" #include "HTMLTitleElement.h" +#include "HTMLTokenizer.h" #include "HTTPParsers.h" #include "HistoryItem.h" #include "HitTestRequest.h" @@ -191,6 +192,9 @@ #endif #if ENABLE(TOUCH_EVENTS) +#if USE(V8) +#include "RuntimeEnabledFeatures.h" +#endif #include "TouchEvent.h" #endif @@ -219,6 +223,29 @@ namespace WebCore { using namespace HTMLNames; +class SynchronousHTMLTokenizerGuard { +public: + SynchronousHTMLTokenizerGuard(Tokenizer* tokenizer) + : m_htmlTokenizer(tokenizer->asHTMLTokenizer()) + , m_savedForceSynchronous(false) + { + if (m_htmlTokenizer) { + m_savedForceSynchronous = m_htmlTokenizer->forceSynchronous(); + m_htmlTokenizer->setForceSynchronous(true); + } + } + + ~SynchronousHTMLTokenizerGuard() + { + if (m_htmlTokenizer) + m_htmlTokenizer->setForceSynchronous(m_savedForceSynchronous); + } + +private: + HTMLTokenizer* m_htmlTokenizer; + bool m_savedForceSynchronous; +}; + // #define INSTRUMENT_LAYOUT_SCHEDULING 1 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay. @@ -439,7 +466,7 @@ Document::Document(Frame* frame, bool isXHTML, bool isHTML) m_textColor = Color::black; m_listenerTypes = 0; - m_inDocument = true; + setInDocument(); m_inStyleRecalc = false; m_closeAfterStyleRecalc = false; @@ -1421,7 +1448,7 @@ void Document::recalcStyle(StyleChange change) bail_out: setNeedsStyleRecalc(NoStyleChange); - setChildNeedsStyleRecalc(false); + clearChildNeedsStyleRecalc(); unscheduleStyleRecalc(); if (view()) @@ -1997,8 +2024,11 @@ void Document::write(const SegmentedString& text, Document* ownerDocument) if (!m_tokenizer) open(ownerDocument); - ASSERT(m_tokenizer); - m_tokenizer->write(text, false); + { + ASSERT(m_tokenizer); + SynchronousHTMLTokenizerGuard tokenizerGuard(m_tokenizer.get()); + m_tokenizer->write(text, false); + } #ifdef INSTRUMENT_LAYOUT_SCHEDULING if (!ownerElement()) @@ -2891,7 +2921,7 @@ bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode) m_focusedNode = 0; // Remove focus from the existing focus node (if any) - if (oldFocusedNode && !oldFocusedNode->m_inDetach) { + if (oldFocusedNode && !oldFocusedNode->inDetach()) { if (oldFocusedNode->active()) oldFocusedNode->setActive(false); @@ -2927,6 +2957,14 @@ bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode) if (oldFocusedNode == oldFocusedNode->rootEditableElement()) frame()->editor()->didEndEditing(); + + if (view()) { + Widget* oldWidget = widgetForNode(oldFocusedNode.get()); + if (oldWidget) + oldWidget->setFocus(false); + else + view()->setFocus(false); + } } if (newFocusedNode) { @@ -2954,7 +2992,7 @@ bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode) focusChangeBlocked = true; goto SetFocusedNodeDone; } - m_focusedNode->setFocus(); + m_focusedNode->setFocus(true); if (m_focusedNode == m_focusedNode->rootEditableElement()) frame()->editor()->didBeginEditing(); @@ -2972,9 +3010,9 @@ bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode) focusWidget = widgetForNode(m_focusedNode.get()); } if (focusWidget) - focusWidget->setFocus(); + focusWidget->setFocus(true); else - view()->setFocus(); + view()->setFocus(true); } } @@ -3212,7 +3250,11 @@ PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& event = SVGZoomEvent::create(); #endif #if ENABLE(TOUCH_EVENTS) +#if USE(V8) + else if (eventType == "TouchEvent" && RuntimeEnabledFeatures::touchEnabled()) +#else else if (eventType == "TouchEvent") +#endif event = TouchEvent::create(); #endif if (event) @@ -4543,6 +4585,8 @@ void Document::setIconURL(const String& iconURL, const String& type) m_iconURL = iconURL; else if (!type.isEmpty()) m_iconURL = iconURL; + if (Frame* f = frame()) + f->loader()->setIconURL(m_iconURL); } void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard) @@ -4900,10 +4944,9 @@ void Document::enqueuePageshowEvent(PageshowEventPersistence persisted) void Document::enqueueHashchangeEvent(const String& /*oldURL*/, const String& /*newURL*/) { - // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36201 Hashchange event needs to fire asynchronously. // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36335 Hashchange event is now its own interface and takes two // URL arguments which we need to pass in here. - dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false)); + enqueueEvent(Event::create(eventNames().hashchangeEvent, false, false)); } void Document::enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject) @@ -4921,7 +4964,7 @@ bool Document::isXHTMLMPDocument() const // MUST accept XHTMLMP document identified as "application/vnd.wap.xhtml+xml" // and SHOULD accept it identified as "application/xhtml+xml" , "application/xhtml+xml" is a // general MIME type for all XHTML documents, not only for XHTMLMP - return frame()->loader()->responseMIMEType() == "application/vnd.wap.xhtml+xml"; + return frame()->loader()->writer()->mimeType() == "application/vnd.wap.xhtml+xml"; } #endif diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h index 6ac1f01..45031c3 100644 --- a/WebCore/dom/Document.h +++ b/WebCore/dom/Document.h @@ -958,6 +958,7 @@ public: #endif virtual bool isContextThread() const; + virtual bool isJSExecutionTerminated() const { return false; } void setUsingGeolocation(bool f) { m_usingGeolocation = f; } bool usingGeolocation() const { return m_usingGeolocation; }; @@ -1264,6 +1265,22 @@ inline bool Node::isDocumentNode() const return this == m_document; } +// here because it uses a Document method but we really want to inline it +inline Node::Node(Document* document, ConstructionType type) + : TreeShared<Node>(initialRefCount(type)) + , m_document(document) + , m_previous(0) + , m_next(0) + , m_renderer(0) + , m_nodeFlags(type) +{ + if (m_document) + m_document->selfOnlyRef(); +#if !defined(NDEBUG) || (defined(DUMP_NODE_STATISTICS) && DUMP_NODE_STATISTICS) + trackForDebugging(); +#endif +} + } // namespace WebCore #endif // Document_h diff --git a/WebCore/dom/Document.idl b/WebCore/dom/Document.idl index 88bd639..cd877b3 100644 --- a/WebCore/dom/Document.idl +++ b/WebCore/dom/Document.idl @@ -306,10 +306,10 @@ module core { attribute [DontEnum] EventListener onreset; attribute [DontEnum] EventListener onsearch; attribute [DontEnum] EventListener onselectstart; - attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchstart; - attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchmove; - attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchend; - attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchcancel; + attribute [DontEnum,Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchstart; + attribute [DontEnum,Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchmove; + attribute [DontEnum,Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchend; + attribute [DontEnum,Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchcancel; #endif }; diff --git a/WebCore/dom/DocumentFragment.cpp b/WebCore/dom/DocumentFragment.cpp index 3663e99..f7df8f6 100644 --- a/WebCore/dom/DocumentFragment.cpp +++ b/WebCore/dom/DocumentFragment.cpp @@ -23,6 +23,8 @@ #include "config.h" #include "DocumentFragment.h" +#include "Document.h" + namespace WebCore { inline DocumentFragment::DocumentFragment(Document* document) diff --git a/WebCore/dom/EditingText.cpp b/WebCore/dom/EditingText.cpp index b36931a..e412ad6 100644 --- a/WebCore/dom/EditingText.cpp +++ b/WebCore/dom/EditingText.cpp @@ -20,6 +20,8 @@ #include "config.h" #include "EditingText.h" +#include "Document.h" + // FIXME: Does this really require a class? Perhaps instead any text node // inside an editable element could have the "always create a renderer" behavior. diff --git a/WebCore/dom/Element.cpp b/WebCore/dom/Element.cpp index 3363e95..171a869 100644 --- a/WebCore/dom/Element.cpp +++ b/WebCore/dom/Element.cpp @@ -64,12 +64,6 @@ namespace WebCore { using namespace HTMLNames; using namespace XMLNames; -Element::Element(const QualifiedName& tagName, Document* document, ConstructionType type) - : ContainerNode(document, type) - , m_tagName(tagName) -{ -} - PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document) { return adoptRef(new Element(tagName, document, CreateElement)); @@ -161,12 +155,12 @@ PassRefPtr<Element> Element::cloneElementWithoutChildren() // This is a sanity check as HTML overloads some of the DOM methods. ASSERT(isHTMLElement() == clone->isHTMLElement()); - clone->copyNonAttributeProperties(this); - // Clone attributes. if (namedAttrMap) clone->attributes()->setAttributes(*attributes(true)); // Call attributes(true) to force attribute synchronization to occur (for svg and style) before cloning happens. + clone->copyNonAttributeProperties(this); + return clone.release(); } @@ -225,11 +219,11 @@ bool Element::hasAttribute(const QualifiedName& name) const const AtomicString& Element::getAttribute(const QualifiedName& name) const { - if (name == styleAttr && !m_isStyleAttributeValid) + if (name == styleAttr && !isStyleAttributeValid()) updateStyleAttribute(); #if ENABLE(SVG) - if (!m_areSVGAttributesValid) + if (!areSVGAttributesValid()) updateAnimatedSVGAttribute(name); #endif @@ -532,11 +526,11 @@ const AtomicString& Element::getAttribute(const String& name) const bool ignoreCase = shouldIgnoreAttributeCase(this); // Update the 'style' attribute if it's invalid and being requested: - if (!m_isStyleAttributeValid && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase)) + if (!isStyleAttributeValid() && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase)) updateStyleAttribute(); #if ENABLE(SVG) - if (!m_areSVGAttributesValid) { + if (!areSVGAttributesValid()) { // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well. updateAnimatedSVGAttribute(QualifiedName(nullAtom, name, nullAtom)); } @@ -583,7 +577,7 @@ void Element::setAttribute(const AtomicString& name, const AtomicString& value, #if ENABLE(INSPECTOR) if (Page* page = document()->page()) { if (InspectorController* inspectorController = page->inspectorController()) { - if (!m_synchronizingStyleAttribute) + if (!isSynchronizingStyleAttribute()) inspectorController->didModifyDOMAttr(this); } } @@ -612,7 +606,7 @@ void Element::setAttribute(const QualifiedName& name, const AtomicString& value, #if ENABLE(INSPECTOR) if (Page* page = document()->page()) { if (InspectorController* inspectorController = page->inspectorController()) { - if (!m_synchronizingStyleAttribute) + if (!isSynchronizingStyleAttribute()) inspectorController->didModifyDOMAttr(this); } } @@ -718,11 +712,11 @@ void Element::setAttributeMap(PassRefPtr<NamedNodeMap> list, FragmentScriptingPe bool Element::hasAttributes() const { - if (!m_isStyleAttributeValid) + if (!isStyleAttributeValid()) updateStyleAttribute(); #if ENABLE(SVG) - if (!m_areSVGAttributesValid) + if (!areSVGAttributesValid()) updateAnimatedSVGAttribute(anyQName()); #endif @@ -916,7 +910,7 @@ void Element::recalcStyle(StyleChange change) attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along. // attach recalulates the style for all children. No need to do it twice. setNeedsStyleRecalc(NoStyleChange); - setChildNeedsStyleRecalc(false); + clearChildNeedsStyleRecalc(); return; } @@ -982,7 +976,7 @@ void Element::recalcStyle(StyleChange change) } setNeedsStyleRecalc(NoStyleChange); - setChildNeedsStyleRecalc(false); + clearChildNeedsStyleRecalc(); } bool Element::childTypeAllowed(NodeType type) @@ -1091,7 +1085,7 @@ void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* af void Element::finishParsingChildren() { ContainerNode::finishParsingChildren(); - m_parsingChildrenFinished = true; + setIsParsingChildrenFinished(); checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0); } diff --git a/WebCore/dom/Element.h b/WebCore/dom/Element.h index eefaeb1..3d02f1b 100644 --- a/WebCore/dom/Element.h +++ b/WebCore/dom/Element.h @@ -29,6 +29,7 @@ #include "Document.h" #include "HTMLNames.h" #include "MappedAttributeEntry.h" +#include "NamedNodeMap.h" #include "QualifiedName.h" #include "ScrollTypes.h" @@ -236,9 +237,9 @@ public: // Use Document::registerForMediaVolumeCallbacks() to subscribe to this virtual void mediaVolumeDidChange() { } - bool isFinishedParsingChildren() const { return m_parsingChildrenFinished; } + bool isFinishedParsingChildren() const { return isParsingChildrenFinished(); } virtual void finishParsingChildren(); - virtual void beginParsingChildren() { m_parsingChildrenFinished = false; } + virtual void beginParsingChildren() { clearIsParsingChildrenFinished(); } // ElementTraversal API Element* firstElementChild() const; @@ -252,6 +253,7 @@ public: 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; } @@ -272,7 +274,11 @@ public: virtual void dispatchFormControlChangeEvent() { } protected: - Element(const QualifiedName&, Document*, ConstructionType); + Element(const QualifiedName& tagName, Document* document, ConstructionType type) + : ContainerNode(document, type) + , m_tagName(tagName) + { + } virtual void insertedIntoDocument(); virtual void removedFromDocument(); @@ -356,11 +362,11 @@ inline const QualifiedName& Element::idAttributeName() const inline NamedNodeMap* Element::attributes(bool readonly) const { - if (!m_isStyleAttributeValid) + if (!isStyleAttributeValid()) updateStyleAttribute(); #if ENABLE(SVG) - if (!m_areSVGAttributesValid) + if (!areSVGAttributesValid()) updateAnimatedSVGAttribute(anyQName()); #endif diff --git a/WebCore/dom/Element.idl b/WebCore/dom/Element.idl index 1368503..977d15a 100644 --- a/WebCore/dom/Element.idl +++ b/WebCore/dom/Element.idl @@ -195,10 +195,10 @@ module core { attribute [DontEnum] EventListener onreset; attribute [DontEnum] EventListener onsearch; attribute [DontEnum] EventListener onselectstart; - attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchstart; - attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchmove; - attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchend; - attribute [DontEnum,Conditional=TOUCH_EVENTS] EventListener ontouchcancel; + attribute [DontEnum,Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchstart; + attribute [DontEnum,Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchmove; + attribute [DontEnum,Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchend; + attribute [DontEnum,Conditional=TOUCH_EVENTS,EnabledAtRuntime] EventListener ontouchcancel; #endif }; diff --git a/WebCore/dom/EntityReference.cpp b/WebCore/dom/EntityReference.cpp index c4c292a..72944ec 100644 --- a/WebCore/dom/EntityReference.cpp +++ b/WebCore/dom/EntityReference.cpp @@ -21,6 +21,8 @@ #include "config.h" #include "EntityReference.h" +#include "Document.h" + namespace WebCore { inline EntityReference::EntityReference(Document* document, const String& entityName) diff --git a/WebCore/dom/EventNames.h b/WebCore/dom/EventNames.h index c50cfb2..ca2ae96 100644 --- a/WebCore/dom/EventNames.h +++ b/WebCore/dom/EventNames.h @@ -159,6 +159,8 @@ namespace WebCore { \ macro(success) \ \ + macro(loadend) \ + \ // end of DOM_EVENT_NAMES_FOR_EACH class EventNames : public Noncopyable { diff --git a/WebCore/dom/EventTarget.cpp b/WebCore/dom/EventTarget.cpp index 1598790..91a5d0c 100644 --- a/WebCore/dom/EventTarget.cpp +++ b/WebCore/dom/EventTarget.cpp @@ -156,6 +156,13 @@ Notification* EventTarget::toNotification() } #endif +#if ENABLE(FILE_READER) +FileReader* EventTarget::toFileReader() +{ + return 0; +} +#endif + bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) { EventTargetData* d = ensureEventTargetData(); diff --git a/WebCore/dom/EventTarget.h b/WebCore/dom/EventTarget.h index da98d98..96d2d29 100644 --- a/WebCore/dom/EventTarget.h +++ b/WebCore/dom/EventTarget.h @@ -48,6 +48,7 @@ namespace WebCore { class Event; class EventListener; class EventSource; + class FileReader; class MessagePort; class Node; class Notification; @@ -118,6 +119,9 @@ namespace WebCore { #if ENABLE(NOTIFICATIONS) virtual Notification* toNotification(); #endif +#if ENABLE(FILE_READER) + virtual FileReader* toFileReader(); +#endif virtual ScriptExecutionContext* scriptExecutionContext() const = 0; diff --git a/WebCore/dom/ExceptionCode.h b/WebCore/dom/ExceptionCode.h index 573fb36..a5618f8 100644 --- a/WebCore/dom/ExceptionCode.h +++ b/WebCore/dom/ExceptionCode.h @@ -58,6 +58,13 @@ namespace WebCore { ABORT_ERR = 20, URL_MISMATCH_ERR = 21, QUOTA_EXCEEDED_ERR = 22, + + // Introduced in File API: + // http://www.w3.org/TR/file-upload/#dfn-fileerror +#if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + NOT_READABLE_ERR = 24, + ENCODING_ERR = 26, +#endif }; enum ExceptionType { diff --git a/WebCore/dom/InputElement.cpp b/WebCore/dom/InputElement.cpp index 52812f9..3459906 100644 --- a/WebCore/dom/InputElement.cpp +++ b/WebCore/dom/InputElement.cpp @@ -22,6 +22,15 @@ #include "InputElement.h" #include "BeforeTextInsertedEvent.h" + +#if ENABLE(WCSS) +#include "CSSPropertyNames.h" +#include "CSSRule.h" +#include "CSSRuleList.h" +#include "CSSStyleRule.h" +#include "CSSStyleSelector.h" +#endif + #include "Chrome.h" #include "ChromeClient.h" #include "Document.h" @@ -138,6 +147,14 @@ void InputElement::setValueFromRenderer(InputElementData& data, InputElement* in String InputElement::sanitizeValue(const InputElement* inputElement, const String& proposedValue) { +#if ENABLE(WCSS) + InputElementData data = const_cast<InputElement*>(inputElement)->data(); + if (!isConformToInputMask(data, proposedValue)) { + if (isConformToInputMask(data, data.value())) + return data.value(); + return String(); + } +#endif return InputElement::sanitizeUserInputValue(inputElement, proposedValue, s_maximumLength); } @@ -172,8 +189,12 @@ void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, InputEl // RenderTextControlSingleLine::subtreeHasChanged() in some cases. unsigned oldLength = numGraphemeClusters(toRenderTextControlSingleLine(element->renderer())->text()); - // selection() may be a pre-edit text. - unsigned selectionLength = numGraphemeClusters(plainText(element->document()->frame()->selection()->selection().toNormalizedRange().get())); + // selectionLength represents the selection length of this text field to be + // removed by this insertion. + // If the text field has no focus, we don't need to take account of the + // selection length. The selection is the source of text drag-and-drop in + // that case, and nothing in the text field will be removed. + unsigned selectionLength = element->focused() ? numGraphemeClusters(plainText(element->document()->frame()->selection()->selection().toNormalizedRange().get())) : 0; ASSERT(oldLength >= selectionLength); // Selected characters will be removed by the next text event. @@ -183,6 +204,18 @@ void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, InputEl // Truncate the inserted text to avoid violating the maxLength and other constraints. BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(event); +#if ENABLE(WCSS) + RefPtr<Range> range = element->document()->frame()->selection()->selection().toNormalizedRange(); + String candidateString = toRenderTextControlSingleLine(element->renderer())->text(); + if (selectionLength) + candidateString.replace(range->startOffset(), range->endOffset(), textEvent->text()); + else + candidateString.insert(textEvent->text(), range->startOffset()); + if (!isConformToInputMask(inputElement->data(), candidateString)) { + textEvent->setText(""); + return; + } +#endif textEvent->setText(sanitizeUserInputValue(inputElement, textEvent->text(), appendableLength)); } @@ -234,6 +267,10 @@ InputElementData::InputElementData() , m_maxLength(InputElement::s_maximumLength) , m_cachedSelectionStart(-1) , m_cachedSelectionEnd(-1) +#if ENABLE(WCSS) + , m_inputFormatMask("*m") + , m_maxInputCharsAllowed(InputElement::s_maximumLength) +#endif { } @@ -255,4 +292,137 @@ InputElement* toInputElement(Element* element) return 0; } +#if ENABLE(WCSS) +static inline const AtomicString& formatCodes() +{ + DEFINE_STATIC_LOCAL(AtomicString, codes, ("AaNnXxMm")); + return codes; +} + +static unsigned cursorPositionToMaskIndex(const String& inputFormatMask, unsigned cursorPosition) +{ + UChar mask; + int index = -1; + do { + mask = inputFormatMask[++index]; + if (mask == '\\') + ++index; + else if (mask == '*' || (isASCIIDigit(mask) && mask != '0')) { + index = inputFormatMask.length() - 1; + break; + } + } while (cursorPosition--); + + return index; +} + +bool InputElement::isConformToInputMask(const InputElementData& data, const String& inputChars) +{ + for (unsigned i = 0; i < inputChars.length(); ++i) + if (!isConformToInputMask(data, inputChars[i], i)) + return false; + return true; +} + +bool InputElement::isConformToInputMask(const InputElementData& data, UChar inChar, unsigned cursorPosition) +{ + String inputFormatMask = data.inputFormatMask(); + + if (inputFormatMask.isEmpty() || inputFormatMask == "*M" || inputFormatMask == "*m") + return true; + + if (cursorPosition >= data.maxInputCharsAllowed()) + return false; + + unsigned maskIndex = cursorPositionToMaskIndex(inputFormatMask, cursorPosition); + bool ok = true; + UChar mask = inputFormatMask[maskIndex]; + // Match the inputed character with input mask + switch (mask) { + case 'A': + ok = !isASCIIDigit(inChar) && !isASCIILower(inChar) && isASCIIPrintable(inChar); + break; + case 'a': + ok = !isASCIIDigit(inChar) && !isASCIIUpper(inChar) && isASCIIPrintable(inChar); + break; + case 'N': + ok = isASCIIDigit(inChar); + break; + case 'n': + ok = !isASCIIAlpha(inChar) && isASCIIPrintable(inChar); + break; + case 'X': + ok = !isASCIILower(inChar) && isASCIIPrintable(inChar); + break; + case 'x': + ok = !isASCIIUpper(inChar) && isASCIIPrintable(inChar); + break; + case 'M': + case 'm': + ok = isASCIIPrintable(inChar); + break; + default: + ok = (mask == inChar); + break; + } + + return ok; +} + +String InputElement::validateInputMask(InputElementData& data, String& inputMask) +{ + inputMask.replace("\\\\", "\\"); + + bool isValid = true; + bool hasWildcard = false; + unsigned escapeCharCount = 0; + unsigned maskLength = inputMask.length(); + UChar formatCode; + for (unsigned i = 0; i < maskLength; ++i) { + formatCode = inputMask[i]; + if (formatCodes().find(formatCode) == -1) { + if (formatCode == '*' || (isASCIIDigit(formatCode) && formatCode != '0')) { + // Validate codes which ends with '*f' or 'nf' + formatCode = inputMask[++i]; + if ((i + 1 != maskLength) || formatCodes().find(formatCode) == -1) { + isValid = false; + break; + } + hasWildcard = true; + } else if (formatCode == '\\') { + // skip over the next mask character + ++i; + ++escapeCharCount; + } else { + isValid = false; + break; + } + } + } + + if (!isValid) + return String(); + // calculate the number of characters allowed to be entered by input mask + unsigned allowedLength = maskLength; + if (escapeCharCount) + allowedLength -= escapeCharCount; + + if (hasWildcard) { + formatCode = inputMask[maskLength - 2]; + if (formatCode == '*') + allowedLength = data.maxInputCharsAllowed(); + else { + unsigned leftLen = String(&formatCode).toInt(); + allowedLength = leftLen + allowedLength - 2; + } + } + + if (allowedLength < data.maxInputCharsAllowed()) + data.setMaxInputCharsAllowed(allowedLength); + + return inputMask; +} + +#endif + } diff --git a/WebCore/dom/InputElement.h b/WebCore/dom/InputElement.h index a24b438..bdd5645 100644 --- a/WebCore/dom/InputElement.h +++ b/WebCore/dom/InputElement.h @@ -43,6 +43,7 @@ public: virtual bool isPasswordField() const = 0; virtual bool isSearchField() const = 0; virtual bool isTextField() const = 0; + virtual bool hasSpinButton() const { return false; } virtual bool searchEventsShouldBeDispatched() const = 0; @@ -57,6 +58,10 @@ public: virtual void cacheSelection(int start, int end) = 0; virtual void select() = 0; + +#if ENABLE(WCSS) + virtual InputElementData data() const = 0; +#endif static const int s_maximumLength; static const int s_defaultSize; @@ -79,6 +84,11 @@ protected: static void parseMaxLengthAttribute(InputElementData&, InputElement*, Element*, MappedAttribute*); static void updateValueIfNeeded(InputElementData&, InputElement*); static void notifyFormStateChanged(Element*); +#if ENABLE(WCSS) + static bool isConformToInputMask(const InputElementData&, const String&); + static bool isConformToInputMask(const InputElementData&, UChar, unsigned); + static String validateInputMask(InputElementData&, String&); +#endif }; // HTML/WMLInputElement hold this struct as member variable @@ -108,6 +118,15 @@ public: int cachedSelectionEnd() const { return m_cachedSelectionEnd; } void setCachedSelectionEnd(int value) { m_cachedSelectionEnd = value; } +#if ENABLE(WCSS) + String inputFormatMask() const { return m_inputFormatMask; } + void setInputFormatMask(const String& mask) { m_inputFormatMask = mask; } + + unsigned maxInputCharsAllowed() const { return m_maxInputCharsAllowed; } + void setMaxInputCharsAllowed(unsigned maxLength) { m_maxInputCharsAllowed = maxLength; } + +#endif + private: AtomicString m_name; String m_value; @@ -116,6 +135,10 @@ private: int m_maxLength; int m_cachedSelectionStart; int m_cachedSelectionEnd; +#if ENABLE(WCSS) + String m_inputFormatMask; + unsigned m_maxInputCharsAllowed; +#endif }; InputElement* toInputElement(Element*); diff --git a/WebCore/dom/MessagePort.idl b/WebCore/dom/MessagePort.idl index 9312430..7bde45e 100644 --- a/WebCore/dom/MessagePort.idl +++ b/WebCore/dom/MessagePort.idl @@ -43,12 +43,12 @@ module events { attribute EventListener onmessage; // EventTarget interface - [JSCCustom] void addEventListener(in DOMString type, - in EventListener listener, - in boolean useCapture); - [JSCCustom] void removeEventListener(in DOMString type, - in EventListener listener, - in boolean useCapture); + void addEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + void removeEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); boolean dispatchEvent(in Event evt) raises(EventException); #endif diff --git a/WebCore/dom/NameNodeList.cpp b/WebCore/dom/NameNodeList.cpp index 4d96de0..2ffa577 100644 --- a/WebCore/dom/NameNodeList.cpp +++ b/WebCore/dom/NameNodeList.cpp @@ -31,12 +31,17 @@ namespace WebCore { using namespace HTMLNames; -NameNodeList::NameNodeList(PassRefPtr<Node> rootNode, const String& name, DynamicNodeList::Caches* caches) - : DynamicNodeList(rootNode, caches) +NameNodeList::NameNodeList(PassRefPtr<Node> rootNode, const String& name) + : DynamicNodeList(rootNode) , m_nodeName(name) { } +NameNodeList::~NameNodeList() +{ + m_rootNode->removeCachedNameNodeList(this, m_nodeName); +} + bool NameNodeList::nodeMatches(Element* testNode) const { return testNode->getAttribute(nameAttr) == m_nodeName; diff --git a/WebCore/dom/NameNodeList.h b/WebCore/dom/NameNodeList.h index 2fdb43d..4f109b4 100644 --- a/WebCore/dom/NameNodeList.h +++ b/WebCore/dom/NameNodeList.h @@ -34,13 +34,15 @@ namespace WebCore { // NodeList which lists all Nodes in a Element with a given "name" attribute class NameNodeList : public DynamicNodeList { public: - static PassRefPtr<NameNodeList> create(PassRefPtr<Node> rootNode, const String& name, Caches* caches) + static PassRefPtr<NameNodeList> create(PassRefPtr<Node> rootNode, const String& name) { - return adoptRef(new NameNodeList(rootNode, name, caches)); + return adoptRef(new NameNodeList(rootNode, name)); } + virtual ~NameNodeList(); + private: - NameNodeList(PassRefPtr<Node> rootNode, const String& name, Caches*); + NameNodeList(PassRefPtr<Node> rootNode, const String& name); virtual bool nodeMatches(Element*) const; diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp index a8ffc37..83aef21 100644 --- a/WebCore/dom/Node.cpp +++ b/WebCore/dom/Node.cpp @@ -103,8 +103,13 @@ #include "HTMLNoScriptElement.h" #endif +<<<<<<< HEAD:WebCore/dom/Node.cpp #if ENABLE(TOUCH_EVENTS) #include "ChromeClient.h" +======= +#if USE(JSC) +#include <runtime/JSGlobalData.h> +>>>>>>> webkit.org at r58956:WebCore/dom/Node.cpp #endif #define DUMP_NODE_STATISTICS 0 @@ -339,99 +344,8 @@ Node::StyleChange Node::diff(const RenderStyle* s1, const RenderStyle* s2) return ch; } -inline bool Node::initialRefCount(ConstructionType type) -{ - switch (type) { - case CreateContainer: - case CreateElement: - case CreateOther: - case CreateText: - return 1; - case CreateElementZeroRefCount: - return 0; - } - ASSERT_NOT_REACHED(); - return 1; -} - -inline bool Node::isContainer(ConstructionType type) +void Node::trackForDebugging() { - switch (type) { - case CreateContainer: - case CreateElement: - case CreateElementZeroRefCount: - return true; - case CreateOther: - case CreateText: - return false; - } - ASSERT_NOT_REACHED(); - return false; -} - -inline bool Node::isElement(ConstructionType type) -{ - switch (type) { - case CreateContainer: - case CreateOther: - case CreateText: - return false; - case CreateElement: - case CreateElementZeroRefCount: - return true; - } - ASSERT_NOT_REACHED(); - return false; -} - -inline bool Node::isText(ConstructionType type) -{ - switch (type) { - case CreateContainer: - case CreateElement: - case CreateElementZeroRefCount: - case CreateOther: - return false; - case CreateText: - return true; - } - ASSERT_NOT_REACHED(); - return false; -} - -Node::Node(Document* document, ConstructionType type) - : TreeShared<Node>(initialRefCount(type)) - , m_document(document) - , m_previous(0) - , m_next(0) - , m_renderer(0) - , m_styleChange(NoStyleChange) - , m_hasId(false) - , m_hasClass(false) - , m_attached(false) - , m_childNeedsStyleRecalc(false) - , m_inDocument(false) - , m_isLink(false) - , m_active(false) - , m_hovered(false) - , m_inActiveChain(false) - , m_inDetach(false) - , m_hasRareData(false) - , m_isElement(isElement(type)) - , m_isContainer(isContainer(type)) - , m_isText(isText(type)) - , m_parsingChildrenFinished(true) - , m_isStyleAttributeValid(true) - , m_synchronizingStyleAttribute(false) -#if ENABLE(SVG) - , m_areSVGAttributesValid(true) - , m_synchronizingSVGAttributes(false) - , m_hasRareSVGData(false) -#endif -{ - if (m_document) - m_document->selfOnlyRef(); - #ifndef NDEBUG if (shouldIgnoreLeaks) ignoreSet.add(this); @@ -555,7 +469,7 @@ NodeRareData* Node::ensureRareData() ASSERT(!NodeRareData::rareDataMap().contains(this)); NodeRareData* data = createRareData(); NodeRareData::rareDataMap().set(this, data); - m_hasRareData = true; + setFlag(HasRareDataFlag); return data; } @@ -771,17 +685,43 @@ IntRect Node::getRect() const return IntRect(); } +bool Node::hasNonEmptyBoundingBox() const +{ + // Before calling absoluteRects, check for the common case where the renderer + // is non-empty, since this is a faster check and almost always returns true. + RenderBoxModelObject* box = renderBoxModelObject(); + if (!box) + return false; + if (!box->borderBoundingBox().isEmpty()) + return true; + + Vector<IntRect> rects; + FloatPoint absPos = renderer()->localToAbsolute(); + renderer()->absoluteRects(rects, absPos.x(), absPos.y()); + size_t n = rects.size(); + for (size_t i = 0; i < n; ++i) + if (!rects[i].isEmpty()) + return true; + + return false; +} + +inline void Node::setStyleChange(StyleChangeType changeType) +{ + m_nodeFlags = (m_nodeFlags & ~StyleChangeMask) | changeType; +} + void Node::setNeedsStyleRecalc(StyleChangeType changeType) { if ((changeType != NoStyleChange) && !attached()) // changed compared to what? return; - if (!(changeType == InlineStyleChange && (m_styleChange == FullStyleChange || m_styleChange == SyntheticStyleChange))) - m_styleChange = changeType; + if (!(changeType == InlineStyleChange && (styleChangeType() == FullStyleChange || styleChangeType() == SyntheticStyleChange))) + setStyleChange(changeType); - if (m_styleChange != NoStyleChange) { + if (styleChangeType() != NoStyleChange) { for (Node* p = parentNode(); p && !p->childNeedsStyleRecalc(); p = p->parentNode()) - p->setChildNeedsStyleRecalc(true); + p->setChildNeedsStyleRecalc(); if (document()->childNeedsStyleRecalc()) document()->scheduleStyleRecalc(); } @@ -805,9 +745,9 @@ void Node::lazyAttach() } if (n->firstChild()) - n->setChildNeedsStyleRecalc(true); - n->m_styleChange = FullStyleChange; - n->m_attached = true; + n->setChildNeedsStyleRecalc(); + n->setStyleChange(FullStyleChange); + n->setAttached(); } if (mustDoFullAttach) { @@ -817,7 +757,7 @@ void Node::lazyAttach() lazyAttachedAncestor->attach(); } else { for (Node* p = parentNode(); p && !p->childNeedsStyleRecalc(); p = p->parentNode()) - p->setChildNeedsStyleRecalc(true); + p->setChildNeedsStyleRecalc(); if (document()->childNeedsStyleRecalc()) document()->scheduleStyleRecalc(); } @@ -965,6 +905,39 @@ void Node::notifyNodeListsChildrenChanged() n->notifyLocalNodeListsChildrenChanged(); } +void Node::removeCachedClassNodeList(ClassNodeList* list, const String& className) +{ + ASSERT(rareData()); + ASSERT(rareData()->nodeLists()); + ASSERT_UNUSED(list, list->hasOwnCaches()); + + NodeListsNodeData* data = rareData()->nodeLists(); + ASSERT_UNUSED(list, list == data->m_classNodeListCache.get(className)); + data->m_classNodeListCache.remove(className); +} + +void Node::removeCachedNameNodeList(NameNodeList* list, const String& nodeName) +{ + ASSERT(rareData()); + ASSERT(rareData()->nodeLists()); + ASSERT_UNUSED(list, list->hasOwnCaches()); + + NodeListsNodeData* data = rareData()->nodeLists(); + ASSERT_UNUSED(list, list == data->m_nameNodeListCache.get(nodeName)); + data->m_nameNodeListCache.remove(nodeName); +} + +void Node::removeCachedTagNodeList(TagNodeList* list, const QualifiedName& name) +{ + ASSERT(rareData()); + ASSERT(rareData()->nodeLists()); + ASSERT_UNUSED(list, list->hasOwnCaches()); + + NodeListsNodeData* data = rareData()->nodeLists(); + ASSERT_UNUSED(list, list == data->m_tagNodeListCache.get(name)); + data->m_tagNodeListCache.remove(name); +} + Node *Node::traverseNextNode(const Node *stayWithin) const { if (firstChild()) @@ -1247,7 +1220,7 @@ void Node::attach() } } - m_attached = true; + setAttached(); } void Node::willRemove() @@ -1256,23 +1229,24 @@ void Node::willRemove() void Node::detach() { - m_inDetach = true; + setFlag(InDetachFlag); if (renderer()) renderer()->destroy(); setRenderer(0); Document* doc = document(); - if (m_hovered) + if (hovered()) doc->hoveredNodeDetached(this); - if (m_inActiveChain) + if (inActiveChain()) doc->activeChainNodeDetached(this); - m_active = false; - m_hovered = false; - m_inActiveChain = false; - m_attached = false; - m_inDetach = false; + clearFlag(IsActiveFlag); + clearFlag(IsHoveredFlag); + clearFlag(InActiveChainFlag); + clearFlag(IsAttachedFlag); + + clearFlag(InDetachFlag); } Node *Node::previousEditable() const @@ -1595,11 +1569,13 @@ PassRefPtr<NodeList> Node::getElementsByTagNameNS(const AtomicString& namespaceU AtomicString localNameAtom = name; - pair<NodeListsNodeData::TagCacheMap::iterator, bool> result = data->nodeLists()->m_tagNodeListCaches.add(QualifiedName(nullAtom, localNameAtom, namespaceURI), 0); - if (result.second) - result.first->second = DynamicNodeList::Caches::create(); + pair<NodeListsNodeData::TagNodeListCache::iterator, bool> result = data->nodeLists()->m_tagNodeListCache.add(QualifiedName(nullAtom, localNameAtom, namespaceURI), 0); + if (!result.second) + return PassRefPtr<TagNodeList>(result.first->second); - return TagNodeList::create(this, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localNameAtom, result.first->second.get()); + RefPtr<TagNodeList> list = TagNodeList::create(this, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localNameAtom); + result.first->second = list.get(); + return list.release(); } PassRefPtr<NodeList> Node::getElementsByName(const String& elementName) @@ -1610,11 +1586,13 @@ PassRefPtr<NodeList> Node::getElementsByName(const String& elementName) document()->addNodeListCache(); } - pair<NodeListsNodeData::CacheMap::iterator, bool> result = data->nodeLists()->m_nameNodeListCaches.add(elementName, 0); - if (result.second) - result.first->second = DynamicNodeList::Caches::create(); - - return NameNodeList::create(this, elementName, result.first->second.get()); + pair<NodeListsNodeData::NameNodeListCache::iterator, bool> result = data->nodeLists()->m_nameNodeListCache.add(elementName, 0); + if (!result.second) + return PassRefPtr<NodeList>(result.first->second); + + RefPtr<NameNodeList> list = NameNodeList::create(this, elementName); + result.first->second = list.get(); + return list.release(); } PassRefPtr<NodeList> Node::getElementsByClassName(const String& classNames) @@ -1625,11 +1603,13 @@ PassRefPtr<NodeList> Node::getElementsByClassName(const String& classNames) document()->addNodeListCache(); } - pair<NodeListsNodeData::CacheMap::iterator, bool> result = data->nodeLists()->m_classNodeListCaches.add(classNames, 0); - if (result.second) - result.first->second = DynamicNodeList::Caches::create(); - - return ClassNodeList::create(this, classNames, result.first->second.get()); + pair<NodeListsNodeData::ClassNodeListCache::iterator, bool> result = data->nodeLists()->m_classNodeListCache.add(classNames, 0); + if (!result.second) + return PassRefPtr<NodeList>(result.first->second); + + RefPtr<ClassNodeList> list = ClassNodeList::create(this, classNames); + result.first->second = list.get(); + return list.release(); } PassRefPtr<Element> Node::querySelector(const String& selectors, ExceptionCode& ec) @@ -2271,21 +2251,21 @@ void Node::formatForDebugger(char* buffer, unsigned length) const void NodeListsNodeData::invalidateCaches() { m_childNodeListCaches->reset(); - TagCacheMap::const_iterator tagCachesEnd = m_tagNodeListCaches.end(); - for (TagCacheMap::const_iterator it = m_tagNodeListCaches.begin(); it != tagCachesEnd; ++it) - it->second->reset(); + TagNodeListCache::const_iterator tagCacheEnd = m_tagNodeListCache.end(); + for (TagNodeListCache::const_iterator it = m_tagNodeListCache.begin(); it != tagCacheEnd; ++it) + it->second->invalidateCache(); invalidateCachesThatDependOnAttributes(); } void NodeListsNodeData::invalidateCachesThatDependOnAttributes() { - CacheMap::iterator classCachesEnd = m_classNodeListCaches.end(); - for (CacheMap::iterator it = m_classNodeListCaches.begin(); it != classCachesEnd; ++it) - it->second->reset(); + ClassNodeListCache::iterator classCacheEnd = m_classNodeListCache.end(); + for (ClassNodeListCache::iterator it = m_classNodeListCache.begin(); it != classCacheEnd; ++it) + it->second->invalidateCache(); - CacheMap::iterator nameCachesEnd = m_nameNodeListCaches.end(); - for (CacheMap::iterator it = m_nameNodeListCaches.begin(); it != nameCachesEnd; ++it) - it->second->reset(); + NameNodeListCache::iterator nameCacheEnd = m_nameNodeListCache.end(); + for (NameNodeListCache::iterator it = m_nameNodeListCache.begin(); it != nameCacheEnd; ++it) + it->second->invalidateCache(); } bool NodeListsNodeData::isEmpty() const @@ -2296,20 +2276,20 @@ bool NodeListsNodeData::isEmpty() const if (m_childNodeListCaches->refCount()) return false; - TagCacheMap::const_iterator tagCachesEnd = m_tagNodeListCaches.end(); - for (TagCacheMap::const_iterator it = m_tagNodeListCaches.begin(); it != tagCachesEnd; ++it) { + TagNodeListCache::const_iterator tagCacheEnd = m_tagNodeListCache.end(); + for (TagNodeListCache::const_iterator it = m_tagNodeListCache.begin(); it != tagCacheEnd; ++it) { if (it->second->refCount()) return false; } - CacheMap::const_iterator classCachesEnd = m_classNodeListCaches.end(); - for (CacheMap::const_iterator it = m_classNodeListCaches.begin(); it != classCachesEnd; ++it) { + ClassNodeListCache::const_iterator classCacheEnd = m_classNodeListCache.end(); + for (ClassNodeListCache::const_iterator it = m_classNodeListCache.begin(); it != classCacheEnd; ++it) { if (it->second->refCount()) return false; } - CacheMap::const_iterator nameCachesEnd = m_nameNodeListCaches.end(); - for (CacheMap::const_iterator it = m_nameNodeListCaches.begin(); it != nameCachesEnd; ++it) { + NameNodeListCache::const_iterator nameCacheEnd = m_nameNodeListCache.end(); + for (NameNodeListCache::const_iterator it = m_nameNodeListCache.begin(); it != nameCacheEnd; ++it) { if (it->second->refCount()) return false; } @@ -2384,12 +2364,12 @@ ScriptExecutionContext* Node::scriptExecutionContext() const void Node::insertedIntoDocument() { - setInDocument(true); + setInDocument(); } void Node::removedFromDocument() { - setInDocument(false); + clearInDocument(); } void Node::willMoveToNewOwnerDocument() @@ -2569,6 +2549,28 @@ EventTargetData* Node::ensureEventTargetData() return ensureRareData()->ensureEventTargetData(); } +#if USE(JSC) + +template <class NodeListMap> +void markNodeLists(const NodeListMap& map, JSC::MarkStack& markStack, JSC::JSGlobalData& globalData) +{ + for (typename NodeListMap::const_iterator it = map.begin(); it != map.end(); ++it) + markDOMObjectWrapper(markStack, globalData, it->second); +} + +void Node::markCachedNodeListsSlow(JSC::MarkStack& markStack, JSC::JSGlobalData& globalData) +{ + NodeListsNodeData* nodeLists = rareData()->nodeLists(); + if (!nodeLists) + return; + + markNodeLists(nodeLists->m_classNodeListCache, markStack, globalData); + markNodeLists(nodeLists->m_nameNodeListCache, markStack, globalData); + markNodeLists(nodeLists->m_tagNodeListCache, markStack, globalData); +} + +#endif + void Node::handleLocalEvents(Event* event) { if (!hasRareData() || !rareData()->eventTargetData()) diff --git a/WebCore/dom/Node.h b/WebCore/dom/Node.h index b2af8fc..b165615 100644 --- a/WebCore/dom/Node.h +++ b/WebCore/dom/Node.h @@ -32,10 +32,20 @@ #include "TreeShared.h" #include <wtf/ListHashSet.h> +#if USE(JSC) +namespace JSC { + + class JSGlobalData; + class MarkStack; + +} +#endif + namespace WebCore { class AtomicString; class Attribute; +class ClassNodeList; class ContainerNode; class Document; class DynamicNodeList; @@ -48,6 +58,7 @@ class IntRect; class KeyboardEvent; class NSResolver; class NamedNodeMap; +class NameNodeList; class NodeList; class NodeRareData; class PlatformKeyboardEvent; @@ -61,13 +72,21 @@ class RenderBoxModelObject; class RenderObject; class RenderStyle; class StringBuilder; +class TagNodeList; typedef int ExceptionCode; +const int nodeStyleChangeShift = 24; + // SyntheticStyleChange means that we need to go through the entire style change logic even though // no style property has actually changed. It is used to restructure the tree when, for instance, // RenderLayers are created or destroyed due to animation changes. -enum StyleChangeType { NoStyleChange, InlineStyleChange, FullStyleChange, SyntheticStyleChange }; +enum StyleChangeType { + NoStyleChange = 0, + InlineStyleChange = 1 << nodeStyleChangeShift, + FullStyleChange = 2 << nodeStyleChangeShift, + SyntheticStyleChange = 3 << nodeStyleChangeShift +}; const unsigned short DOCUMENT_POSITION_EQUIVALENT = 0x00; const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01; @@ -162,17 +181,13 @@ public: // Other methods (not part of DOM) - bool isElementNode() const { return m_isElement; } - bool isContainerNode() const { return m_isContainer; } - bool isTextNode() const { return m_isText; } + bool isElementNode() const { return getFlag(IsElementFlag); } + bool isContainerNode() const { return getFlag(IsContainerFlag); } + bool isTextNode() const { return getFlag(IsTextFlag); } - virtual bool isHTMLElement() const { return false; } + bool isHTMLElement() const { return getFlag(IsHTMLFlag); } -#if ENABLE(SVG) - virtual bool isSVGElement() const { return false; } -#else - static bool isSVGElement() { return false; } -#endif + bool isSVGElement() const { return getFlag(IsSVGFlag); } #if ENABLE(WML) virtual bool isWMLElement() const { return false; } @@ -188,10 +203,10 @@ public: virtual bool isMediaControlElement() const { return false; } - virtual bool isStyledElement() const { return false; } + bool isStyledElement() const { return getFlag(IsStyledElementFlag); } virtual bool isFrameOwnerElement() const { return false; } virtual bool isAttributeNode() const { return false; } - virtual bool isCommentNode() const { return false; } + bool isCommentNode() const { return getFlag(IsCommentFlag); } virtual bool isCharacterDataNode() const { return false; } bool isDocumentNode() const; virtual bool isShadowNode() const { return false; } @@ -268,33 +283,40 @@ public: // For <link> and <style> elements. virtual bool sheetLoaded() { return true; } - bool hasID() const { return m_hasId; } - bool hasClass() const { return m_hasClass; } - bool active() const { return m_active; } - bool inActiveChain() const { return m_inActiveChain; } - bool inDetach() const { return m_inDetach; } - bool hovered() const { return m_hovered; } + bool hasID() const { return getFlag(HasIDFlag); } + bool hasClass() const { return getFlag(HasClassFlag); } + bool active() const { return getFlag(IsActiveFlag); } + bool inActiveChain() const { return getFlag(InActiveChainFlag); } + bool inDetach() const { return getFlag(InDetachFlag); } + bool hovered() const { return getFlag(IsHoveredFlag); } bool focused() const { return hasRareData() ? rareDataFocused() : false; } - bool attached() const { return m_attached; } - void setAttached(bool b = true) { m_attached = b; } - bool needsStyleRecalc() const { return m_styleChange != NoStyleChange; } - StyleChangeType styleChangeType() const { return static_cast<StyleChangeType>(m_styleChange); } - bool childNeedsStyleRecalc() const { return m_childNeedsStyleRecalc; } - bool isLink() const { return m_isLink; } - void setHasID(bool b = true) { m_hasId = b; } - void setHasClass(bool b = true) { m_hasClass = b; } - void setChildNeedsStyleRecalc(bool b = true) { m_childNeedsStyleRecalc = b; } - void setInDocument(bool b = true) { m_inDocument = b; } - void setInActiveChain(bool b = true) { m_inActiveChain = b; } + bool attached() const { return getFlag(IsAttachedFlag); } + void setAttached() { setFlag(IsAttachedFlag); } + bool needsStyleRecalc() const { return styleChangeType() != NoStyleChange; } + StyleChangeType styleChangeType() const { return static_cast<StyleChangeType>(m_nodeFlags & StyleChangeMask); } + bool childNeedsStyleRecalc() const { return getFlag(ChildNeedsStyleRecalcFlag); } + bool isLink() const { return getFlag(IsLinkFlag); } + + void setHasID(bool f) { setFlag(f, HasIDFlag); } + void setHasClass(bool f) { setFlag(f, HasClassFlag); } + void setChildNeedsStyleRecalc() { setFlag(ChildNeedsStyleRecalcFlag); } + void clearChildNeedsStyleRecalc() { clearFlag(ChildNeedsStyleRecalcFlag); } + void setInDocument() { setFlag(InDocumentFlag); } + void clearInDocument() { clearFlag(InDocumentFlag); } + + void setInActiveChain() { setFlag(InActiveChainFlag); } + void clearInActiveChain() { clearFlag(InActiveChainFlag); } void setNeedsStyleRecalc(StyleChangeType changeType = FullStyleChange); - void setIsLink(bool b = true) { m_isLink = b; } + void setIsLink(bool f) { setFlag(f, IsLinkFlag); } + void setIsLink() { setFlag(IsLinkFlag); } + void clearIsLink() { clearFlag(IsLinkFlag); } void lazyAttach(); virtual bool canLazyAttach(); virtual void setFocus(bool b = true); - virtual void setActive(bool b = true, bool /*pause*/ = false) { m_active = b; } - virtual void setHovered(bool b = true) { m_hovered = b; } + virtual void setActive(bool f = true, bool /*pause*/ = false) { setFlag(f, IsActiveFlag); } + virtual void setHovered(bool f = true) { setFlag(f, IsHoveredFlag); } virtual short tabIndex() const; @@ -311,6 +333,11 @@ public: virtual bool shouldUseInputMethod() const; virtual IntRect getRect() const; + // Returns true if the node has a non-empty bounding box in layout. + // This does not 100% guarantee the user can see it, but is pretty close. + // Note: This method only works properly after layout has occurred. + bool hasNonEmptyBoundingBox() const; + virtual void recalcStyle(StyleChange = NoChange) { } unsigned nodeIndex() const; @@ -333,8 +360,8 @@ public: // node tree, false otherwise. bool inDocument() const { - ASSERT(m_document || !m_inDocument); - return m_inDocument; + ASSERT(m_document || !getFlag(InDocumentFlag)); + return getFlag(InDocumentFlag); } bool isReadOnlyNode() const { return nodeType() == ENTITY_REFERENCE_NODE; } @@ -497,6 +524,9 @@ public: void notifyLocalNodeListsChildrenChanged(); void notifyNodeListsAttributeChanged(); void notifyLocalNodeListsAttributeChanged(); + void removeCachedClassNodeList(ClassNodeList*, const String&); + void removeCachedNameNodeList(NameNodeList*, const String&); + void removeCachedTagNodeList(TagNodeList*, const QualifiedName&); PassRefPtr<NodeList> getElementsByTagName(const String&); PassRefPtr<NodeList> getElementsByTagNameNS(const AtomicString& namespaceURI, const String& localName); @@ -571,10 +601,82 @@ public: virtual EventTargetData* eventTargetData(); virtual EventTargetData* ensureEventTargetData(); +#if USE(JSC) + void markCachedNodeLists(JSC::MarkStack& markStack, JSC::JSGlobalData& globalData) + { + // NodeLists may be present. If so, they need to be marked. + if (!hasRareData()) + return; + + markCachedNodeListsSlow(markStack, globalData); + } +#endif + +private: + enum NodeFlags { + IsTextFlag = 1, + IsCommentFlag = 1 << 1, + IsContainerFlag = 1 << 2, + IsElementFlag = 1 << 3, + IsStyledElementFlag = 1 << 4, + IsHTMLFlag = 1 << 5, + IsSVGFlag = 1 << 6, + HasIDFlag = 1 << 7, + HasClassFlag = 1 << 8, + IsAttachedFlag = 1 << 9, + ChildNeedsStyleRecalcFlag = 1 << 10, + InDocumentFlag = 1 << 11, + IsLinkFlag = 1 << 12, + IsActiveFlag = 1 << 13, + IsHoveredFlag = 1 << 14, + InActiveChainFlag = 1 << 15, + InDetachFlag = 1 << 16, + HasRareDataFlag = 1 << 17, + + // These bits are used by derived classes, pulled up here so they can + // be stored in the same memory word as the Node bits above. + IsParsingChildrenFinishedFlag = 1 << 18, // Element + IsStyleAttributeValidFlag = 1 << 19, // StyledElement + IsSynchronizingStyleAttributeFlag = 1 << 20, // StyledElement +#if ENABLE(SVG) + AreSVGAttributesValidFlag = 1 << 21, // Element + IsSynchronizingSVGAttributesFlag = 1 << 22, // SVGElement + HasSVGRareDataFlag = 1 << 23, // SVGElement +#endif + StyleChangeMask = 1 << nodeStyleChangeShift | 1 << (nodeStyleChangeShift + 1), + CreateWithZeroRefCountFlag = 1 << 26, + +#if ENABLE(SVG) + DefaultNodeFlags = IsParsingChildrenFinishedFlag | IsStyleAttributeValidFlag | AreSVGAttributesValidFlag +#else + DefaultNodeFlags = IsParsingChildrenFinishedFlag | IsStyleAttributeValidFlag +#endif + }; + + // 5 bits remaining + + bool getFlag(NodeFlags mask) const { return m_nodeFlags & mask; } + void setFlag(bool f, NodeFlags mask) const { m_nodeFlags = (m_nodeFlags & ~mask) | (-(int32_t)f & mask); } + void setFlag(NodeFlags mask) const { m_nodeFlags |= mask; } + void clearFlag(NodeFlags mask) const { m_nodeFlags &= ~mask; } + protected: // CreateElementZeroRefCount is deprecated and can be removed once we convert all element // classes to start with a reference count of 1. - enum ConstructionType { CreateContainer, CreateElement, CreateOther, CreateText, CreateElementZeroRefCount }; + enum ConstructionType { + CreateOther = DefaultNodeFlags, + CreateText = DefaultNodeFlags | IsTextFlag, + CreateComment = DefaultNodeFlags | IsCommentFlag, + CreateContainer = DefaultNodeFlags | IsContainerFlag, + CreateElement = CreateContainer | IsElementFlag, + CreateElementZeroRefCount = IsElementFlag | CreateWithZeroRefCountFlag, + CreateStyledElement = CreateElement | IsStyledElementFlag, + CreateStyledElementZeroRefCount = CreateStyledElement | CreateWithZeroRefCountFlag, + CreateHTMLElement = CreateStyledElement | IsHTMLFlag, + CreateHTMLElementZeroRefCount = CreateHTMLElement | CreateWithZeroRefCountFlag, + CreateSVGElement = CreateStyledElement | IsSVGFlag, + CreateSVGElementZeroRefCount = CreateSVGElement | CreateWithZeroRefCountFlag, + }; Node(Document*, ConstructionType); virtual void willMoveToNewOwnerDocument(); @@ -583,19 +685,18 @@ protected: virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const { } void setTabIndexExplicitly(short); - bool hasRareData() const { return m_hasRareData; } -#if ENABLE(SVG) - bool hasRareSVGData() const { return m_hasRareSVGData; } -#endif + bool hasRareData() const { return getFlag(HasRareDataFlag); } NodeRareData* rareData() const; NodeRareData* ensureRareData(); private: +#if USE(JSC) + void markCachedNodeListsSlow(JSC::MarkStack&, JSC::JSGlobalData&); +#endif + static bool initialRefCount(ConstructionType); - static bool isContainer(ConstructionType); - static bool isElement(ConstructionType); - static bool isText(ConstructionType); + void setStyleChange(StyleChangeType); virtual void refEventTarget() { ref(); } virtual void derefEventTarget() { deref(); } @@ -617,45 +718,45 @@ private: Element* ancestorElement() const; void appendTextContent(bool convertBRsToNewlines, StringBuilder&) const; + void trackForDebugging(); Document* m_document; Node* m_previous; Node* m_next; RenderObject* m_renderer; - - unsigned m_styleChange : 2; - bool m_hasId : 1; - bool m_hasClass : 1; - bool m_attached : 1; - bool m_childNeedsStyleRecalc : 1; - bool m_inDocument : 1; - bool m_isLink : 1; - bool m_active : 1; - bool m_hovered : 1; - bool m_inActiveChain : 1; - bool m_inDetach : 1; - bool m_hasRareData : 1; - const bool m_isElement : 1; - const bool m_isContainer : 1; - const bool m_isText : 1; - -protected: - // These bits are used by derived classes, pulled up here so they can - // be stored in the same memory word as the Node bits above. - - bool m_parsingChildrenFinished : 1; // Element - mutable bool m_isStyleAttributeValid : 1; // StyledElement - mutable bool m_synchronizingStyleAttribute : 1; // StyledElement + mutable uint32_t m_nodeFlags; + + protected: + bool isParsingChildrenFinished() const { return getFlag(IsParsingChildrenFinishedFlag); } + void setIsParsingChildrenFinished() { setFlag(IsParsingChildrenFinishedFlag); } + void clearIsParsingChildrenFinished() { clearFlag(IsParsingChildrenFinishedFlag); } + bool isStyleAttributeValid() const { return getFlag(IsStyleAttributeValidFlag); } + void setIsStyleAttributeValid(bool f) { setFlag(f, IsStyleAttributeValidFlag); } + void setIsStyleAttributeValid() const { setFlag(IsStyleAttributeValidFlag); } + void clearIsStyleAttributeValid() { clearFlag(IsStyleAttributeValidFlag); } + bool isSynchronizingStyleAttribute() const { return getFlag(IsSynchronizingStyleAttributeFlag); } + void setIsSynchronizingStyleAttribute(bool f) { setFlag(f, IsSynchronizingStyleAttributeFlag); } + void setIsSynchronizingStyleAttribute() const { setFlag(IsSynchronizingStyleAttributeFlag); } + void clearIsSynchronizingStyleAttribute() const { clearFlag(IsSynchronizingStyleAttributeFlag); } #if ENABLE(SVG) - mutable bool m_areSVGAttributesValid : 1; // Element - mutable bool m_synchronizingSVGAttributes : 1; // SVGElement - bool m_hasRareSVGData : 1; // SVGElement + bool areSVGAttributesValid() const { return getFlag(AreSVGAttributesValidFlag); } + void setAreSVGAttributesValid() const { setFlag(AreSVGAttributesValidFlag); } + void clearAreSVGAttributesValid() { clearFlag(AreSVGAttributesValidFlag); } + bool isSynchronizingSVGAttributes() const { return getFlag(IsSynchronizingSVGAttributesFlag); } + void setIsSynchronizingSVGAttributes() const { setFlag(IsSynchronizingSVGAttributesFlag); } + void clearIsSynchronizingSVGAttributes() const { clearFlag(IsSynchronizingSVGAttributesFlag); } + bool hasRareSVGData() const { return getFlag(HasSVGRareDataFlag); } + void setHasRareSVGData() { setFlag(HasSVGRareDataFlag); } + void clearHasRareSVGData() { clearFlag(HasSVGRareDataFlag); } #endif - - // 10 bits remaining }; +inline bool Node::initialRefCount(ConstructionType type) +{ + return !(type & CreateWithZeroRefCountFlag); +} + // Used in Node::addSubresourceAttributeURLs() and in addSubresourceStyleURLs() inline void addSubresourceURL(ListHashSet<KURL>& urls, const KURL& url) { diff --git a/WebCore/dom/Node.idl b/WebCore/dom/Node.idl index c0f159c..7bc6d1d 100644 --- a/WebCore/dom/Node.idl +++ b/WebCore/dom/Node.idl @@ -62,9 +62,7 @@ module core { readonly attribute Node previousSibling; readonly attribute Node nextSibling; readonly attribute NamedNodeMap attributes; -#if !defined(LANGUAGE_GOBJECT) || !LANGUAGE_GOBJECT readonly attribute Document ownerDocument; -#endif [OldStyleObjC, Custom] Node insertBefore(in [Return] Node newChild, in Node refChild) @@ -136,12 +134,12 @@ module core { #if !defined(LANGUAGE_OBJECTIVE_C) || !LANGUAGE_OBJECTIVE_C #if !defined(LANGUAGE_GOBJECT) || !LANGUAGE_GOBJECT - [JSCCustom] void addEventListener(in DOMString type, - in EventListener listener, - in boolean useCapture); - [JSCCustom] void removeEventListener(in DOMString type, - in EventListener listener, - in boolean useCapture); + void addEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + void removeEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); boolean dispatchEvent(in Event event) raises(EventException); #endif diff --git a/WebCore/dom/NodeFilter.idl b/WebCore/dom/NodeFilter.idl index d721f80..16f3f26 100644 --- a/WebCore/dom/NodeFilter.idl +++ b/WebCore/dom/NodeFilter.idl @@ -43,7 +43,7 @@ module traversal { const unsigned long SHOW_DOCUMENT_FRAGMENT = 0x00000400; const unsigned long SHOW_NOTATION = 0x00000800; - [Custom] short acceptNode(in Node n); + [CallWith=ScriptState] short acceptNode(in Node n); }; diff --git a/WebCore/dom/NodeIterator.idl b/WebCore/dom/NodeIterator.idl index e1818a1..9f59ae1 100644 --- a/WebCore/dom/NodeIterator.idl +++ b/WebCore/dom/NodeIterator.idl @@ -31,9 +31,9 @@ module traversal { readonly attribute Node referenceNode; readonly attribute boolean pointerBeforeReferenceNode; - [Custom] Node nextNode() + [CallWith=ScriptState] Node nextNode() raises (DOMException); - [Custom] Node previousNode() + [CallWith=ScriptState] Node previousNode() raises (DOMException); void detach(); }; diff --git a/WebCore/dom/NodeRareData.h b/WebCore/dom/NodeRareData.h index 6e9d0e4..3d2cf0c 100644 --- a/WebCore/dom/NodeRareData.h +++ b/WebCore/dom/NodeRareData.h @@ -22,11 +22,14 @@ #ifndef NodeRareData_h #define NodeRareData_h +#include "ClassNodeList.h" #include "DynamicNodeList.h" #include "EventListener.h" +#include "NameNodeList.h" +#include "QualifiedName.h" #include "RegisteredEventListener.h" #include "StringHash.h" -#include "QualifiedName.h" +#include "TagNodeList.h" #include <wtf/HashSet.h> #include <wtf/PassOwnPtr.h> #include <wtf/OwnPtr.h> @@ -39,12 +42,14 @@ struct NodeListsNodeData : Noncopyable { RefPtr<DynamicNodeList::Caches> m_childNodeListCaches; - typedef HashMap<String, RefPtr<DynamicNodeList::Caches> > CacheMap; - CacheMap m_classNodeListCaches; - CacheMap m_nameNodeListCaches; + typedef HashMap<String, ClassNodeList*> ClassNodeListCache; + ClassNodeListCache m_classNodeListCache; + + typedef HashMap<String, NameNodeList*> NameNodeListCache; + NameNodeListCache m_nameNodeListCache; - typedef HashMap<QualifiedName, RefPtr<DynamicNodeList::Caches> > TagCacheMap; - TagCacheMap m_tagNodeListCaches; + typedef HashMap<QualifiedName, TagNodeList*> TagNodeListCache; + TagNodeListCache m_tagNodeListCache; static PassOwnPtr<NodeListsNodeData> create() { diff --git a/WebCore/dom/Notation.cpp b/WebCore/dom/Notation.cpp index cade384..4b3ab28 100644 --- a/WebCore/dom/Notation.cpp +++ b/WebCore/dom/Notation.cpp @@ -21,6 +21,8 @@ #include "config.h" #include "Notation.h" +#include "Document.h" + namespace WebCore { Notation::Notation(Document* document, const String& name, const String& publicId, const String& systemId) diff --git a/WebCore/dom/PopStateEvent.idl b/WebCore/dom/PopStateEvent.idl index f9c9a71..28da9e6 100644 --- a/WebCore/dom/PopStateEvent.idl +++ b/WebCore/dom/PopStateEvent.idl @@ -27,11 +27,11 @@ module events { interface PopStateEvent : Event { - [Custom] void initPopStateEvent(in DOMString typeArg, + void initPopStateEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, - in any stateArg); - + in SerializedScriptValue stateArg); + readonly attribute [V8CustomGetter] any state; }; diff --git a/WebCore/dom/Position.cpp b/WebCore/dom/Position.cpp index fa994e3..fdcd7e5 100644 --- a/WebCore/dom/Position.cpp +++ b/WebCore/dom/Position.cpp @@ -986,27 +986,46 @@ static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer) return 0; } +static Position downstreamIgnoringEditingBoundaries(Position position) +{ + Position lastPosition; + while (position != lastPosition) { + lastPosition = position; + position = position.downstream(Position::CanCrossEditingBoundary); + } + return position; +} + +static Position upstreamIgnoringEditingBoundaries(Position position) +{ + Position lastPosition; + while (position != lastPosition) { + lastPosition = position; + position = position.upstream(Position::CanCrossEditingBoundary); + } + return position; +} + void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const { caretOffset = m_offset; RenderObject* renderer = node()->renderer(); - + if (!renderer->isText()) { - if (!renderer->isRenderButton() && renderer->isBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) { - bool lastPosition = caretOffset == lastOffsetInNode(node()); - Node* startNode = lastPosition ? node()->childNode(caretOffset - 1) : node()->childNode(caretOffset); - while (startNode && (!startNode->renderer() || (startNode->isTextNode() && toRenderText(startNode->renderer())->isAllCollapsibleWhitespace()))) - startNode = (lastPosition)? startNode->previousSibling(): startNode->nextSibling(); - if (startNode) { - Position pos(startNode, 0); - pos = pos.downstream(CanCrossEditingBoundary); - pos.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset); - if (lastPosition && inlineBox) - caretOffset = inlineBox->caretMaxOffset(); + inlineBox = 0; + if (canHaveChildrenForEditing(node()) && renderer->isBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) { + // Try a visually equivalent position with possibly opposite editability. This helps in case |this| is in + // an editable block but surrounded by non-editable positions. It acts to negate the logic at the beginning + // of RenderObject::createVisiblePosition(). + Position equivalent = downstreamIgnoringEditingBoundaries(*this); + if (equivalent == *this) + equivalent = upstreamIgnoringEditingBoundaries(*this); + if (equivalent == *this) return; - } + + equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset); + return; } - inlineBox = 0; if (renderer->isBox()) { inlineBox = toRenderBox(renderer)->inlineBoxWrapper(); if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset())) diff --git a/WebCore/dom/QualifiedName.cpp b/WebCore/dom/QualifiedName.cpp index 6f5a74f..7cc809f 100644 --- a/WebCore/dom/QualifiedName.cpp +++ b/WebCore/dom/QualifiedName.cpp @@ -78,6 +78,7 @@ void QualifiedName::deref() if (!m_impl) return; #endif + ASSERT(!isHashTableDeletedValue()); if (m_impl->hasOneRef()) gNameCache->remove(m_impl); diff --git a/WebCore/dom/QualifiedName.h b/WebCore/dom/QualifiedName.h index 7581ba1..672a302 100644 --- a/WebCore/dom/QualifiedName.h +++ b/WebCore/dom/QualifiedName.h @@ -58,6 +58,8 @@ public: QualifiedName(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI); QualifiedName(const AtomicString& prefix, const char* localName, const AtomicString& namespaceURI); + QualifiedName(WTF::HashTableDeletedValueType) : m_impl(hashTableDeletedValue()) { } + bool isHashTableDeletedValue() const { return m_impl == hashTableDeletedValue(); } ~QualifiedName() { deref(); } #ifdef QNAME_DEFAULT_CONSTRUCTOR QualifiedName() : m_impl(0) { } @@ -92,6 +94,8 @@ private: void init(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI); void ref() const { m_impl->ref(); } void deref(); + + static QualifiedNameImpl* hashTableDeletedValue() { return RefPtr<QualifiedNameImpl>::hashTableDeletedValue(); } QualifiedNameImpl* m_impl; }; @@ -167,8 +171,8 @@ namespace WTF { template<> struct HashTraits<WebCore::QualifiedName> : GenericHashTraits<WebCore::QualifiedName> { static const bool emptyValueIsZero = false; static WebCore::QualifiedName emptyValue() { return WebCore::QualifiedName(WebCore::nullAtom, WebCore::nullAtom, WebCore::nullAtom); } - static void constructDeletedValue(WebCore::QualifiedName& slot) { new (&slot) WebCore::QualifiedName(WebCore::nullAtom, WebCore::AtomicString(HashTableDeletedValue), WebCore::nullAtom); } - static bool isDeletedValue(const WebCore::QualifiedName& slot) { return slot.localName().isHashTableDeletedValue(); } + static void constructDeletedValue(WebCore::QualifiedName& slot) { new (&slot) WebCore::QualifiedName(WTF::HashTableDeletedValue); } + static bool isDeletedValue(const WebCore::QualifiedName& slot) { return slot.isHashTableDeletedValue(); } }; } diff --git a/WebCore/dom/ScriptExecutionContext.h b/WebCore/dom/ScriptExecutionContext.h index d0f2e26..18e2cd0 100644 --- a/WebCore/dom/ScriptExecutionContext.h +++ b/WebCore/dom/ScriptExecutionContext.h @@ -76,6 +76,7 @@ namespace WebCore { void stopDatabases(DatabaseTaskSynchronizer*); #endif virtual bool isContextThread() const = 0; + virtual bool isJSExecutionTerminated() const = 0; const KURL& url() const { return virtualURL(); } KURL completeURL(const String& url) const { return virtualCompleteURL(url); } diff --git a/WebCore/dom/SelectElement.cpp b/WebCore/dom/SelectElement.cpp index 4af90c9..fb7d9a6 100644 --- a/WebCore/dom/SelectElement.cpp +++ b/WebCore/dom/SelectElement.cpp @@ -529,12 +529,8 @@ static int nextValidIndex(const Vector<Element*>& listItems, int listIndex, Skip } #endif -void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm) +void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element* element, Event* event) { -#if !ARROW_KEYS_POP_MENU - UNUSED_PARAM(htmlForm); -#endif - if (event->type() == eventNames().keydownEvent) { if (!element->renderer() || !event->isKeyboardEvent()) return; @@ -613,8 +609,6 @@ void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element handled = true; } else if (keyCode == '\r') { menuListOnChange(data, element); - if (htmlForm) - htmlForm->submitClick(event); handled = true; } #else @@ -693,7 +687,7 @@ void SelectElement::updateSelectedState(SelectElementData& data, Element* elemen updateListBoxSelection(data, element, !multiSelect); } -void SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm) +void SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element* element, Event* event) { const Vector<Element*>& listItems = data.listItems(element); @@ -759,29 +753,18 @@ void SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element* listBoxOnChange(data, element); event->setDefaultHandled(); } - } else if (event->type() == eventNames().keypressEvent) { - if (!event->isKeyboardEvent()) - return; - int keyCode = static_cast<KeyboardEvent*>(event)->keyCode(); - - if (keyCode == '\r') { - if (htmlForm) - htmlForm->submitClick(event); - event->setDefaultHandled(); - return; - } } } -void SelectElement::defaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm) +void SelectElement::defaultEventHandler(SelectElementData& data, Element* element, Event* event) { if (!element->renderer()) return; if (data.usesMenuList()) - menuListDefaultEventHandler(data, element, event, htmlForm); + menuListDefaultEventHandler(data, element, event); else - listBoxDefaultEventHandler(data, element, event, htmlForm); + listBoxDefaultEventHandler(data, element, event); if (event->defaultHandled()) return; diff --git a/WebCore/dom/SelectElement.h b/WebCore/dom/SelectElement.h index dcb6879..6db841e 100644 --- a/WebCore/dom/SelectElement.h +++ b/WebCore/dom/SelectElement.h @@ -92,7 +92,7 @@ protected: static void parseMultipleAttribute(SelectElementData&, Element*, MappedAttribute*); static bool appendFormData(SelectElementData&, Element*, FormDataList&); static void reset(SelectElementData&, Element*); - static void defaultEventHandler(SelectElementData&, Element*, Event*, HTMLFormElement* = 0); + static void defaultEventHandler(SelectElementData&, Element*, Event*); static int lastSelectedListIndex(const SelectElementData&, const Element*); static void typeAheadFind(SelectElementData&, Element*, KeyboardEvent*); static void insertedIntoTree(SelectElementData&, Element*); @@ -103,8 +103,8 @@ protected: bool multi, bool shift); private: - static void menuListDefaultEventHandler(SelectElementData&, Element*, Event*, HTMLFormElement*); - static void listBoxDefaultEventHandler(SelectElementData&, Element*, Event*, HTMLFormElement*); + static void menuListDefaultEventHandler(SelectElementData&, Element*, Event*); + static void listBoxDefaultEventHandler(SelectElementData&, Element*, Event*); static void setOptionsChangedOnRenderer(SelectElementData&, Element*); }; diff --git a/WebCore/dom/StyledElement.cpp b/WebCore/dom/StyledElement.cpp index 3607963..cd5f863 100644 --- a/WebCore/dom/StyledElement.cpp +++ b/WebCore/dom/StyledElement.cpp @@ -103,17 +103,12 @@ void StyledElement::removeMappedAttributeDecl(MappedAttributeEntry entryType, co void StyledElement::updateStyleAttribute() const { - ASSERT(!m_isStyleAttributeValid); - m_isStyleAttributeValid = true; - m_synchronizingStyleAttribute = true; + ASSERT(!isStyleAttributeValid()); + setIsStyleAttributeValid(); + setIsSynchronizingStyleAttribute(); if (m_inlineStyleDecl) const_cast<StyledElement*>(this)->setAttribute(styleAttr, m_inlineStyleDecl->cssText()); - m_synchronizingStyleAttribute = false; -} - -StyledElement::StyledElement(const QualifiedName& name, Document* document, ConstructionType type) - : Element(name, document, type) -{ + clearIsSynchronizingStyleAttribute(); } StyledElement::~StyledElement() @@ -208,7 +203,7 @@ bool StyledElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEnt { result = eNone; if (attrName == styleAttr) - return !m_synchronizingStyleAttribute; + return !isSynchronizingStyleAttribute(); return true; } @@ -253,7 +248,7 @@ void StyledElement::parseMappedAttribute(MappedAttribute *attr) destroyInlineStyleDecl(); else getInlineStyleDecl()->parseDeclaration(attr->value()); - m_isStyleAttributeValid = true; + setIsStyleAttributeValid(); setNeedsStyleRecalc(); } } @@ -476,8 +471,8 @@ void StyledElement::copyNonAttributeProperties(const Element *sourceElement) return; *getInlineStyleDecl() = *source->m_inlineStyleDecl; - m_isStyleAttributeValid = source->m_isStyleAttributeValid; - m_synchronizingStyleAttribute = source->m_synchronizingStyleAttribute; + setIsStyleAttributeValid(source->isStyleAttributeValid()); + setIsSynchronizingStyleAttribute(source->isSynchronizingStyleAttribute()); Element::copyNonAttributeProperties(sourceElement); } diff --git a/WebCore/dom/StyledElement.h b/WebCore/dom/StyledElement.h index 52bffd3..279282c 100644 --- a/WebCore/dom/StyledElement.h +++ b/WebCore/dom/StyledElement.h @@ -25,6 +25,7 @@ #ifndef StyledElement_h #define StyledElement_h +#include "CSSMutableStyleDeclaration.h" #include "CSSPrimitiveValue.h" #include "Element.h" #include "MappedAttributeEntry.h" @@ -33,7 +34,6 @@ namespace WebCore { class CSSMappedAttributeDeclaration; -class CSSMutableStyleDeclaration; class MappedAttribute; class StyledElement : public Element { @@ -73,7 +73,10 @@ public: virtual PassRefPtr<Attribute> createAttribute(const QualifiedName&, const AtomicString& value); protected: - StyledElement(const QualifiedName&, Document*, ConstructionType); + StyledElement(const QualifiedName& name, Document* document, ConstructionType type) + : Element(name, document, type) + { + } virtual void attributeChanged(Attribute*, bool preserveDecls = false); virtual void parseMappedAttribute(MappedAttribute*); @@ -89,8 +92,6 @@ protected: virtual void didMoveToNewOwnerDocument(); private: - virtual bool isStyledElement() const { return true; } - void createMappedDecl(MappedAttribute*); void createInlineStyleDecl(); @@ -104,7 +105,7 @@ private: inline void StyledElement::invalidateStyleAttribute() { - m_isStyleAttributeValid = false; + clearIsStyleAttributeValid(); } } //namespace diff --git a/WebCore/dom/TagNodeList.cpp b/WebCore/dom/TagNodeList.cpp index bec9b8e..4914e09 100644 --- a/WebCore/dom/TagNodeList.cpp +++ b/WebCore/dom/TagNodeList.cpp @@ -29,14 +29,19 @@ namespace WebCore { -TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName, DynamicNodeList::Caches* caches) - : DynamicNodeList(rootNode, caches) +TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName) + : DynamicNodeList(rootNode) , m_namespaceURI(namespaceURI) , m_localName(localName) { ASSERT(m_namespaceURI.isNull() || !m_namespaceURI.isEmpty()); } +TagNodeList::~TagNodeList() +{ + m_rootNode->removeCachedTagNodeList(this, QualifiedName(nullAtom, m_localName, m_namespaceURI)); +} + bool TagNodeList::nodeMatches(Element* testNode) const { if (m_namespaceURI != starAtom && m_namespaceURI != testNode->namespaceURI()) diff --git a/WebCore/dom/TagNodeList.h b/WebCore/dom/TagNodeList.h index 0031bad..1b1a038 100644 --- a/WebCore/dom/TagNodeList.h +++ b/WebCore/dom/TagNodeList.h @@ -32,13 +32,15 @@ namespace WebCore { // NodeList that limits to a particular tag. class TagNodeList : public DynamicNodeList { public: - static PassRefPtr<TagNodeList> create(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName, DynamicNodeList::Caches* caches) + static PassRefPtr<TagNodeList> create(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName) { - return adoptRef(new TagNodeList(rootNode, namespaceURI, localName, caches)); + return adoptRef(new TagNodeList(rootNode, namespaceURI, localName)); } + virtual ~TagNodeList(); + private: - TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName, DynamicNodeList::Caches* caches); + TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName); virtual bool nodeMatches(Element*) const; diff --git a/WebCore/dom/Text.cpp b/WebCore/dom/Text.cpp index cf98817..14da1a4 100644 --- a/WebCore/dom/Text.cpp +++ b/WebCore/dom/Text.cpp @@ -41,11 +41,6 @@ using namespace std; namespace WebCore { -Text::Text(Document* document, const String& data) - : CharacterData(document, data, CreateText) -{ -} - PassRefPtr<Text> Text::create(Document* document, const String& data) { return adoptRef(new Text(document, data)); diff --git a/WebCore/dom/Text.h b/WebCore/dom/Text.h index 4722736..45678ef 100644 --- a/WebCore/dom/Text.h +++ b/WebCore/dom/Text.h @@ -44,7 +44,10 @@ public: virtual void attach(); protected: - Text(Document*, const String&); + Text(Document* document, const String& data) + : CharacterData(document, data, CreateText) + { + } private: virtual String nodeName() const; diff --git a/WebCore/dom/Tokenizer.h b/WebCore/dom/Tokenizer.h index 9a9b7b3..939ac70 100644 --- a/WebCore/dom/Tokenizer.h +++ b/WebCore/dom/Tokenizer.h @@ -25,6 +25,7 @@ namespace WebCore { + class HTMLTokenizer; class SegmentedString; class XSSAuditor; @@ -57,6 +58,7 @@ namespace WebCore { virtual void executeScriptsWaitingForStylesheets() {} virtual bool isHTMLTokenizer() const { return false; } + virtual HTMLTokenizer* asHTMLTokenizer() { return 0; } XSSAuditor* xssAuditor() const { return m_XSSAuditor; } void setXSSAuditor(XSSAuditor* auditor) { m_XSSAuditor = auditor; } diff --git a/WebCore/dom/TreeDepthLimit.h b/WebCore/dom/TreeDepthLimit.h new file mode 100644 index 0000000..e78e093 --- /dev/null +++ b/WebCore/dom/TreeDepthLimit.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TreeDepthLimit_h +#define TreeDepthLimit_h + +#ifndef MAX_DOM_TREE_DEPTH +#define MAX_DOM_TREE_DEPTH 5000 +#endif +const unsigned maxDOMTreeDepth = MAX_DOM_TREE_DEPTH; + +#endif // TreeDepthLimit.h + diff --git a/WebCore/dom/TreeWalker.idl b/WebCore/dom/TreeWalker.idl index f591128..890e315 100644 --- a/WebCore/dom/TreeWalker.idl +++ b/WebCore/dom/TreeWalker.idl @@ -31,13 +31,13 @@ module traversal { attribute Node currentNode setter raises(DOMException); - [Custom] Node parentNode(); - [Custom] Node firstChild(); - [Custom] Node lastChild(); - [Custom] Node previousSibling(); - [Custom] Node nextSibling(); - [Custom] Node previousNode(); - [Custom] Node nextNode(); + [CallWith=ScriptState] Node parentNode(); + [CallWith=ScriptState] Node firstChild(); + [CallWith=ScriptState] Node lastChild(); + [CallWith=ScriptState] Node previousSibling(); + [CallWith=ScriptState] Node nextSibling(); + [CallWith=ScriptState] Node previousNode(); + [CallWith=ScriptState] Node nextNode(); }; } diff --git a/WebCore/dom/XMLTokenizer.cpp b/WebCore/dom/XMLTokenizer.cpp index 818dacd..1d98dfe 100644 --- a/WebCore/dom/XMLTokenizer.cpp +++ b/WebCore/dom/XMLTokenizer.cpp @@ -50,6 +50,7 @@ #include "ScriptSourceCode.h" #include "ScriptValue.h" #include "TextResourceDecoder.h" +#include "TreeDepthLimit.h" #include <wtf/text/CString.h> #include <wtf/StringExtras.h> #include <wtf/Threading.h> @@ -67,7 +68,6 @@ namespace WebCore { using namespace HTMLNames; const int maxErrors = 25; -const size_t maxNestingDepth = 4096; #if ENABLE(WML) bool XMLTokenizer::isWMLDocument() const @@ -87,7 +87,7 @@ void XMLTokenizer::pushCurrentNode(Node* n) n->ref(); m_currentNodeStack.append(m_currentNode); m_currentNode = n; - if (m_currentNodeStack.size() > maxNestingDepth) + if (m_currentNodeStack.size() > maxDOMTreeDepth) handleError(fatal, "Excessive node nesting.", lineNumber(), columnNumber()); } |