WebCore/wml/WMLCardElement.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 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(Attribute* 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