diff -r 000000000000 -r 4f2f89ce4247 WebCore/wml/WMLCardElement.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/wml/WMLCardElement.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,347 @@ +/* + * 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 + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(WML) +#include "WMLCardElement.h" + +#include "Attribute.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "HTMLNames.h" +#include "NodeList.h" +#include "Page.h" +#include "RenderStyle.h" +#include "WMLDoElement.h" +#include "WMLDocument.h" +#include "WMLInputElement.h" +#include "WMLIntrinsicEventHandler.h" +#include "WMLNames.h" +#include "WMLSelectElement.h" +#include "WMLTemplateElement.h" +#include "WMLTimerElement.h" +#include "WMLVariables.h" + +namespace WebCore { + +using namespace WMLNames; + +WMLCardElement::WMLCardElement(const QualifiedName& tagName, Document* doc) + : WMLElement(tagName, doc) + , m_isNewContext(false) + , m_isOrdered(false) + , m_isVisible(false) + , m_eventTimer(0) + , m_template(0) +{ + ASSERT(hasTagName(cardTag)); +} + +WMLCardElement::~WMLCardElement() +{ +} + +void WMLCardElement::showCard() +{ + ASSERT(attached()); + + if (m_isVisible) { + ASSERT(renderer()); + return; + } + + m_isVisible = true; + ASSERT(!renderer()); + + detach(); + attach(); + + ASSERT(attached()); + ASSERT(renderer()); +} + +void WMLCardElement::hideCard() +{ + ASSERT(attached()); + + if (!m_isVisible) { + ASSERT(!renderer()); + return; + } + + m_isVisible = false; + ASSERT(renderer()); + + detach(); + attach(); + + ASSERT(attached()); + ASSERT(!renderer()); +} + +void WMLCardElement::setTemplateElement(WMLTemplateElement* temp) +{ + // Only one template is allowed to be attached to a card + if (m_template) { + reportWMLError(document(), WMLErrorMultipleTemplateElements); + return; + } + + m_template = temp; +} + +void WMLCardElement::setIntrinsicEventTimer(WMLTimerElement* timer) +{ + // Only one timer is allowed in a card + if (m_eventTimer) { + reportWMLError(document(), WMLErrorMultipleTimerElements); + return; + } + + m_eventTimer = timer; +} + +void WMLCardElement::handleIntrinsicEventIfNeeded() +{ + WMLPageState* pageState = wmlPageStateForDocument(document()); + if (!pageState) + return; + + Frame* frame = document()->frame(); + if (!frame) + return; + + FrameLoader* loader = frame->loader(); + if (!loader) + return; + + // Calculate the entry method of current card + WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown; + + switch (loader->policyChecker()->loadType()) { + case FrameLoadTypeReload: + break; + case FrameLoadTypeBack: + eventType = WMLIntrinsicEventOnEnterBackward; + break; + case FrameLoadTypeBackWMLDeckNotAccessible: + reportWMLError(document(), WMLErrorDeckNotAccessible); + return; + default: + eventType = WMLIntrinsicEventOnEnterForward; + break; + } + + // Figure out target event handler + WMLIntrinsicEventHandler* eventHandler = this->eventHandler(); + bool hasIntrinsicEvent = false; + + if (eventType != WMLIntrinsicEventUnknown) { + if (eventHandler && eventHandler->hasIntrinsicEvent(eventType)) + hasIntrinsicEvent = true; + else if (m_template) { + eventHandler = m_template->eventHandler(); + if (eventHandler && eventHandler->hasIntrinsicEvent(eventType)) + hasIntrinsicEvent = true; + } + } + + if (hasIntrinsicEvent) + eventHandler->triggerIntrinsicEvent(eventType); + + // Start the timer if it exists in current card + if (m_eventTimer) + m_eventTimer->start(); + + for (Node* node = traverseNextNode(); node != 0; node = node->traverseNextNode()) { + if (!node->isElementNode()) + continue; + + if (node->hasTagName(inputTag)) + static_cast(node)->initialize(); + else if (node->hasTagName(selectTag)) + static_cast(node)->selectInitialOptions(); + } +} + +void WMLCardElement::handleDeckLevelTaskOverridesIfNeeded() +{ + // Spec: The event-handling element may appear inside a template element and specify + // event-processing behaviour for all cards in the deck. A deck-level event-handling + // element is equivalent to specifying the event-handling element in each card. + if (!m_template) + return; + + Vector& templateDoElements = m_template->doElements(); + if (templateDoElements.isEmpty()) + return; + + Vector& cardDoElements = doElements(); + Vector::iterator it = cardDoElements.begin(); + Vector::iterator end = cardDoElements.end(); + + HashSet cardDoElementNames; + for (; it != end; ++it) + cardDoElementNames.add((*it)->name()); + + it = templateDoElements.begin(); + end = templateDoElements.end(); + + for (; it != end; ++it) + (*it)->setActive(!cardDoElementNames.contains((*it)->name())); +} + +void WMLCardElement::parseMappedAttribute(Attribute* attr) +{ + WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown; + + if (attr->name() == onenterforwardAttr) + eventType = WMLIntrinsicEventOnEnterForward; + else if (attr->name() == onenterbackwardAttr) + eventType = WMLIntrinsicEventOnEnterBackward; + else if (attr->name() == ontimerAttr) + eventType = WMLIntrinsicEventOnTimer; + else if (attr->name() == newcontextAttr) + m_isNewContext = (attr->value() == "true"); + else if (attr->name() == orderedAttr) + m_isOrdered = (attr->value() == "true"); + else { + WMLElement::parseMappedAttribute(attr); + return; + } + + if (eventType == WMLIntrinsicEventUnknown) + return; + + // Register intrinsic event in card + RefPtr event = WMLIntrinsicEvent::create(document(), attr->value()); + + createEventHandlerIfNeeded(); + eventHandler()->registerIntrinsicEvent(eventType, event); +} + +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 = 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) +{ + if (!m_isVisible) { + style->setUnique(); + style->setDisplay(NONE); + } + + return WMLElement::createRenderer(arena, style); +} + +WMLCardElement* WMLCardElement::findNamedCardInDocument(Document* doc, const String& cardName) +{ + if (cardName.isEmpty()) + return 0; + + RefPtr nodeList = doc->getElementsByTagName("card"); + if (!nodeList) + return 0; + + unsigned length = nodeList->length(); + if (length < 1) + return 0; + + for (unsigned i = 0; i < length; ++i) { + WMLCardElement* card = static_cast(nodeList->item(i)); + if (card->getIDAttribute() != cardName) + continue; + + return card; + } + + return 0; +} + +WMLCardElement* WMLCardElement::determineActiveCard(Document* doc) +{ + WMLPageState* pageState = wmlPageStateForDocument(doc); + if (!pageState) + return 0; + + RefPtr nodeList = doc->getElementsByTagName("card"); + if (!nodeList) + return 0; + + unsigned length = nodeList->length(); + if (length < 1) + return 0; + + // Figure out the new target card + String cardName = doc->url().fragmentIdentifier(); + + WMLCardElement* activeCard = findNamedCardInDocument(doc, cardName); + if (activeCard) { + // Hide all cards - except the destination card - in document + for (unsigned i = 0; i < length; ++i) { + WMLCardElement* card = static_cast(nodeList->item(i)); + + if (card == activeCard) + card->showCard(); + else + card->hideCard(); + } + } else { + // If the target URL didn't contain a fragment identifier, activeCard + // is 0, and has to be set to the first card element in the deck. + activeCard = static_cast(nodeList->item(0)); + activeCard->showCard(); + } + + // Assure destination card is visible + ASSERT(activeCard->isVisible()); + ASSERT(activeCard->attached()); + ASSERT(activeCard->renderer()); + + // Update the document title + doc->setTitle(activeCard->title()); + + return activeCard; +} + +} + +#endif