• 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 "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 
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 
~WMLCardElement()58 WMLCardElement::~WMLCardElement()
59 {
60 }
61 
showCard()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 
hideCard()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 
setTemplateElement(WMLTemplateElement * temp)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 
setIntrinsicEventTimer(WMLTimerElement * timer)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 
handleIntrinsicEventIfNeeded()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 
handleDeckLevelTaskOverridesIfNeeded()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 
parseMappedAttribute(MappedAttribute * attr)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 
insertedIntoDocument()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 
createRenderer(RenderArena * arena,RenderStyle * style)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 
findNamedCardInDocument(Document * doc,const String & cardName)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 
determineActiveCard(Document * doc)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