diff options
author | Ben Murdoch <benm@google.com> | 2009-08-11 17:01:47 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2009-08-11 18:21:02 +0100 |
commit | 0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5 (patch) | |
tree | 2943df35f62d885c89d01063cc528dd73b480fea /WebCore/wml | |
parent | 7e7a70bfa49a1122b2597a1e6367d89eb4035eca (diff) | |
download | external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.zip external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.gz external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.bz2 |
Merge in WebKit r47029.
Diffstat (limited to 'WebCore/wml')
42 files changed, 910 insertions, 235 deletions
diff --git a/WebCore/wml/WMLAElement.cpp b/WebCore/wml/WMLAElement.cpp index 5fbeac6..9c84193 100644 --- a/WebCore/wml/WMLAElement.cpp +++ b/WebCore/wml/WMLAElement.cpp @@ -150,7 +150,7 @@ void WMLAElement::defaultEventHandler(Event* event) } if (!event->defaultPrevented() && document()->frame()) { - KURL url = document()->completeURL(parseURL(getAttribute(HTMLNames::hrefAttr))); + KURL url = document()->completeURL(deprecatedParseURL(getAttribute(HTMLNames::hrefAttr))); document()->frame()->loader()->urlSelected(url, target(), event, false, false, true); } diff --git a/WebCore/wml/WMLAccessElement.cpp b/WebCore/wml/WMLAccessElement.cpp index db0ab67..a633260 100644 --- a/WebCore/wml/WMLAccessElement.cpp +++ b/WebCore/wml/WMLAccessElement.cpp @@ -43,16 +43,14 @@ void WMLAccessElement::parseMappedAttribute(MappedAttribute* attr) String value = parseValueForbiddingVariableReferences(attr->value()); if (value.isEmpty()) return; - - if (WMLPageState* pageState = wmlPageStateForDocument(document())) - pageState->restrictDeckAccessToDomain(value); + + m_domain = value; } else if (attr->name() == pathAttr) { String value = parseValueForbiddingVariableReferences(attr->value()); if (value.isEmpty()) return; - if (WMLPageState* pageState = wmlPageStateForDocument(document())) - pageState->restrictDeckAccessToPath(value); + m_path = value; } else WMLElement::parseMappedAttribute(attr); } @@ -62,8 +60,11 @@ void WMLAccessElement::insertedIntoDocument() WMLElement::insertedIntoDocument(); WMLPageState* pageState = wmlPageStateForDocument(document()); - if (pageState && !pageState->setNeedCheckDeckAccess(true)) - reportWMLError(document(), WMLErrorMultipleAccessElements); + if (!pageState || pageState->processAccessControlData(m_domain, m_path)) + return; + + pageState->resetAccessControlData(); + reportWMLError(document(), WMLErrorMultipleAccessElements); } } diff --git a/WebCore/wml/WMLAccessElement.h b/WebCore/wml/WMLAccessElement.h index 023d113..1bc44ab 100644 --- a/WebCore/wml/WMLAccessElement.h +++ b/WebCore/wml/WMLAccessElement.h @@ -32,6 +32,10 @@ public: virtual void parseMappedAttribute(MappedAttribute*); virtual void insertedIntoDocument(); + +private: + String m_domain; + String m_path; }; } diff --git a/WebCore/wml/WMLAnchorElement.cpp b/WebCore/wml/WMLAnchorElement.cpp index 300cbf6..91526b9 100644 --- a/WebCore/wml/WMLAnchorElement.cpp +++ b/WebCore/wml/WMLAnchorElement.cpp @@ -32,6 +32,7 @@ namespace WebCore { WMLAnchorElement::WMLAnchorElement(const QualifiedName& tagName, Document* doc) : WMLAElement(tagName, doc) + , m_task(0) { // Calling setIsLink(true), and returning a non-null value on CSSStyleSelectors' linkAttribute // method, makes it possible to 'appear as link' (just like <a href="..">) without the need to @@ -62,6 +63,18 @@ void WMLAnchorElement::defaultEventHandler(Event* event) WMLElement::defaultEventHandler(event); } +void WMLAnchorElement::registerTask(WMLTaskElement* task) +{ + ASSERT(!m_task); + m_task = task; +} + +void WMLAnchorElement::deregisterTask(WMLTaskElement* task) +{ + ASSERT(m_task == task); + m_task = 0; +} + } #endif diff --git a/WebCore/wml/WMLAnchorElement.h b/WebCore/wml/WMLAnchorElement.h index f4afee4..abc01c9 100644 --- a/WebCore/wml/WMLAnchorElement.h +++ b/WebCore/wml/WMLAnchorElement.h @@ -37,7 +37,8 @@ public: private: friend class WMLTaskElement; - void registerTask(WMLTaskElement* task) { m_task = task; } + void registerTask(WMLTaskElement*); + void deregisterTask(WMLTaskElement*); WMLTaskElement* m_task; }; diff --git a/WebCore/wml/WMLCardElement.cpp b/WebCore/wml/WMLCardElement.cpp index c8e92af..63240f3 100644 --- a/WebCore/wml/WMLCardElement.cpp +++ b/WebCore/wml/WMLCardElement.cpp @@ -28,12 +28,14 @@ #include "HTMLNames.h" #include "MappedAttribute.h" #include "NodeList.h" +#include "Page.h" #include "RenderStyle.h" #include "WMLDocument.h" #include "WMLDoElement.h" #include "WMLInputElement.h" #include "WMLIntrinsicEventHandler.h" #include "WMLNames.h" +#include "WMLSelectElement.h" #include "WMLTemplateElement.h" #include "WMLTimerElement.h" #include "WMLVariables.h" @@ -130,20 +132,24 @@ void WMLCardElement::handleIntrinsicEventIfNeeded() FrameLoader* loader = frame->loader(); if (!loader) return; - - int currentHistoryLength = loader->getHistoryLength(); - int lastHistoryLength = pageState->historyLength(); // Calculate the entry method of current card WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown; - if (lastHistoryLength > currentHistoryLength) + + switch (loader->loadType()) { + case FrameLoadTypeReload: + break; + case FrameLoadTypeBack: eventType = WMLIntrinsicEventOnEnterBackward; - else if (lastHistoryLength < currentHistoryLength) + break; + case FrameLoadTypeBackWMLDeckNotAccessible: + reportWMLError(document(), WMLErrorDeckNotAccessible); + return; + default: eventType = WMLIntrinsicEventOnEnterForward; + break; + } - // Synchronize history length with WMLPageState - pageState->setHistoryLength(currentHistoryLength); - // Figure out target event handler WMLIntrinsicEventHandler* eventHandler = this->eventHandler(); bool hasIntrinsicEvent = false; @@ -165,17 +171,14 @@ void WMLCardElement::handleIntrinsicEventIfNeeded() if (m_eventTimer) m_eventTimer->start(); - // FIXME: Initialize select elements in this card for (Node* node = traverseNextNode(); node != 0; node = node->traverseNextNode()) { if (!node->isElementNode()) continue; if (node->hasTagName(inputTag)) static_cast<WMLInputElement*>(node)->initialize(); - /* else if (node->hasTagName(selectTag)) static_cast<WMLSelectElement*>(node)->selectInitialOptions(); - */ } } @@ -238,13 +241,25 @@ void WMLCardElement::parseMappedAttribute(MappedAttribute* attr) void WMLCardElement::insertedIntoDocument() { WMLElement::insertedIntoDocument(); + Document* document = this->document(); // The first card inserted into a document, is visible by default. if (!m_isVisible) { - RefPtr<NodeList> nodeList = document()->getElementsByTagName("card"); + RefPtr<NodeList> nodeList = document->getElementsByTagName("card"); if (nodeList && nodeList->length() == 1 && nodeList->item(0) == this) m_isVisible = true; } + + // For the WML layout tests we embed WML content in a XHTML document. Navigating to different cards + // within the same deck has a different behaviour in HTML than in WML. HTML wants to "scroll to anchor" + // (see FrameLoader) but WML wants a reload. Notify the root document of the layout test that we want + // to mimic WML behaviour. This is rather tricky, but has been tested extensively. Usually it's not possible + // at all to embed WML in HTML, it's not designed that way, we're just "abusing" it for dynamically created layout tests. + if (document->page() && document->page()->mainFrame()) { + Document* rootDocument = document->page()->mainFrame()->document(); + if (rootDocument && rootDocument != document) + rootDocument->setContainsWMLContent(true); + } } RenderObject* WMLCardElement::createRenderer(RenderArena* arena, RenderStyle* style) @@ -296,7 +311,7 @@ WMLCardElement* WMLCardElement::determineActiveCard(Document* doc) return 0; // Figure out the new target card - String cardName = doc->url().ref(); + String cardName = doc->url().fragmentIdentifier(); WMLCardElement* activeCard = findNamedCardInDocument(doc, cardName); if (activeCard) { diff --git a/WebCore/wml/WMLDoElement.cpp b/WebCore/wml/WMLDoElement.cpp index 916bc6e..34be6df 100644 --- a/WebCore/wml/WMLDoElement.cpp +++ b/WebCore/wml/WMLDoElement.cpp @@ -98,8 +98,6 @@ void WMLDoElement::parseMappedAttribute(MappedAttribute* attr) m_type = parseValueForbiddingVariableReferences(attr->value()); else if (attr->name() == HTMLNames::nameAttr) m_name = parseValueForbiddingVariableReferences(attr->value()); - else if (attr->name() == HTMLNames::labelAttr) - m_label = parseValueSubstitutingVariableReferences(attr->value()); else if (attr->name() == optionalAttr) m_isOptional = (attr->value() == "true"); else @@ -115,8 +113,6 @@ void WMLDoElement::insertedIntoDocument() m_name = m_type; Node* parent = parentNode(); - ASSERT(parent); - if (!parent || !parent->isWMLElement()) return; @@ -124,6 +120,29 @@ void WMLDoElement::insertedIntoDocument() eventHandlingElement->registerDoElement(this, document()); } +void WMLDoElement::removedFromDocument() +{ + Node* parent = parentNode(); + + if (parent && parent->isWMLElement()) { + if (WMLEventHandlingElement* eventHandlingElement = toWMLEventHandlingElement(static_cast<WMLElement*>(parent))) + eventHandlingElement->deregisterDoElement(this); + } + + WMLElement::removedFromDocument(); +} + +void WMLDoElement::attach() +{ + WMLElement::attach(); + + // The call to updateFromElement() needs to go after the call through + // to the base class's attach() because that can sometimes do a close + // on the renderer. + if (renderer()) + renderer()->updateFromElement(); +} + RenderObject* WMLDoElement::createRenderer(RenderArena* arena, RenderStyle* style) { if (!m_isActive || m_isOptional || m_isNoop) @@ -145,6 +164,23 @@ void WMLDoElement::recalcStyle(StyleChange change) renderer()->updateFromElement(); } +void WMLDoElement::registerTask(WMLTaskElement* task) +{ + ASSERT(!m_task); + m_task = task; +} + +void WMLDoElement::deregisterTask(WMLTaskElement* task) +{ + ASSERT(m_task == task); + m_task = 0; +} + +String WMLDoElement::label() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::labelAttr)); +} + } #endif diff --git a/WebCore/wml/WMLDoElement.h b/WebCore/wml/WMLDoElement.h index 98e97cc..fe48eae 100644 --- a/WebCore/wml/WMLDoElement.h +++ b/WebCore/wml/WMLDoElement.h @@ -35,14 +35,17 @@ public: virtual void defaultEventHandler(Event*); virtual void parseMappedAttribute(MappedAttribute*); virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + virtual void attach(); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual void recalcStyle(StyleChange); - void registerTask(WMLTaskElement* task) { m_task = task; } + void registerTask(WMLTaskElement*); + void deregisterTask(WMLTaskElement*); bool isActive() const { return m_isActive; } - String label() const { return m_label; } + String label() const; String name() const { return m_name; } void setActive(bool active) { m_isActive = active; } @@ -53,7 +56,6 @@ private: bool m_isActive; bool m_isNoop; bool m_isOptional; - String m_label; String m_name; String m_type; }; diff --git a/WebCore/wml/WMLDocument.cpp b/WebCore/wml/WMLDocument.cpp index 7f73848..f2287be 100644 --- a/WebCore/wml/WMLDocument.cpp +++ b/WebCore/wml/WMLDocument.cpp @@ -23,6 +23,7 @@ #if ENABLE(WML) #include "WMLDocument.h" +#include "Frame.h" #include "Page.h" #include "Tokenizer.h" #include "WMLCardElement.h" @@ -34,6 +35,7 @@ namespace WebCore { WMLDocument::WMLDocument(Frame* frame) : Document(frame, false) + , m_activeCard(0) { clearXMLVersion(); } @@ -51,38 +53,65 @@ void WMLDocument::finishedParsing() } } - WMLPageState* wmlPageState = wmlPageStateForDocument(this); - if (!wmlPageState->isDeckAccessible()) { - reportWMLError(this, WMLErrorDeckNotAccessible); - Document::finishedParsing(); + bool hasAccess = initialize(true); + Document::finishedParsing(); + + if (!hasAccess) { + m_activeCard = 0; + + WMLPageState* wmlPageState = wmlPageStateForDocument(this); + if (!wmlPageState) + return; + + Page* page = wmlPageState->page(); + if (!page) + return; + + BackForwardList* list = page->backForwardList(); + if (!list) + return; + + HistoryItem* item = list->backItem(); + if (!item) + return; + + page->goToItem(item, FrameLoadTypeBackWMLDeckNotAccessible); return; } - // Remember that we'e successfully entered the deck - wmlPageState->setNeedCheckDeckAccess(false); - - initialize(); - Document::finishedParsing(); + if (m_activeCard) { + m_activeCard->handleIntrinsicEventIfNeeded(); + m_activeCard = 0; + } } -void WMLDocument::initialize() +bool WMLDocument::initialize(bool aboutToFinishParsing) { + WMLPageState* wmlPageState = wmlPageStateForDocument(this); + if (!wmlPageState || !wmlPageState->canAccessDeck()) + return false; + + // Remember that we'e successfully entered the deck + wmlPageState->resetAccessControlData(); + // Notify the existance of templates to all cards of the current deck WMLTemplateElement::registerTemplatesInDocument(this); // Set destination card - WMLCardElement* card = WMLCardElement::determineActiveCard(this); - if (!card) { + m_activeCard = WMLCardElement::determineActiveCard(this); + if (!m_activeCard) { reportWMLError(this, WMLErrorNoCardInDocument); - Document::finishedParsing(); - return; + return true; } // Handle deck-level task overrides - card->handleDeckLevelTaskOverridesIfNeeded(); + m_activeCard->handleDeckLevelTaskOverridesIfNeeded(); // Handle card-level intrinsic event - card->handleIntrinsicEventIfNeeded(); + if (!aboutToFinishParsing) + m_activeCard->handleIntrinsicEventIfNeeded(); + + return true; } WMLPageState* wmlPageStateForDocument(Document* doc) diff --git a/WebCore/wml/WMLDocument.h b/WebCore/wml/WMLDocument.h index 9189085..fb3e62e 100644 --- a/WebCore/wml/WMLDocument.h +++ b/WebCore/wml/WMLDocument.h @@ -28,6 +28,8 @@ namespace WebCore { +class WMLCardElement; + class WMLDocument : public Document { public: static PassRefPtr<WMLDocument> create(Frame* frame) @@ -40,10 +42,11 @@ public: virtual bool isWMLDocument() const { return true; } virtual void finishedParsing(); - void initialize(); + bool initialize(bool aboutToFinishParsing = false); private: WMLDocument(Frame*); + WMLCardElement* m_activeCard; }; WMLPageState* wmlPageStateForDocument(Document*); diff --git a/WebCore/wml/WMLElement.cpp b/WebCore/wml/WMLElement.cpp index e818f9d..a9e4b5d 100644 --- a/WebCore/wml/WMLElement.cpp +++ b/WebCore/wml/WMLElement.cpp @@ -77,6 +77,11 @@ void WMLElement::parseMappedAttribute(MappedAttribute* attr) } } +String WMLElement::title() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::titleAttr)); +} + bool WMLElement::rendererIsNeeded(RenderStyle* style) { return document()->documentElement() == this || style->display() != NONE; @@ -87,7 +92,7 @@ RenderObject* WMLElement::createRenderer(RenderArena*, RenderStyle* style) return RenderObject::createObject(this, style); } -String WMLElement::parseValueSubstitutingVariableReferences(const AtomicString& value, WMLErrorCode defaultErrorCode) +String WMLElement::parseValueSubstitutingVariableReferences(const AtomicString& value, WMLErrorCode defaultErrorCode) const { bool isValid = false; if (!containsVariableReference(value, isValid)) @@ -101,7 +106,7 @@ String WMLElement::parseValueSubstitutingVariableReferences(const AtomicString& return substituteVariableReferences(value, document()); } -String WMLElement::parseValueForbiddingVariableReferences(const AtomicString& value) +String WMLElement::parseValueForbiddingVariableReferences(const AtomicString& value) const { bool isValid = false; if (containsVariableReference(value, isValid)) { diff --git a/WebCore/wml/WMLElement.h b/WebCore/wml/WMLElement.h index 61bd98f..46b0ff4 100644 --- a/WebCore/wml/WMLElement.h +++ b/WebCore/wml/WMLElement.h @@ -37,13 +37,15 @@ public: virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; virtual void parseMappedAttribute(MappedAttribute*); + virtual String title() const; + virtual bool rendererIsNeeded(RenderStyle*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); protected: // Helper function for derived classes - String parseValueSubstitutingVariableReferences(const AtomicString&, WMLErrorCode defaultErrorCode = WMLErrorInvalidVariableReference); - String parseValueForbiddingVariableReferences(const AtomicString&); + String parseValueSubstitutingVariableReferences(const AtomicString&, WMLErrorCode defaultErrorCode = WMLErrorInvalidVariableReference) const; + String parseValueForbiddingVariableReferences(const AtomicString&) const; }; } diff --git a/WebCore/wml/WMLErrorHandling.cpp b/WebCore/wml/WMLErrorHandling.cpp index a228299..d62ccb7 100644 --- a/WebCore/wml/WMLErrorHandling.cpp +++ b/WebCore/wml/WMLErrorHandling.cpp @@ -38,7 +38,8 @@ void reportWMLError(Document* doc, WMLErrorCode error) return; String errorMessage = errorMessageForErrorCode(error); - if (XMLTokenizer* tokenizer = static_cast<XMLTokenizer*>(doc->tokenizer())) { + XMLTokenizer* tokenizer = static_cast<XMLTokenizer*>(doc->tokenizer()); + if (tokenizer && error != WMLErrorDeckNotAccessible) { // Some errors are reported as result of an insertedIntoDocument() call. // If this happened, parsing has been stopped, and the document fragment // is wrapped in a XHTML error document. That means insertedIntoDocument() @@ -61,7 +62,7 @@ void reportWMLError(Document* doc, WMLErrorCode error) if (!console) return; - console->addMessage(WMLMessageSource, ErrorMessageLevel, errorMessage, 0, String()); + console->addMessage(WMLMessageSource, LogMessageType, ErrorMessageLevel, errorMessage, 0, String()); } } diff --git a/WebCore/wml/WMLEventHandlingElement.cpp b/WebCore/wml/WMLEventHandlingElement.cpp index 2848985..faa80c7 100644 --- a/WebCore/wml/WMLEventHandlingElement.cpp +++ b/WebCore/wml/WMLEventHandlingElement.cpp @@ -61,10 +61,22 @@ void WMLEventHandlingElement::registerDoElement(WMLDoElement* doElement, Documen } } + ASSERT(m_doElements.find(doElement) == WTF::notFound); m_doElements.append(doElement); doElement->setActive(true); } +void WMLEventHandlingElement::deregisterDoElement(WMLDoElement* doElement) +{ + doElement->setActive(false); + + size_t position = m_doElements.find(doElement); + if (position == WTF::notFound) + return; + + m_doElements.remove(position); +} + WMLEventHandlingElement* toWMLEventHandlingElement(WMLElement* element) { if (!element->isWMLElement()) diff --git a/WebCore/wml/WMLEventHandlingElement.h b/WebCore/wml/WMLEventHandlingElement.h index 92ae289..15cef7b 100644 --- a/WebCore/wml/WMLEventHandlingElement.h +++ b/WebCore/wml/WMLEventHandlingElement.h @@ -42,6 +42,7 @@ public: Vector<WMLDoElement*>& doElements() { return m_doElements; } void registerDoElement(WMLDoElement*, Document*); + void deregisterDoElement(WMLDoElement*); private: OwnPtr<WMLIntrinsicEventHandler> m_eventHandler; diff --git a/WebCore/wml/WMLFieldSetElement.cpp b/WebCore/wml/WMLFieldSetElement.cpp index 8146375..3930de2 100644 --- a/WebCore/wml/WMLFieldSetElement.cpp +++ b/WebCore/wml/WMLFieldSetElement.cpp @@ -43,19 +43,12 @@ WMLFieldSetElement::~WMLFieldSetElement() { } -void WMLFieldSetElement::parseMappedAttribute(MappedAttribute* attr) -{ - if (attr->name() == HTMLNames::titleAttr) - m_title = parseValueSubstitutingVariableReferences(attr->value()); - else - WMLElement::parseMappedAttribute(attr); -} - void WMLFieldSetElement::insertedIntoDocument() { WMLElement::insertedIntoDocument(); - if (m_title.isEmpty()) + String title = parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::titleAttr)); + if (title.isEmpty()) return; m_insertedLegendElement = WMLElementFactory::createWMLElement(insertedLegendTag, document()); @@ -67,14 +60,14 @@ void WMLFieldSetElement::insertedIntoDocument() ASSERT(ec == 0); // Create text node holding the 'title' attribute value - m_insertedLegendElement->appendChild(document()->createTextNode(m_title), ec); + m_insertedLegendElement->appendChild(document()->createTextNode(title), ec); ASSERT(ec == 0); } void WMLFieldSetElement::removedFromDocument() { - WMLElement::removedFromDocument(); m_insertedLegendElement.clear(); + WMLElement::removedFromDocument(); } RenderObject* WMLFieldSetElement::createRenderer(RenderArena* arena, RenderStyle*) diff --git a/WebCore/wml/WMLFieldSetElement.h b/WebCore/wml/WMLFieldSetElement.h index 2043364..1087fa1 100644 --- a/WebCore/wml/WMLFieldSetElement.h +++ b/WebCore/wml/WMLFieldSetElement.h @@ -31,14 +31,12 @@ public: WMLFieldSetElement(const QualifiedName& tagName, Document*); virtual ~WMLFieldSetElement(); - virtual void parseMappedAttribute(MappedAttribute*); virtual void insertedIntoDocument(); virtual void removedFromDocument(); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); private: - String m_title; RefPtr<WMLElement> m_insertedLegendElement; }; diff --git a/WebCore/wml/WMLGoElement.cpp b/WebCore/wml/WMLGoElement.cpp index 7293e66..635302f 100644 --- a/WebCore/wml/WMLGoElement.cpp +++ b/WebCore/wml/WMLGoElement.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -50,8 +50,16 @@ WMLGoElement::WMLGoElement(const QualifiedName& tagName, Document* doc) void WMLGoElement::registerPostfieldElement(WMLPostfieldElement* postfield) { + ASSERT(m_postfieldElements.find(postfield) == WTF::notFound); m_postfieldElements.append(postfield); } + +void WMLGoElement::deregisterPostfieldElement(WMLPostfieldElement* postfield) +{ + size_t position = m_postfieldElements.find(postfield); + ASSERT(position != WTF::notFound); + m_postfieldElements.remove(position); +} void WMLGoElement::parseMappedAttribute(MappedAttribute* attr) { @@ -101,11 +109,8 @@ void WMLGoElement::executeTask(Event*) // FIXME: 'newcontext' handling not implemented for external cards bool inSameDeck = doc->url().path() == url.path(); - if (inSameDeck && url.hasRef()) { - // Force frame loader to load the URL with fragment identifier - loader->setForceReloadWmlDeck(true); - - if (WMLCardElement* card = WMLCardElement::findNamedCardInDocument(doc, url.ref())) { + if (inSameDeck && url.hasFragmentIdentifier()) { + if (WMLCardElement* card = WMLCardElement::findNamedCardInDocument(doc, url.fragmentIdentifier())) { if (card->isNewContext()) pageState->reset(); } diff --git a/WebCore/wml/WMLGoElement.h b/WebCore/wml/WMLGoElement.h index 3c70289..75c1858 100644 --- a/WebCore/wml/WMLGoElement.h +++ b/WebCore/wml/WMLGoElement.h @@ -36,6 +36,7 @@ public: WMLGoElement(const QualifiedName& tagName, Document*); void registerPostfieldElement(WMLPostfieldElement*); + void deregisterPostfieldElement(WMLPostfieldElement*); virtual void parseMappedAttribute(MappedAttribute*); virtual void executeTask(Event*); diff --git a/WebCore/wml/WMLImageLoader.cpp b/WebCore/wml/WMLImageLoader.cpp index c77b511..3c40215 100644 --- a/WebCore/wml/WMLImageLoader.cpp +++ b/WebCore/wml/WMLImageLoader.cpp @@ -49,7 +49,7 @@ void WMLImageLoader::dispatchLoadEvent() String WMLImageLoader::sourceURI(const AtomicString& attr) const { - return parseURL(KURL(element()->baseURI(), attr).string()); + return deprecatedParseURL(KURL(element()->baseURI(), attr).string()); } void WMLImageLoader::notifyFinished(CachedResource* image) diff --git a/WebCore/wml/WMLInputElement.cpp b/WebCore/wml/WMLInputElement.cpp index cb824d1..d6fa79a 100644 --- a/WebCore/wml/WMLInputElement.cpp +++ b/WebCore/wml/WMLInputElement.cpp @@ -298,7 +298,7 @@ void WMLInputElement::defaultEventHandler(Event* evt) InputElement::handleBeforeTextInsertedEvent(m_data, this, document(), evt); if (renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent)) - static_cast<RenderTextControlSingleLine*>(renderer())->forwardEvent(evt); + toRenderTextControlSingleLine(renderer())->forwardEvent(evt); } void WMLInputElement::cacheSelection(int start, int end) diff --git a/WebCore/wml/WMLIntrinsicEventHandler.cpp b/WebCore/wml/WMLIntrinsicEventHandler.cpp index 46cdb8c..67364d9 100644 --- a/WebCore/wml/WMLIntrinsicEventHandler.cpp +++ b/WebCore/wml/WMLIntrinsicEventHandler.cpp @@ -38,6 +38,12 @@ bool WMLIntrinsicEventHandler::registerIntrinsicEvent(WMLIntrinsicEventType type return true; } +void WMLIntrinsicEventHandler::deregisterIntrinsicEvent(WMLIntrinsicEventType type) +{ + if (m_events.contains(type)) + m_events.remove(type); +} + void WMLIntrinsicEventHandler::triggerIntrinsicEvent(WMLIntrinsicEventType type) const { RefPtr<WMLIntrinsicEvent> event = m_events.get(type); diff --git a/WebCore/wml/WMLIntrinsicEventHandler.h b/WebCore/wml/WMLIntrinsicEventHandler.h index b24bb54..8ac6d1b 100644 --- a/WebCore/wml/WMLIntrinsicEventHandler.h +++ b/WebCore/wml/WMLIntrinsicEventHandler.h @@ -44,6 +44,7 @@ public: WMLIntrinsicEventHandler(); bool registerIntrinsicEvent(WMLIntrinsicEventType, PassRefPtr<WMLIntrinsicEvent>); + void deregisterIntrinsicEvent(WMLIntrinsicEventType); void triggerIntrinsicEvent(WMLIntrinsicEventType) const; bool hasIntrinsicEvent(WMLIntrinsicEventType) const; diff --git a/WebCore/wml/WMLNoopElement.cpp b/WebCore/wml/WMLNoopElement.cpp index 1ba1c18..b2ce506 100644 --- a/WebCore/wml/WMLNoopElement.cpp +++ b/WebCore/wml/WMLNoopElement.cpp @@ -45,15 +45,18 @@ void WMLNoopElement::insertedIntoDocument() WMLElement::insertedIntoDocument(); Node* parent = parentNode(); - ASSERT(parent); - if (!parent || !parent->isWMLElement()) return; if (parent->hasTagName(doTag)) { WMLDoElement* doElement = static_cast<WMLDoElement*>(parent); doElement->setNoop(true); - doElement->setNeedsStyleRecalc(); + + if (doElement->attached()) + doElement->detach(); + + ASSERT(!doElement->attached()); + doElement->attach(); } else if (parent->hasTagName(anchorTag)) reportWMLError(document(), WMLErrorForbiddenTaskInAnchorElement); } diff --git a/WebCore/wml/WMLOnEventElement.cpp b/WebCore/wml/WMLOnEventElement.cpp index a8d35a0..6fc4e8b 100644 --- a/WebCore/wml/WMLOnEventElement.cpp +++ b/WebCore/wml/WMLOnEventElement.cpp @@ -60,19 +60,21 @@ void WMLOnEventElement::parseMappedAttribute(MappedAttribute* attr) WMLElement::parseMappedAttribute(attr); } +static inline WMLEventHandlingElement* eventHandlingParent(Node* parent) +{ + if (!parent || !parent->isWMLElement()) + return 0; + + return toWMLEventHandlingElement(static_cast<WMLElement*>(parent)); +} + void WMLOnEventElement::registerTask(WMLTaskElement* task) { if (m_type == WMLIntrinsicEventUnknown) return; // Register intrinsic event to the event handler of the owner of onevent element - Node* parent = parentNode(); - ASSERT(parent); - - if (!parent || !parent->isWMLElement()) - return; - - WMLEventHandlingElement* eventHandlingElement = toWMLEventHandlingElement(static_cast<WMLElement*>(parent)); + WMLEventHandlingElement* eventHandlingElement = eventHandlingParent(parentNode()); if (!eventHandlingElement) return; @@ -83,6 +85,15 @@ void WMLOnEventElement::registerTask(WMLTaskElement* task) reportWMLError(document(), WMLErrorConflictingEventBinding); } +void WMLOnEventElement::deregisterTask(WMLTaskElement*) +{ + WMLEventHandlingElement* eventHandlingElement = eventHandlingParent(parentNode()); + if (!eventHandlingElement) + return; + + eventHandlingElement->eventHandler()->deregisterIntrinsicEvent(m_type); +} + } #endif diff --git a/WebCore/wml/WMLOnEventElement.h b/WebCore/wml/WMLOnEventElement.h index bb004fe..de33600 100644 --- a/WebCore/wml/WMLOnEventElement.h +++ b/WebCore/wml/WMLOnEventElement.h @@ -36,6 +36,7 @@ public: virtual void parseMappedAttribute(MappedAttribute*); void registerTask(WMLTaskElement*); + void deregisterTask(WMLTaskElement*); private: WMLIntrinsicEventType m_type; diff --git a/WebCore/wml/WMLOptGroupElement.cpp b/WebCore/wml/WMLOptGroupElement.cpp index d70731c..9a7ea88 100644 --- a/WebCore/wml/WMLOptGroupElement.cpp +++ b/WebCore/wml/WMLOptGroupElement.cpp @@ -120,11 +120,6 @@ void WMLOptGroupElement::childrenChanged(bool changedByParser, Node* beforeChang void WMLOptGroupElement::parseMappedAttribute(MappedAttribute* attr) { - if (attr->name() == HTMLNames::titleAttr) { - m_title = parseValueSubstitutingVariableReferences(attr->value()); - return; - } - WMLFormControlElement::parseMappedAttribute(attr); recalcSelectOptions(); } @@ -154,7 +149,7 @@ RenderStyle* WMLOptGroupElement::nonRendererRenderStyle() const String WMLOptGroupElement::groupLabelText() const { - String itemText = document()->displayStringModifiedByEncoding(m_title); + String itemText = document()->displayStringModifiedByEncoding(title()); // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior. itemText = itemText.stripWhiteSpace(); diff --git a/WebCore/wml/WMLOptGroupElement.h b/WebCore/wml/WMLOptGroupElement.h index 1ba5ac1..e1b9217 100644 --- a/WebCore/wml/WMLOptGroupElement.h +++ b/WebCore/wml/WMLOptGroupElement.h @@ -32,8 +32,6 @@ public: WMLOptGroupElement(const QualifiedName& tagName, Document*); virtual ~WMLOptGroupElement(); - String title() const { return m_title; } - virtual const AtomicString& formControlType() const; virtual bool rendererIsNeeded(RenderStyle*) { return false; } @@ -59,7 +57,6 @@ private: void recalcSelectOptions(); private: - String m_title; RefPtr<RenderStyle> m_style; }; diff --git a/WebCore/wml/WMLOptionElement.cpp b/WebCore/wml/WMLOptionElement.cpp index 1087134..764d3a1 100644 --- a/WebCore/wml/WMLOptionElement.cpp +++ b/WebCore/wml/WMLOptionElement.cpp @@ -125,7 +125,15 @@ bool WMLOptionElement::selected() const void WMLOptionElement::setSelectedState(bool selected) { + if (this->selected() == selected) + return; + OptionElement::setSelectedState(m_data, this, selected); + + if (WMLSelectElement* select = ownerSelectElement(this)) { + if (select->multiple() || selected) + handleIntrinsicEventIfNeeded(); + } } String WMLOptionElement::value() const @@ -135,7 +143,7 @@ String WMLOptionElement::value() const String WMLOptionElement::text() const { - return OptionElement::collectOptionText(m_data, this); + return OptionElement::collectOptionLabelOrText(m_data, this); } String WMLOptionElement::textIndentedToRespectGroupLabel() const diff --git a/WebCore/wml/WMLPageState.cpp b/WebCore/wml/WMLPageState.cpp index 15ae9ca..5f431bb 100644 --- a/WebCore/wml/WMLPageState.cpp +++ b/WebCore/wml/WMLPageState.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) - * + * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * Copyright (C) 2004-2007 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -25,6 +24,9 @@ #if ENABLE(WML) #include "WMLPageState.h" +#include "CString.h" +#include "Document.h" +#include "Frame.h" #include "HistoryItem.h" #include "KURL.h" #include "Page.h" @@ -33,9 +35,8 @@ namespace WebCore { WMLPageState::WMLPageState(Page* page) : m_page(page) - , m_historyLength(0) , m_activeCard(0) - , m_hasDeckAccess(false) + , m_hasAccessControlData(false) { } @@ -44,87 +45,223 @@ WMLPageState::~WMLPageState() m_variables.clear(); } +#ifndef NDEBUG +// Debugging helper for use within gdb +void WMLPageState::dump() +{ + WMLVariableMap::iterator it = m_variables.begin(); + WMLVariableMap::iterator end = m_variables.end(); + + fprintf(stderr, "Dumping WMLPageState (this=%p) associated with Page (page=%p)...\n", this, m_page); + for (; it != end; ++it) + fprintf(stderr, "\t-> name: '%s'\tvalue: '%s'\n", (*it).first.latin1().data(), (*it).second.latin1().data()); +} +#endif + void WMLPageState::reset() { - // remove all the variables in the current browser context + // Remove all the variables m_variables.clear(); - // clear the navigation history state - if (m_page) - m_page->backForwardList()->clearWmlPageHistory(); + // Clear the navigation history state + if (BackForwardList* list = m_page ? m_page->backForwardList() : 0) + list->clearWMLPageHistory(); +} + +static inline String normalizedHostName(const String& passedHost) +{ + if (passedHost.contains("127.0.0.1")) { + String host = passedHost; + return host.replace("127.0.0.1", "localhost"); + } + + return passedHost; +} + +static inline String hostFromURL(const KURL& url) +{ + // Default to "localhost" + String host = normalizedHostName(url.host()); + return host.isEmpty() ? "localhost" : host; +} + +static KURL urlForHistoryItem(Frame* frame, HistoryItem* item) +{ + // For LayoutTests we need to find the corresponding WML frame in the test document + // to be able to test access-control correctly. Remember that WML is never supposed + // to be embedded anywhere, so the purpose is to simulate a standalone WML document. + if (frame->document()->isWMLDocument()) + return item->url(); + + const HistoryItemVector& childItems = item->children(); + HistoryItemVector::const_iterator it = childItems.begin(); + const HistoryItemVector::const_iterator end = childItems.end(); + + for (; it != end; ++it) { + const RefPtr<HistoryItem> childItem = *it; + Frame* childFrame = frame->tree()->child(childItem->target()); + if (!childFrame) + continue; + + if (Document* childDocument = childFrame->document()) { + if (childDocument->isWMLDocument()) + return childItem->url(); + } + } - // reset implementation-specfic state if UA has - m_historyLength = 1; + return item->url(); } -bool WMLPageState::setNeedCheckDeckAccess(bool need) +static bool tryAccessHistoryURLs(Page* page, KURL& previousURL, KURL& currentURL) { - if (m_hasDeckAccess && need) + if (!page) return false; - m_hasDeckAccess = need; - m_accessPath = String(); - m_accessDomain = String(); + Frame* frame = page->mainFrame(); + if (!frame || !frame->document()) + return false; + + BackForwardList* list = page->backForwardList(); + if (!list) + return false; + + HistoryItem* previousItem = list->backItem(); + if (!previousItem) + return false; + + HistoryItem* currentItem = list->currentItem(); + if (!currentItem) + return false; + + previousURL = urlForHistoryItem(frame, previousItem); + currentURL = urlForHistoryItem(frame, currentItem); + return true; } -// FIXME: We may want another name, it does far more than just checking wheter the deck is accessable -bool WMLPageState::isDeckAccessible() +bool WMLPageState::processAccessControlData(const String& domain, const String& path) { - if (!m_hasDeckAccess || !m_page || !m_page->backForwardList() || !m_page->backForwardList()->backItem()) + if (m_hasAccessControlData) + return false; + + m_hasAccessControlData = true; + + KURL previousURL, currentURL; + if (!tryAccessHistoryURLs(m_page, previousURL, currentURL)) return true; - HistoryItem* histItem = m_page->backForwardList()->backItem(); - KURL url(histItem->urlString()); + // Spec: The path attribute defaults to the value "/" + m_accessPath = path.isEmpty() ? "/" : path; - String prevHost = url.host(); - String prevPath = url.path(); + // Spec: The domain attribute defaults to the current decks domain. + String previousHost = hostFromURL(previousURL); + m_accessDomain = domain.isEmpty() ? previousHost : normalizedHostName(domain); - // for 'file' URI, the host part may be empty, so we should complete it. - if (prevHost.isEmpty()) - prevHost = "localhost"; + // Spec: To simplify the development of applications that may not know the absolute path to the + // current deck, the path attribute accepts relative URIs. The user agent converts the relative + // path to an absolute path and then performs prefix matching against the PATH attribute. + Document* document = m_page->mainFrame() ? m_page->mainFrame()->document() : 0; + if (document && previousHost == m_accessDomain && !m_accessPath.startsWith("/")) { + String currentPath = currentURL.path(); - histItem = m_page->backForwardList()->currentItem(); - KURL curUrl(histItem->urlString()); - String curPath = curUrl.path(); + size_t index = currentPath.reverseFind('/'); + if (index != WTF::notFound) + m_accessPath = document->completeURL(currentPath.left(index + 1) + m_accessPath).path(); + } - if (equalIgnoringRef(url, curUrl)) + return true; +} + +void WMLPageState::resetAccessControlData() +{ + m_hasAccessControlData = false; + m_accessDomain = String(); + m_accessPath = String(); +} + +bool WMLPageState::canAccessDeck() const +{ + if (!m_hasAccessControlData) + return true; + + KURL previousURL, currentURL; + if (!tryAccessHistoryURLs(m_page, previousURL, currentURL)) + return true; + + if (equalIgnoringFragmentIdentifier(previousURL, currentURL)) return true; - // "/" is the default value if not specified - if (m_accessPath.isEmpty()) - m_accessPath = "/"; - else if (m_accessPath.endsWith("/") && (m_accessPath != "/")) - m_accessPath = m_accessPath.left((m_accessPath.length()-1)); - - - // current deck domain is the default value if not specified - if (m_accessDomain.isEmpty()) - m_accessDomain = prevHost; - - // convert relative URL to absolute URL before performing path matching - if (prevHost == m_accessDomain) { - if (!m_accessPath.startsWith("/")) { - int index = curPath.reverseFind('/'); - if (index != -1) { - curPath = curPath.left(index + 1); - curPath += m_accessPath; - curUrl.setPath(curPath); - m_accessPath = curUrl.path(); - } + return hostIsAllowedToAccess(hostFromURL(previousURL)) && pathIsAllowedToAccess(previousURL.path()); +} + +bool WMLPageState::hostIsAllowedToAccess(const String& host) const +{ + // Spec: The access domain is suffix-matched against the domain name portion of the referring URI + Vector<String> subdomainsAllowed; + if (m_accessDomain.contains('.')) + m_accessDomain.split('.', subdomainsAllowed); + else + subdomainsAllowed.append(m_accessDomain); + + Vector<String> subdomainsCheck; + if (host.contains('.')) + host.split('.', subdomainsCheck); + else + subdomainsCheck.append(host); + + Vector<String>::iterator itAllowed = subdomainsAllowed.end() - 1; + Vector<String>::iterator beginAllowed = subdomainsAllowed.begin(); + + Vector<String>::iterator itCheck = subdomainsCheck.end() - 1; + Vector<String>::iterator beginCheck = subdomainsCheck.begin(); + + bool hostOk = true; + for (; itAllowed >= beginAllowed && itCheck >= beginCheck; ) { + if (*itAllowed != *itCheck) { + hostOk = false; + break; } + + --itAllowed; + --itCheck; } - // path prefix matching - if (prevPath.startsWith(m_accessPath) && - (prevPath[m_accessPath.length()] == '/' || prevPath.length() == m_accessPath.length())) { - // domain suffix matching - unsigned domainLength = m_accessDomain.length(); - unsigned hostLength = prevHost.length(); - return (prevHost.endsWith(m_accessDomain) && prevHost[hostLength - domainLength - 1] == '.') || hostLength == domainLength; + return hostOk; +} + +bool WMLPageState::pathIsAllowedToAccess(const String& path) const +{ + // Spec: The access path is prefix matched against the path portion of the referring URI + Vector<String> subpathsAllowed; + if (m_accessPath.contains('/')) + m_accessPath.split('/', subpathsAllowed); + else + subpathsAllowed.append(m_accessPath); + + Vector<String> subpathsCheck; + if (path.contains('/')) + path.split('/', subpathsCheck); + else + subpathsCheck.append(path); + + Vector<String>::iterator itAllowed = subpathsAllowed.begin(); + Vector<String>::iterator endAllowed = subpathsAllowed.end(); + + Vector<String>::iterator itCheck = subpathsCheck.begin(); + Vector<String>::iterator endCheck = subpathsCheck.end(); + + bool pathOk = true; + for (; itAllowed != endAllowed && itCheck != endCheck; ) { + if (*itAllowed != *itCheck) { + pathOk = false; + break; + } + + ++itAllowed; + ++itCheck; } - return false; + return pathOk; } } diff --git a/WebCore/wml/WMLPageState.h b/WebCore/wml/WMLPageState.h index 6a1d960..de0af91 100644 --- a/WebCore/wml/WMLPageState.h +++ b/WebCore/wml/WMLPageState.h @@ -39,40 +39,41 @@ public: WMLPageState(Page*); virtual ~WMLPageState(); - // reset the browser context when 'newcontext' attribute - // of card element is performed as part of go task +#ifndef NDEBUG + void dump(); +#endif + + // Reset the browser context void reset(); - // variables operations + // Variable handling void storeVariable(const String& name, const String& value) { m_variables.set(name, value); } void storeVariables(WMLVariableMap& variables) { m_variables = variables; } String getVariable(const String& name) const { return m_variables.get(name); } bool hasVariables() const { return !m_variables.isEmpty(); } - int historyLength() const { return m_historyLength; } - void setHistoryLength(int length) { m_historyLength = length; } - Page* page() const { return m_page; } WMLCardElement* activeCard() const { return m_activeCard; } void setActiveCard(WMLCardElement* card) { m_activeCard = card; } - // deck access control - void restrictDeckAccessToDomain(const String& domain) { m_accessDomain = domain; } - void restrictDeckAccessToPath(const String& path) { m_accessPath = path; } - bool hasDeckAccess() const { return m_hasDeckAccess; } - - bool setNeedCheckDeckAccess(bool); - bool isDeckAccessible(); + // Deck access control + bool processAccessControlData(const String& dmain, const String& path); + void resetAccessControlData(); + + bool canAccessDeck() const; + +private: + bool hostIsAllowedToAccess(const String&) const; + bool pathIsAllowedToAccess(const String&) const; private: Page* m_page; WMLVariableMap m_variables; - int m_historyLength; WMLCardElement* m_activeCard; String m_accessDomain; String m_accessPath; - bool m_hasDeckAccess; + bool m_hasAccessControlData; }; } diff --git a/WebCore/wml/WMLPostfieldElement.cpp b/WebCore/wml/WMLPostfieldElement.cpp index 69f61f5..21f4c5b 100644 --- a/WebCore/wml/WMLPostfieldElement.cpp +++ b/WebCore/wml/WMLPostfieldElement.cpp @@ -26,7 +26,6 @@ #include "CString.h" #include "TextEncoding.h" #include "HTMLNames.h" -#include "MappedAttribute.h" #include "WMLDocument.h" #include "WMLGoElement.h" #include "WMLNames.h" @@ -40,27 +39,32 @@ WMLPostfieldElement::WMLPostfieldElement(const QualifiedName& tagName, Document* { } -void WMLPostfieldElement::parseMappedAttribute(MappedAttribute* attr) -{ - if (attr->name() == HTMLNames::nameAttr) - m_name = parseValueSubstitutingVariableReferences(attr->value()); - else if (attr->name() == HTMLNames::valueAttr) - m_value = parseValueSubstitutingVariableReferences(attr->value()); - else - WMLElement::parseMappedAttribute(attr); -} - void WMLPostfieldElement::insertedIntoDocument() { WMLElement::insertedIntoDocument(); Node* parent = parentNode(); - ASSERT(parent); + if (parent && parent->hasTagName(goTag)) + static_cast<WMLGoElement*>(parent)->registerPostfieldElement(this); +} + +void WMLPostfieldElement::removedFromDocument() +{ + Node* parent = parentNode(); + if (parent && parent->hasTagName(goTag)) + static_cast<WMLGoElement*>(parent)->deregisterPostfieldElement(this); + + WMLElement::removedFromDocument(); +} - if (!parent->hasTagName(goTag)) - return; +String WMLPostfieldElement::name() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::nameAttr)); +} - static_cast<WMLGoElement*>(parent)->registerPostfieldElement(this); +String WMLPostfieldElement::value() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr)); } static inline CString encodedString(const TextEncoding& encoding, const String& data) @@ -70,8 +74,8 @@ static inline CString encodedString(const TextEncoding& encoding, const String& void WMLPostfieldElement::encodeData(const TextEncoding& encoding, CString& name, CString& value) { - name = encodedString(encoding, m_name); - value = encodedString(encoding, m_value); + name = encodedString(encoding, this->name()); + value = encodedString(encoding, this->value()); } } diff --git a/WebCore/wml/WMLPostfieldElement.h b/WebCore/wml/WMLPostfieldElement.h index 59b7f64..dd10b47 100644 --- a/WebCore/wml/WMLPostfieldElement.h +++ b/WebCore/wml/WMLPostfieldElement.h @@ -30,18 +30,14 @@ class WMLPostfieldElement : public WMLElement { public: WMLPostfieldElement(const QualifiedName& tagName, Document*); - virtual void parseMappedAttribute(MappedAttribute*); virtual void insertedIntoDocument(); + virtual void removedFromDocument(); - String name() const { return m_name; } - String value() const { return m_value; } + String name() const; + String value() const; // Encode name() and value() in a CString using the passed encoding void encodeData(const TextEncoding&, CString& name, CString& value); - -private: - String m_name; - String m_value; }; } diff --git a/WebCore/wml/WMLSelectElement.cpp b/WebCore/wml/WMLSelectElement.cpp index 5b5aed1..2d03a3f 100644 --- a/WebCore/wml/WMLSelectElement.cpp +++ b/WebCore/wml/WMLSelectElement.cpp @@ -22,16 +22,21 @@ #if ENABLE(WML) #include "WMLSelectElement.h" - +#include "CString.h" #include "HTMLNames.h" #include "MappedAttribute.h" +#include "OptionElement.h" #include "RenderListBox.h" #include "RenderMenuList.h" - +#include "WMLDocument.h" +#include "WMLNames.h" +#include "WMLVariables.h" #include <wtf/StdLibExtras.h> namespace WebCore { +using namespace WMLNames; + WMLSelectElement::WMLSelectElement(const QualifiedName& tagName, Document* document) : WMLFormControlElement(tagName, document) { @@ -41,6 +46,12 @@ WMLSelectElement::~WMLSelectElement() { } +const AtomicString& WMLSelectElement::formControlName() const +{ + AtomicString name = this->name(); + return name.isNull() ? emptyAtom : name; +} + const AtomicString& WMLSelectElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple")); @@ -92,9 +103,14 @@ int WMLSelectElement::selectedIndex() const return SelectElement::selectedIndex(m_data, this); } -void WMLSelectElement::setSelectedIndex(int index, bool deselect, bool fireOnChange) +void WMLSelectElement::setSelectedIndex(int optionIndex, bool deselect) { - SelectElement::setSelectedIndex(m_data, this, index, deselect, fireOnChange); + SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, false, false); +} + +void WMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, bool fireOnChangeNow) +{ + SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, fireOnChangeNow, true); } bool WMLSelectElement::saveFormControlState(String& value) const @@ -151,6 +167,14 @@ void WMLSelectElement::reset() void WMLSelectElement::defaultEventHandler(Event* event) { SelectElement::defaultEventHandler(m_data, this, event); + + // FIXME: There must be a better place to update the page variable state. Investigate. + updateVariables(); + + if (event->defaultHandled()) + return; + + WMLFormControlElement::defaultEventHandler(event); } void WMLSelectElement::accessKeyAction(bool sendToAnyElement) @@ -213,12 +237,311 @@ void WMLSelectElement::scrollToSelection() SelectElement::scrollToSelection(m_data, this); } +void WMLSelectElement::selectInitialOptions() +{ + // Spec: Step 1 - the default option index is determined using iname and ivalue + calculateDefaultOptionIndices(); + + if (m_defaultOptionIndices.isEmpty()) + return; + + // Spec: Step 2 – initialise variables + initializeVariables(); + + // Spec: Step 3 – pre-select option(s) specified by the default option index + selectDefaultOptions(); +} + void WMLSelectElement::insertedIntoTree(bool deep) { SelectElement::insertedIntoTree(m_data, this); WMLFormControlElement::insertedIntoTree(deep); } +void WMLSelectElement::calculateDefaultOptionIndices() +{ + WMLPageState* pageState = wmlPageStateForDocument(document()); + if (!pageState) + return; + + String variable; + + // Spec: If the 'iname' attribute is specified and names a variable that is set, + // then the default option index is the validated value of that variable. + String iname = this->iname(); + if (!iname.isEmpty()) { + variable = pageState->getVariable(iname); + if (!variable.isEmpty()) + m_defaultOptionIndices = parseIndexValueString(variable); + } + + // Spec: If the default option index is empty and the 'ivalue' attribute is specified, + // then the default option index is the validated attribute value. + String ivalue = this->ivalue(); + if (m_defaultOptionIndices.isEmpty() && !ivalue.isEmpty()) + m_defaultOptionIndices = parseIndexValueString(ivalue); + + // Spec: If the default option index is empty, and the 'name' attribute is specified + // and the 'name' ttribute names a variable that is set, then for each value in the 'name' + // variable that is present as a value in the select's option elements, the index of the + // first option element containing that value is added to the default index if that + // index has not been previously added. + String name = this->name(); + if (m_defaultOptionIndices.isEmpty() && !name.isEmpty()) { + variable = pageState->getVariable(name); + if (!variable.isEmpty()) + m_defaultOptionIndices = valueStringToOptionIndices(variable); + } + + String value = parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr)); + + // Spec: If the default option index is empty and the 'value' attribute is specified then + // for each value in the 'value' attribute that is present as a value in the select's + // option elements, the index of the first option element containing that value is added + // to the default index if that index has not been previously added. + if (m_defaultOptionIndices.isEmpty() && !value.isEmpty()) + m_defaultOptionIndices = valueStringToOptionIndices(value); + + // Spec: If the default option index is empty and the select is a multi-choice, then the + // default option index is set to zero. If the select is single-choice, then the default + // option index is set to one. + if (m_defaultOptionIndices.isEmpty()) + m_defaultOptionIndices.append((unsigned) !m_data.multiple()); +} + +void WMLSelectElement::selectDefaultOptions() +{ + ASSERT(!m_defaultOptionIndices.isEmpty()); + + if (!m_data.multiple()) { + setSelectedIndex(m_defaultOptionIndices.first() - 1, false); + return; + } + + Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end(); + for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it) + setSelectedIndex((*it) - 1, false); +} + +void WMLSelectElement::initializeVariables() +{ + ASSERT(!m_defaultOptionIndices.isEmpty()); + + WMLPageState* pageState = wmlPageStateForDocument(document()); + if (!pageState) + return; + + const Vector<Element*>& items = m_data.listItems(this); + if (items.isEmpty()) + return; + + // Spec: If the 'iname' attribute is specified, then the named variable is set with the default option index. + String iname = this->iname(); + if (!iname.isEmpty()) + pageState->storeVariable(iname, optionIndicesToString()); + + String name = this->name(); + if (name.isEmpty()) + return; + + if (m_data.multiple()) { + // Spec: If the 'name' attribute is specified and the select is a multiple-choice element, + // then for each index greater than zero, the value of the 'value' attribute on the option + // element at the index is added to the name variable. + pageState->storeVariable(name, optionIndicesToValueString()); + return; + } + + // Spec: If the 'name' attribute is specified and the select is a single-choice element, + // then the named variable is set with the value of the 'value' attribute on the option + // element at the default option index. + unsigned optionIndex = m_defaultOptionIndices.first(); + ASSERT(optionIndex >= 1); + + int listIndex = optionToListIndex(optionIndex - 1); + ASSERT(listIndex >= 0); + ASSERT(listIndex < (int) items.size()); + + if (OptionElement* optionElement = toOptionElement(items[listIndex])) + pageState->storeVariable(name, optionElement->value()); +} + +void WMLSelectElement::updateVariables() +{ + WMLPageState* pageState = wmlPageStateForDocument(document()); + if (!pageState) + return; + + String name = this->name(); + String iname = this->iname(); + if (iname.isEmpty() && name.isEmpty()) + return; + + String nameString; + String inameString; + + unsigned optionIndex = 0; + const Vector<Element*>& items = m_data.listItems(this); + + for (unsigned i = 0; i < items.size(); ++i) { + OptionElement* optionElement = toOptionElement(items[i]); + if (!optionElement) + continue; + + ++optionIndex; + if (!optionElement->selected()) + continue; + + if (!nameString.isEmpty()) + nameString += ";"; + + if (!inameString.isEmpty()) + inameString += ";"; + + nameString += optionElement->value(); + inameString += String::number(optionIndex); + } + + if (!name.isEmpty()) + pageState->storeVariable(name, nameString); + + if (!iname.isEmpty()) + pageState->storeVariable(iname, inameString); +} + +Vector<unsigned> WMLSelectElement::parseIndexValueString(const String& indexValue) const +{ + Vector<unsigned> indices; + if (indexValue.isEmpty()) + return indices; + + Vector<String> indexStrings; + indexValue.split(';', indexStrings); + + bool ok = false; + unsigned optionCount = SelectElement::optionCount(m_data, this); + + Vector<String>::const_iterator end = indexStrings.end(); + for (Vector<String>::const_iterator it = indexStrings.begin(); it != end; ++it) { + unsigned parsedValue = (*it).toUIntStrict(&ok); + // Spec: Remove all non-integer indices from the value. Remove all out-of-range indices + // from the value, where out-of-range is defined as any index with a value greater than + // the number of options in the select or with a value less than one. + if (!ok || parsedValue < 1 || parsedValue > optionCount) + continue; + + // Spec: Remove duplicate indices. + if (indices.find(parsedValue) == notFound) + indices.append(parsedValue); + } + + return indices; +} + +Vector<unsigned> WMLSelectElement::valueStringToOptionIndices(const String& value) const +{ + Vector<unsigned> indices; + if (value.isEmpty()) + return indices; + + const Vector<Element*>& items = m_data.listItems(this); + if (items.isEmpty()) + return indices; + + Vector<String> indexStrings; + value.split(';', indexStrings); + + unsigned optionIndex = 0; + + Vector<String>::const_iterator end = indexStrings.end(); + for (Vector<String>::const_iterator it = indexStrings.begin(); it != end; ++it) { + String value = *it; + + for (unsigned i = 0; i < items.size(); ++i) { + if (!isOptionElement(items[i])) + continue; + + ++optionIndex; + if (OptionElement* optionElement = toOptionElement(items[i])) { + if (optionElement->value() == value) { + indices.append(optionIndex); + break; + } + } + } + } + + return indices; +} + +String WMLSelectElement::optionIndicesToValueString() const +{ + String valueString; + if (m_defaultOptionIndices.isEmpty()) + return valueString; + + const Vector<Element*>& items = m_data.listItems(this); + if (items.isEmpty()) + return valueString; + + Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end(); + for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it) { + unsigned optionIndex = (*it); + if (optionIndex < 1 || optionIndex > items.size()) + continue; + + int listIndex = optionToListIndex((*it) - 1); + ASSERT(listIndex >= 0); + ASSERT(listIndex < (int) items.size()); + + if (OptionElement* optionElement = toOptionElement(items[listIndex])) { + if (!valueString.isEmpty()) + valueString += ";"; + + valueString += optionElement->value(); + } + } + + return valueString; +} + +String WMLSelectElement::optionIndicesToString() const +{ + String valueString; + if (m_defaultOptionIndices.isEmpty()) + return valueString; + + Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end(); + for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it) { + if (!valueString.isEmpty()) + valueString += ";"; + + valueString += String::number(*it); + } + + return valueString; +} + +String WMLSelectElement::name() const +{ + return parseValueForbiddingVariableReferences(getAttribute(HTMLNames::nameAttr)); +} + +String WMLSelectElement::value() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr)); +} + +String WMLSelectElement::iname() const +{ + return parseValueForbiddingVariableReferences(getAttribute(inameAttr)); +} + +String WMLSelectElement::ivalue() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(ivalueAttr)); +} + } #endif diff --git a/WebCore/wml/WMLSelectElement.h b/WebCore/wml/WMLSelectElement.h index 8d3e0f9..412a950 100644 --- a/WebCore/wml/WMLSelectElement.h +++ b/WebCore/wml/WMLSelectElement.h @@ -32,6 +32,7 @@ public: WMLSelectElement(const QualifiedName&, Document*); virtual ~WMLSelectElement(); + virtual const AtomicString& formControlName() const; virtual const AtomicString& formControlType() const; virtual bool isKeyboardFocusable(KeyboardEvent*) const; @@ -47,7 +48,8 @@ public: virtual bool canStartSelection() const { return false; } virtual int selectedIndex() const; - virtual void setSelectedIndex(int index, bool deselect = true, bool fireOnChange = false); + virtual void setSelectedIndex(int index, bool deselect = true); + virtual void setSelectedIndexByUser(int index, bool deselect = true, bool fireOnChangeNow = false); virtual int size() const { return m_data.size(); } virtual bool multiple() const { return m_data.multiple(); } @@ -81,11 +83,28 @@ public: void accessKeySetSelectedIndex(int); void setRecalcListItems(); void scrollToSelection(); + void selectInitialOptions(); private: virtual void insertedIntoTree(bool); + void calculateDefaultOptionIndices(); + void selectDefaultOptions(); + void initializeVariables(); + void updateVariables(); + + Vector<unsigned> parseIndexValueString(const String&) const; + Vector<unsigned> valueStringToOptionIndices(const String&) const; + String optionIndicesToValueString() const; + String optionIndicesToString() const; + + String name() const; + String value() const; + String iname() const; + String ivalue() const; + SelectElementData m_data; + Vector<unsigned> m_defaultOptionIndices; }; } diff --git a/WebCore/wml/WMLSetvarElement.cpp b/WebCore/wml/WMLSetvarElement.cpp index da9a1f4..5e10ca8 100644 --- a/WebCore/wml/WMLSetvarElement.cpp +++ b/WebCore/wml/WMLSetvarElement.cpp @@ -43,16 +43,11 @@ WMLSetvarElement::~WMLSetvarElement() void WMLSetvarElement::parseMappedAttribute(MappedAttribute* attr) { if (attr->name() == HTMLNames::nameAttr) { - String name = parseValueSubstitutingVariableReferences(attr->value(), WMLErrorInvalidVariableName); - if (!isValidVariableName(name)) { + if (!isValidVariableName(parseValueSubstitutingVariableReferences(attr->value(), WMLErrorInvalidVariableName))) { reportWMLError(document(), WMLErrorInvalidVariableName); return; } - - m_name = name; - } else if (attr->name() == HTMLNames::valueAttr) - m_value = parseValueSubstitutingVariableReferences(attr->value()); - else + } else WMLElement::parseMappedAttribute(attr); } @@ -61,8 +56,6 @@ void WMLSetvarElement::insertedIntoDocument() WMLElement::insertedIntoDocument(); Node* parent = parentNode(); - ASSERT(parent); - if (!parent || !parent->isWMLElement()) return; @@ -70,6 +63,27 @@ void WMLSetvarElement::insertedIntoDocument() static_cast<WMLTaskElement*>(parent)->registerVariableSetter(this); } +void WMLSetvarElement::removedFromDocument() +{ + Node* parent = parentNode(); + if (parent && parent->isWMLElement()) { + if (static_cast<WMLElement*>(parent)->isWMLTaskElement()) + static_cast<WMLTaskElement*>(parent)->deregisterVariableSetter(this); + } + + WMLElement::removedFromDocument(); +} + +String WMLSetvarElement::name() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::nameAttr), WMLErrorInvalidVariableName); +} + +String WMLSetvarElement::value() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr)); +} + } #endif diff --git a/WebCore/wml/WMLSetvarElement.h b/WebCore/wml/WMLSetvarElement.h index ebedbc8..0171b95 100644 --- a/WebCore/wml/WMLSetvarElement.h +++ b/WebCore/wml/WMLSetvarElement.h @@ -33,13 +33,10 @@ public: virtual void parseMappedAttribute(MappedAttribute*); virtual void insertedIntoDocument(); + virtual void removedFromDocument(); - String name() const { return m_name; } - String value() const { return m_value; } - -private: - String m_name; - String m_value; + String name() const; + String value() const; }; } diff --git a/WebCore/wml/WMLTaskElement.cpp b/WebCore/wml/WMLTaskElement.cpp index 1add1da..d49a03e 100644 --- a/WebCore/wml/WMLTaskElement.cpp +++ b/WebCore/wml/WMLTaskElement.cpp @@ -48,8 +48,6 @@ void WMLTaskElement::insertedIntoDocument() WMLElement::insertedIntoDocument(); Node* parent = parentNode(); - ASSERT(parent); - if (!parent || !parent->isWMLElement()) return; @@ -61,10 +59,32 @@ void WMLTaskElement::insertedIntoDocument() static_cast<WMLOnEventElement*>(parent)->registerTask(this); } +void WMLTaskElement::removedFromDocument() +{ + Node* parent = parentNode(); + if (parent && parent->isWMLElement()) { + if (parent->hasTagName(anchorTag)) + static_cast<WMLAnchorElement*>(parent)->deregisterTask(this); + else if (parent->hasTagName(doTag)) + static_cast<WMLDoElement*>(parent)->deregisterTask(this); + else if (parent->hasTagName(oneventTag)) + static_cast<WMLOnEventElement*>(parent)->deregisterTask(this); + } + + WMLElement::removedFromDocument(); +} + void WMLTaskElement::registerVariableSetter(WMLSetvarElement* element) { - ASSERT(element); - m_variableSetterElements.add(element); + ASSERT(m_variableSetterElements.find(element) == WTF::notFound); + m_variableSetterElements.append(element); +} + +void WMLTaskElement::deregisterVariableSetter(WMLSetvarElement* element) +{ + size_t position = m_variableSetterElements.find(element); + ASSERT(position != WTF::notFound); + m_variableSetterElements.remove(position); } void WMLTaskElement::storeVariableState(WMLPageState* pageState) @@ -73,19 +93,23 @@ void WMLTaskElement::storeVariableState(WMLPageState* pageState) return; WMLVariableMap variables; - HashSet<WMLSetvarElement*>::iterator it = m_variableSetterElements.begin(); - HashSet<WMLSetvarElement*>::iterator end = m_variableSetterElements.end(); + Vector<WMLSetvarElement*>::iterator it = m_variableSetterElements.begin(); + Vector<WMLSetvarElement*>::iterator end = m_variableSetterElements.end(); for (; it != end; ++it) { WMLSetvarElement* setterElement = (*it); - if (setterElement->name().isEmpty()) + + String name = setterElement->name(); + if (name.isEmpty()) continue; - variables.set(setterElement->name(), setterElement->value()); - } + String value = setterElement->value(); + variables.set(name, value); - if (variables.isEmpty()) - return; + // The next setvar element may depend on this variable value. It's safe to store the current + // name value pair in the page state, as the whole page state is replaced soon by this new map + pageState->storeVariable(name, value); + } pageState->storeVariables(variables); } diff --git a/WebCore/wml/WMLTaskElement.h b/WebCore/wml/WMLTaskElement.h index f28571a..b5dab8c 100644 --- a/WebCore/wml/WMLTaskElement.h +++ b/WebCore/wml/WMLTaskElement.h @@ -24,7 +24,7 @@ #if ENABLE(WML) #include "WMLElement.h" -#include <wtf/HashSet.h> +#include <wtf/Vector.h> namespace WebCore { @@ -39,15 +39,17 @@ public: virtual bool isWMLTaskElement() const { return true; } virtual void insertedIntoDocument(); + virtual void removedFromDocument(); virtual void executeTask(Event*) = 0; void registerVariableSetter(WMLSetvarElement*); + void deregisterVariableSetter(WMLSetvarElement*); protected: void storeVariableState(WMLPageState*); private: - HashSet<WMLSetvarElement*> m_variableSetterElements; + Vector<WMLSetvarElement*> m_variableSetterElements; }; } diff --git a/WebCore/wml/WMLTimerElement.cpp b/WebCore/wml/WMLTimerElement.cpp index 00c7036..c6476f7 100644 --- a/WebCore/wml/WMLTimerElement.cpp +++ b/WebCore/wml/WMLTimerElement.cpp @@ -46,8 +46,6 @@ void WMLTimerElement::parseMappedAttribute(MappedAttribute* attr) { if (attr->name() == HTMLNames::nameAttr) m_name = parseValueForbiddingVariableReferences(attr->value()); - else if (attr->name() == HTMLNames::valueAttr) - m_value = parseValueSubstitutingVariableReferences(attr->value()); else WMLElement::parseMappedAttribute(attr); } @@ -57,12 +55,10 @@ void WMLTimerElement::insertedIntoDocument() WMLElement::insertedIntoDocument(); // If the value of timeout is not a positive integer, ignore it - if (m_value.toInt() <= 0) + if (value().toInt() <= 0) return; Node* parent = parentNode(); - ASSERT(parent); - if (!parent || !parent->isWMLElement()) return; @@ -72,6 +68,17 @@ void WMLTimerElement::insertedIntoDocument() } } +void WMLTimerElement::removedFromDocument() +{ + Node* parent = parentNode(); + if (parent && parent->isWMLElement() && parent->hasTagName(cardTag)) { + m_card->setIntrinsicEventTimer(0); + m_card = 0; + } + + WMLElement::removedFromDocument(); +} + void WMLTimerElement::timerFired(Timer<WMLTimerElement>*) { if (!m_card) @@ -81,10 +88,12 @@ void WMLTimerElement::timerFired(Timer<WMLTimerElement>*) if (!pageState) return; + String value = this->value(); + // When the timer expires, set the name varialbe of timer to '0' if (!m_name.isEmpty()) { - m_value = "0"; - pageState->storeVariable(m_name, m_value); + value = "0"; + pageState->storeVariable(m_name, value); } WMLIntrinsicEventType eventType = WMLIntrinsicEventOnTimer; @@ -114,7 +123,7 @@ void WMLTimerElement::start(int interval) } if (interval <= 0) - interval = m_value.toInt(); + interval = value().toInt(); if (interval > 0) m_timer.startOneShot(interval / 10.0f); @@ -137,6 +146,11 @@ void WMLTimerElement::storeIntervalToPageState() pageState->storeVariable(m_name, String::number(interval)); } +String WMLTimerElement::value() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr)); +} + } #endif diff --git a/WebCore/wml/WMLTimerElement.h b/WebCore/wml/WMLTimerElement.h index eecacf3..8402027 100644 --- a/WebCore/wml/WMLTimerElement.h +++ b/WebCore/wml/WMLTimerElement.h @@ -35,6 +35,7 @@ public: virtual void parseMappedAttribute(MappedAttribute*); virtual void insertedIntoDocument(); + virtual void removedFromDocument(); void timerFired(Timer<WMLTimerElement>*); @@ -42,10 +43,11 @@ public: void stop(); void storeIntervalToPageState(); + String value() const; + private: WMLCardElement* m_card; String m_name; - String m_value; Timer<WMLTimerElement> m_timer; }; diff --git a/WebCore/wml/WMLVariables.cpp b/WebCore/wml/WMLVariables.cpp index f206234..f48aa1c 100644 --- a/WebCore/wml/WMLVariables.cpp +++ b/WebCore/wml/WMLVariables.cpp @@ -117,8 +117,6 @@ bool containsVariableReference(const String& text, bool& isValid) if (!isValidVariableNameCharacter(text[nameEndPosition])) break; } - - --nameEndPosition; } if (nameEndPosition < nameStartPosition) { @@ -127,7 +125,7 @@ bool containsVariableReference(const String& text, bool& isValid) break; } - // Eventually split of conversion string, and check it's syntax afterwards + // Eventually split of conversion string, and check its syntax afterwards String conversionString; String variableName = text.substring(nameStartPosition, nameEndPosition - nameStartPosition); |