• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WMLCardElement(const QualifiedName & tagName,Document * doc)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 
create(const QualifiedName & tagName,Document * document)58 PassRefPtr<WMLCardElement> WMLCardElement::create(const QualifiedName& tagName, Document* document)
59 {
60     return adoptRef(new WMLCardElement(tagName, document));
61 }
62 
~WMLCardElement()63 WMLCardElement::~WMLCardElement()
64 {
65 }
66 
showCard()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 
hideCard()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 
setTemplateElement(WMLTemplateElement * temp)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 
setIntrinsicEventTimer(WMLTimerElement * timer)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 
handleIntrinsicEventIfNeeded()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 
handleDeckLevelTaskOverridesIfNeeded()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 
parseMappedAttribute(Attribute * attr)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 
insertedIntoDocument()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 
createRenderer(RenderArena * arena,RenderStyle * style)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 
findNamedCardInDocument(Document * doc,const String & cardName)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 
determineActiveCard(Document * doc)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