Home | History | Annotate | Download | only in wml
      1 /*
      2  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  *
     19  */
     20 
     21 #include "config.h"
     22 
     23 #if ENABLE(WML)
     24 #include "WMLCardElement.h"
     25 
     26 #include "Attribute.h"
     27 #include "Frame.h"
     28 #include "FrameLoader.h"
     29 #include "HTMLNames.h"
     30 #include "NodeList.h"
     31 #include "Page.h"
     32 #include "RenderStyle.h"
     33 #include "WMLDoElement.h"
     34 #include "WMLDocument.h"
     35 #include "WMLInputElement.h"
     36 #include "WMLIntrinsicEventHandler.h"
     37 #include "WMLNames.h"
     38 #include "WMLSelectElement.h"
     39 #include "WMLTemplateElement.h"
     40 #include "WMLTimerElement.h"
     41 #include "WMLVariables.h"
     42 
     43 namespace WebCore {
     44 
     45 using namespace WMLNames;
     46 
     47 WMLCardElement::WMLCardElement(const QualifiedName& tagName, Document* doc)
     48     : WMLElement(tagName, doc)
     49     , m_isNewContext(false)
     50     , m_isOrdered(false)
     51     , m_isVisible(false)
     52     , m_eventTimer(0)
     53     , m_template(0)
     54 {
     55     ASSERT(hasTagName(cardTag));
     56 }
     57 
     58 PassRefPtr<WMLCardElement> WMLCardElement::create(const QualifiedName& tagName, Document* document)
     59 {
     60     return adoptRef(new WMLCardElement(tagName, document));
     61 }
     62 
     63 WMLCardElement::~WMLCardElement()
     64 {
     65 }
     66 
     67 void WMLCardElement::showCard()
     68 {
     69     ASSERT(attached());
     70 
     71     if (m_isVisible) {
     72         ASSERT(renderer());
     73         return;
     74     }
     75 
     76     m_isVisible = true;
     77     ASSERT(!renderer());
     78 
     79     detach();
     80     attach();
     81 
     82     ASSERT(attached());
     83     ASSERT(renderer());
     84 }
     85 
     86 void WMLCardElement::hideCard()
     87 {
     88     ASSERT(attached());
     89 
     90     if (!m_isVisible) {
     91         ASSERT(!renderer());
     92         return;
     93     }
     94 
     95     m_isVisible = false;
     96     ASSERT(renderer());
     97 
     98     detach();
     99     attach();
    100 
    101     ASSERT(attached());
    102     ASSERT(!renderer());
    103 }
    104 
    105 void WMLCardElement::setTemplateElement(WMLTemplateElement* temp)
    106 {
    107     // Only one template is allowed to be attached to a card
    108     if (m_template) {
    109         reportWMLError(document(), WMLErrorMultipleTemplateElements);
    110         return;
    111     }
    112 
    113     m_template = temp;
    114 }
    115 
    116 void WMLCardElement::setIntrinsicEventTimer(WMLTimerElement* timer)
    117 {
    118     // Only one timer is allowed in a card
    119     if (m_eventTimer) {
    120         reportWMLError(document(), WMLErrorMultipleTimerElements);
    121         return;
    122     }
    123 
    124     m_eventTimer = timer;
    125 }
    126 
    127 void WMLCardElement::handleIntrinsicEventIfNeeded()
    128 {
    129     WMLPageState* pageState = wmlPageStateForDocument(document());
    130     if (!pageState)
    131         return;
    132 
    133     Frame* frame = document()->frame();
    134     if (!frame)
    135         return;
    136 
    137     FrameLoader* loader = frame->loader();
    138     if (!loader)
    139         return;
    140 
    141     // Calculate the entry method of current card
    142     WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown;
    143 
    144     switch (loader->policyChecker()->loadType()) {
    145     case FrameLoadTypeReload:
    146         break;
    147     case FrameLoadTypeBack:
    148         eventType = WMLIntrinsicEventOnEnterBackward;
    149         break;
    150     case FrameLoadTypeBackWMLDeckNotAccessible:
    151         reportWMLError(document(), WMLErrorDeckNotAccessible);
    152         return;
    153     default:
    154         eventType = WMLIntrinsicEventOnEnterForward;
    155         break;
    156     }
    157 
    158     // Figure out target event handler
    159     WMLIntrinsicEventHandler* eventHandler = this->eventHandler();
    160     bool hasIntrinsicEvent = false;
    161 
    162     if (eventType != WMLIntrinsicEventUnknown) {
    163         if (eventHandler && eventHandler->hasIntrinsicEvent(eventType))
    164             hasIntrinsicEvent = true;
    165         else if (m_template) {
    166             eventHandler = m_template->eventHandler();
    167             if (eventHandler && eventHandler->hasIntrinsicEvent(eventType))
    168                 hasIntrinsicEvent = true;
    169         }
    170     }
    171 
    172     if (hasIntrinsicEvent)
    173         eventHandler->triggerIntrinsicEvent(eventType);
    174 
    175     // Start the timer if it exists in current card
    176     if (m_eventTimer)
    177         m_eventTimer->start();
    178 
    179     for (Node* node = traverseNextNode(); node != 0; node = node->traverseNextNode()) {
    180         if (!node->isElementNode())
    181             continue;
    182 
    183         if (node->hasTagName(inputTag))
    184             static_cast<WMLInputElement*>(node)->initialize();
    185         else if (node->hasTagName(selectTag))
    186             static_cast<WMLSelectElement*>(node)->selectInitialOptions();
    187     }
    188 }
    189 
    190 void WMLCardElement::handleDeckLevelTaskOverridesIfNeeded()
    191 {
    192     // Spec: The event-handling element may appear inside a template element and specify
    193     // event-processing behaviour for all cards in the deck. A deck-level event-handling
    194     // element is equivalent to specifying the event-handling element in each card.
    195     if (!m_template)
    196         return;
    197 
    198     Vector<WMLDoElement*>& templateDoElements = m_template->doElements();
    199     if (templateDoElements.isEmpty())
    200         return;
    201 
    202     Vector<WMLDoElement*>& cardDoElements = doElements();
    203     Vector<WMLDoElement*>::iterator it = cardDoElements.begin();
    204     Vector<WMLDoElement*>::iterator end = cardDoElements.end();
    205 
    206     HashSet<String> cardDoElementNames;
    207     for (; it != end; ++it)
    208         cardDoElementNames.add((*it)->name());
    209 
    210     it = templateDoElements.begin();
    211     end = templateDoElements.end();
    212 
    213     for (; it != end; ++it)
    214         (*it)->setActive(!cardDoElementNames.contains((*it)->name()));
    215 }
    216 
    217 void WMLCardElement::parseMappedAttribute(Attribute* attr)
    218 {
    219     WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown;
    220 
    221     if (attr->name() == onenterforwardAttr)
    222         eventType = WMLIntrinsicEventOnEnterForward;
    223     else if (attr->name() == onenterbackwardAttr)
    224         eventType = WMLIntrinsicEventOnEnterBackward;
    225     else if (attr->name() == ontimerAttr)
    226         eventType = WMLIntrinsicEventOnTimer;
    227     else if (attr->name() == newcontextAttr)
    228         m_isNewContext = (attr->value() == "true");
    229     else if (attr->name() == orderedAttr)
    230         m_isOrdered = (attr->value() == "true");
    231     else {
    232         WMLElement::parseMappedAttribute(attr);
    233         return;
    234     }
    235 
    236     if (eventType == WMLIntrinsicEventUnknown)
    237         return;
    238 
    239     // Register intrinsic event in card
    240     RefPtr<WMLIntrinsicEvent> event = WMLIntrinsicEvent::create(document(), attr->value());
    241 
    242     createEventHandlerIfNeeded();
    243     eventHandler()->registerIntrinsicEvent(eventType, event);
    244 }
    245 
    246 void WMLCardElement::insertedIntoDocument()
    247 {
    248     WMLElement::insertedIntoDocument();
    249     Document* document = this->document();
    250 
    251     // The first card inserted into a document, is visible by default.
    252     if (!m_isVisible) {
    253         RefPtr<NodeList> nodeList = document->getElementsByTagName("card");
    254         if (nodeList && nodeList->length() == 1 && nodeList->item(0) == this)
    255             m_isVisible = true;
    256     }
    257 
    258     // For the WML layout tests we embed WML content in a XHTML document. Navigating to different cards
    259     // within the same deck has a different behaviour in HTML than in WML. HTML wants to "scroll to anchor"
    260     // (see FrameLoader) but WML wants a reload. Notify the root document of the layout test that we want
    261     // to mimic WML behaviour. This is rather tricky, but has been tested extensively. Usually it's not possible
    262     // at all to embed WML in HTML, it's not designed that way, we're just "abusing" it for dynamically created layout tests.
    263     if (document->page() && document->page()->mainFrame()) {
    264         Document* rootDocument = document->page()->mainFrame()->document();
    265         if (rootDocument && rootDocument != document)
    266             rootDocument->setContainsWMLContent(true);
    267     }
    268 }
    269 
    270 RenderObject* WMLCardElement::createRenderer(RenderArena* arena, RenderStyle* style)
    271 {
    272     if (!m_isVisible) {
    273         style->setUnique();
    274         style->setDisplay(NONE);
    275     }
    276 
    277     return WMLElement::createRenderer(arena, style);
    278 }
    279 
    280 WMLCardElement* WMLCardElement::findNamedCardInDocument(Document* doc, const String& cardName)
    281 {
    282     if (cardName.isEmpty())
    283         return 0;
    284 
    285     RefPtr<NodeList> nodeList = doc->getElementsByTagName("card");
    286     if (!nodeList)
    287         return 0;
    288 
    289     unsigned length = nodeList->length();
    290     if (length < 1)
    291         return 0;
    292 
    293     for (unsigned i = 0; i < length; ++i) {
    294         WMLCardElement* card = static_cast<WMLCardElement*>(nodeList->item(i));
    295         if (card->getIdAttribute() != cardName)
    296             continue;
    297 
    298         return card;
    299     }
    300 
    301     return 0;
    302 }
    303 
    304 WMLCardElement* WMLCardElement::determineActiveCard(Document* doc)
    305 {
    306     WMLPageState* pageState = wmlPageStateForDocument(doc);
    307     if (!pageState)
    308         return 0;
    309 
    310     RefPtr<NodeList> nodeList = doc->getElementsByTagName("card");
    311     if (!nodeList)
    312         return 0;
    313 
    314     unsigned length = nodeList->length();
    315     if (length < 1)
    316         return 0;
    317 
    318     // Figure out the new target card
    319     String cardName = doc->url().fragmentIdentifier();
    320 
    321     WMLCardElement* activeCard = findNamedCardInDocument(doc, cardName);
    322     if (activeCard) {
    323         // Hide all cards - except the destination card - in document
    324         for (unsigned i = 0; i < length; ++i) {
    325             WMLCardElement* card = static_cast<WMLCardElement*>(nodeList->item(i));
    326 
    327             if (card == activeCard)
    328                 card->showCard();
    329             else
    330                 card->hideCard();
    331         }
    332     } else {
    333         // If the target URL didn't contain a fragment identifier, activeCard
    334         // is 0, and has to be set to the first card element in the deck.
    335         activeCard = static_cast<WMLCardElement*>(nodeList->item(0));
    336         activeCard->showCard();
    337     }
    338 
    339     // Assure destination card is visible
    340     ASSERT(activeCard->isVisible());
    341     ASSERT(activeCard->attached());
    342     ASSERT(activeCard->renderer());
    343 
    344     // Update the document title
    345     doc->setTitle(activeCard->title());
    346 
    347     return activeCard;
    348 }
    349 
    350 }
    351 
    352 #endif
    353