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 "Frame.h"
     27 #include "FrameLoader.h"
     28 #include "HTMLNames.h"
     29 #include "MappedAttribute.h"
     30 #include "NodeList.h"
     31 #include "Page.h"
     32 #include "RenderStyle.h"
     33 #include "WMLDocument.h"
     34 #include "WMLDoElement.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 WMLCardElement::~WMLCardElement()
     59 {
     60 }
     61 
     62 void WMLCardElement::showCard()
     63 {
     64     ASSERT(attached());
     65 
     66     if (m_isVisible) {
     67         ASSERT(renderer());
     68         return;
     69     }
     70 
     71     m_isVisible = true;
     72     ASSERT(!renderer());
     73 
     74     detach();
     75     attach();
     76 
     77     ASSERT(attached());
     78     ASSERT(renderer());
     79 }
     80 
     81 void WMLCardElement::hideCard()
     82 {
     83     ASSERT(attached());
     84 
     85     if (!m_isVisible) {
     86         ASSERT(!renderer());
     87         return;
     88     }
     89 
     90     m_isVisible = false;
     91     ASSERT(renderer());
     92 
     93     detach();
     94     attach();
     95 
     96     ASSERT(attached());
     97     ASSERT(!renderer());
     98 }
     99 
    100 void WMLCardElement::setTemplateElement(WMLTemplateElement* temp)
    101 {
    102     // Only one template is allowed to be attached to a card
    103     if (m_template) {
    104         reportWMLError(document(), WMLErrorMultipleTemplateElements);
    105         return;
    106     }
    107 
    108     m_template = temp;
    109 }
    110 
    111 void WMLCardElement::setIntrinsicEventTimer(WMLTimerElement* timer)
    112 {
    113     // Only one timer is allowed in a card
    114     if (m_eventTimer) {
    115         reportWMLError(document(), WMLErrorMultipleTimerElements);
    116         return;
    117     }
    118 
    119     m_eventTimer = timer;
    120 }
    121 
    122 void WMLCardElement::handleIntrinsicEventIfNeeded()
    123 {
    124     WMLPageState* pageState = wmlPageStateForDocument(document());
    125     if (!pageState)
    126         return;
    127 
    128     Frame* frame = document()->frame();
    129     if (!frame)
    130         return;
    131 
    132     FrameLoader* loader = frame->loader();
    133     if (!loader)
    134         return;
    135 
    136     // Calculate the entry method of current card
    137     WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown;
    138 
    139     switch (loader->policyChecker()->loadType()) {
    140     case FrameLoadTypeReload:
    141         break;
    142     case FrameLoadTypeBack:
    143         eventType = WMLIntrinsicEventOnEnterBackward;
    144         break;
    145     case FrameLoadTypeBackWMLDeckNotAccessible:
    146         reportWMLError(document(), WMLErrorDeckNotAccessible);
    147         return;
    148     default:
    149         eventType = WMLIntrinsicEventOnEnterForward;
    150         break;
    151     }
    152 
    153     // Figure out target event handler
    154     WMLIntrinsicEventHandler* eventHandler = this->eventHandler();
    155     bool hasIntrinsicEvent = false;
    156 
    157     if (eventType != WMLIntrinsicEventUnknown) {
    158         if (eventHandler && eventHandler->hasIntrinsicEvent(eventType))
    159             hasIntrinsicEvent = true;
    160         else if (m_template) {
    161             eventHandler = m_template->eventHandler();
    162             if (eventHandler && eventHandler->hasIntrinsicEvent(eventType))
    163                 hasIntrinsicEvent = true;
    164         }
    165     }
    166 
    167     if (hasIntrinsicEvent)
    168         eventHandler->triggerIntrinsicEvent(eventType);
    169 
    170     // Start the timer if it exists in current card
    171     if (m_eventTimer)
    172         m_eventTimer->start();
    173 
    174     for (Node* node = traverseNextNode(); node != 0; node = node->traverseNextNode()) {
    175         if (!node->isElementNode())
    176             continue;
    177 
    178         if (node->hasTagName(inputTag))
    179             static_cast<WMLInputElement*>(node)->initialize();
    180         else if (node->hasTagName(selectTag))
    181             static_cast<WMLSelectElement*>(node)->selectInitialOptions();
    182     }
    183 }
    184 
    185 void WMLCardElement::handleDeckLevelTaskOverridesIfNeeded()
    186 {
    187     // Spec: The event-handling element may appear inside a template element and specify
    188     // event-processing behaviour for all cards in the deck. A deck-level event-handling
    189     // element is equivalent to specifying the event-handling element in each card.
    190     if (!m_template)
    191         return;
    192 
    193     Vector<WMLDoElement*>& templateDoElements = m_template->doElements();
    194     if (templateDoElements.isEmpty())
    195         return;
    196 
    197     Vector<WMLDoElement*>& cardDoElements = doElements();
    198     Vector<WMLDoElement*>::iterator it = cardDoElements.begin();
    199     Vector<WMLDoElement*>::iterator end = cardDoElements.end();
    200 
    201     HashSet<String> cardDoElementNames;
    202     for (; it != end; ++it)
    203         cardDoElementNames.add((*it)->name());
    204 
    205     it = templateDoElements.begin();
    206     end = templateDoElements.end();
    207 
    208     for (; it != end; ++it)
    209         (*it)->setActive(!cardDoElementNames.contains((*it)->name()));
    210 }
    211 
    212 void WMLCardElement::parseMappedAttribute(MappedAttribute* attr)
    213 {
    214     WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown;
    215 
    216     if (attr->name() == onenterforwardAttr)
    217         eventType = WMLIntrinsicEventOnEnterForward;
    218     else if (attr->name() == onenterbackwardAttr)
    219         eventType = WMLIntrinsicEventOnEnterBackward;
    220     else if (attr->name() == ontimerAttr)
    221         eventType = WMLIntrinsicEventOnTimer;
    222     else if (attr->name() == newcontextAttr)
    223         m_isNewContext = (attr->value() == "true");
    224     else if (attr->name() == orderedAttr)
    225         m_isOrdered = (attr->value() == "true");
    226     else {
    227         WMLElement::parseMappedAttribute(attr);
    228         return;
    229     }
    230 
    231     if (eventType == WMLIntrinsicEventUnknown)
    232         return;
    233 
    234     // Register intrinsic event in card
    235     RefPtr<WMLIntrinsicEvent> event = WMLIntrinsicEvent::create(document(), attr->value());
    236 
    237     createEventHandlerIfNeeded();
    238     eventHandler()->registerIntrinsicEvent(eventType, event);
    239 }
    240 
    241 void WMLCardElement::insertedIntoDocument()
    242 {
    243     WMLElement::insertedIntoDocument();
    244     Document* document = this->document();
    245 
    246     // The first card inserted into a document, is visible by default.
    247     if (!m_isVisible) {
    248         RefPtr<NodeList> nodeList = document->getElementsByTagName("card");
    249         if (nodeList && nodeList->length() == 1 && nodeList->item(0) == this)
    250             m_isVisible = true;
    251     }
    252 
    253     // For the WML layout tests we embed WML content in a XHTML document. Navigating to different cards
    254     // within the same deck has a different behaviour in HTML than in WML. HTML wants to "scroll to anchor"
    255     // (see FrameLoader) but WML wants a reload. Notify the root document of the layout test that we want
    256     // to mimic WML behaviour. This is rather tricky, but has been tested extensively. Usually it's not possible
    257     // at all to embed WML in HTML, it's not designed that way, we're just "abusing" it for dynamically created layout tests.
    258     if (document->page() && document->page()->mainFrame()) {
    259         Document* rootDocument = document->page()->mainFrame()->document();
    260         if (rootDocument && rootDocument != document)
    261             rootDocument->setContainsWMLContent(true);
    262     }
    263 }
    264 
    265 RenderObject* WMLCardElement::createRenderer(RenderArena* arena, RenderStyle* style)
    266 {
    267     if (!m_isVisible) {
    268         style->setUnique();
    269         style->setDisplay(NONE);
    270     }
    271 
    272     return WMLElement::createRenderer(arena, style);
    273 }
    274 
    275 WMLCardElement* WMLCardElement::findNamedCardInDocument(Document* doc, const String& cardName)
    276 {
    277     if (cardName.isEmpty())
    278         return 0;
    279 
    280     RefPtr<NodeList> nodeList = doc->getElementsByTagName("card");
    281     if (!nodeList)
    282         return 0;
    283 
    284     unsigned length = nodeList->length();
    285     if (length < 1)
    286         return 0;
    287 
    288     for (unsigned i = 0; i < length; ++i) {
    289         WMLCardElement* card = static_cast<WMLCardElement*>(nodeList->item(i));
    290         if (card->getIDAttribute() != cardName)
    291             continue;
    292 
    293         return card;
    294     }
    295 
    296     return 0;
    297 }
    298 
    299 WMLCardElement* WMLCardElement::determineActiveCard(Document* doc)
    300 {
    301     WMLPageState* pageState = wmlPageStateForDocument(doc);
    302     if (!pageState)
    303         return 0;
    304 
    305     RefPtr<NodeList> nodeList = doc->getElementsByTagName("card");
    306     if (!nodeList)
    307         return 0;
    308 
    309     unsigned length = nodeList->length();
    310     if (length < 1)
    311         return 0;
    312 
    313     // Figure out the new target card
    314     String cardName = doc->url().fragmentIdentifier();
    315 
    316     WMLCardElement* activeCard = findNamedCardInDocument(doc, cardName);
    317     if (activeCard) {
    318         // Hide all cards - except the destination card - in document
    319         for (unsigned i = 0; i < length; ++i) {
    320             WMLCardElement* card = static_cast<WMLCardElement*>(nodeList->item(i));
    321 
    322             if (card == activeCard)
    323                 card->showCard();
    324             else
    325                 card->hideCard();
    326         }
    327     } else {
    328         // If the target URL didn't contain a fragment identifier, activeCard
    329         // is 0, and has to be set to the first card element in the deck.
    330         activeCard = static_cast<WMLCardElement*>(nodeList->item(0));
    331         activeCard->showCard();
    332     }
    333 
    334     // Assure destination card is visible
    335     ASSERT(activeCard->isVisible());
    336     ASSERT(activeCard->attached());
    337     ASSERT(activeCard->renderer());
    338 
    339     // Update the document title
    340     doc->setTitle(activeCard->title());
    341 
    342     return activeCard;
    343 }
    344 
    345 }
    346 
    347 #endif
    348