1/*
2 * Copyright (C) 2012 Intel Corporation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WorkQueueManager.h"
28
29#include "PlatformWebView.h"
30#include "TestController.h"
31#include <WebKit/WKPage.h>
32#include <WebKit/WKPagePrivate.h>
33#include <WebKit/WKRetainPtr.h>
34#include <stdio.h>
35#include <wtf/text/CString.h>
36
37namespace WTR {
38
39static inline WKPageRef mainPage()
40{
41 return TestController::singleton().mainWebView()->page();
42}
43
44static inline bool goToItemAtIndex(int index)
45{
46 WKBackForwardListRef backForwardList = WKPageGetBackForwardList(mainPage());
47 ASSERT(backForwardList);
48
49 WKBackForwardListItemRef listItem = WKBackForwardListGetItemAtIndex(backForwardList, index);
50 if (!listItem)
51 return false;
52
53 WKPageGoToBackForwardListItem(mainPage(), listItem);
54
55 return true;
56}
57
58class WorkQueueItem {
59public:
60 enum Type {
61 Loading,
62 NonLoading
63 };
64
65 virtual ~WorkQueueItem() { }
66 virtual Type invoke() const = 0;
67};
68
69// Required by WKPageRunJavaScriptInMainFrame().
70static void runJavaScriptFunction(WKSerializedScriptValueRef, WKErrorRef, void*)
71{
72}
73
74template <WorkQueueItem::Type type>
75class ScriptItem : public WorkQueueItem {
76public:
77 explicit ScriptItem(const String& script)
78 : m_script(adoptWK(WKStringCreateWithUTF8CString(script.utf8().data())))
79 {
80 }
81
82 WorkQueueItem::Type invoke() const
83 {
84 WKPageRunJavaScriptInMainFrame(mainPage(), m_script.get(), 0, runJavaScriptFunction);
85 return type;
86 }
87
88 WKRetainPtr<WKStringRef> m_script;
89};
90
91class NavigationItem : public WorkQueueItem {
92public:
93 explicit NavigationItem(int index) : m_index(index) { }
94
95 WorkQueueItem::Type invoke() const
96 {
97 return goToItemAtIndex(m_index) ? WorkQueueItem::Loading : WorkQueueItem::NonLoading;
98 }
99
100 unsigned m_index;
101};
102
103WorkQueueManager::WorkQueueManager()
104 : m_processing(false)
105{
106}
107
108WorkQueueManager::~WorkQueueManager()
109{
110}
111
112void WorkQueueManager::clearWorkQueue()
113{
114 m_processing = false;
115 m_workQueue.clear();
116}
117
118bool WorkQueueManager::processWorkQueue()
119{
120 m_processing = false;
121 while (!m_processing && !m_workQueue.isEmpty()) {
122 std::unique_ptr<WorkQueueItem> item(m_workQueue.takeFirst());
123 m_processing = (item->invoke() == WorkQueueItem::Loading);
124 }
125
126 return !m_processing;
127}
128
129void WorkQueueManager::queueLoad(const String& url, const String& target, bool shouldOpenExternalURLs)
130{
131 class LoadItem : public WorkQueueItem {
132 public:
133 LoadItem(const String& url, const String& target, bool shouldOpenExternalURLs)
134 : m_url(adoptWK(WKURLCreateWithUTF8CString(url.utf8().data())))
135 , m_target(target)
136 , m_shouldOpenExternalURLs(shouldOpenExternalURLs)
137 {
138 }
139
140 WorkQueueItem::Type invoke() const
141 {
142 if (!m_target.isEmpty()) {
143 // FIXME: Use target. Some layout tests cannot pass as they rely on this functionality.
144 fprintf(stderr, "queueLoad for a specific target is not implemented.\n");
145 return WorkQueueItem::NonLoading;
146 }
147 WKPageLoadURLWithShouldOpenExternalURLsPolicy(mainPage(), m_url.get(), m_shouldOpenExternalURLs);
148 return WorkQueueItem::Loading;
149 }
150
151 WKRetainPtr<WKURLRef> m_url;
152 String m_target;
153 bool m_shouldOpenExternalURLs;
154 };
155
156 enqueue(new LoadItem(url, target, shouldOpenExternalURLs));
157}
158
159void WorkQueueManager::queueLoadHTMLString(const String& content, const String& baseURL, const String& unreachableURL)
160{
161 class LoadHTMLStringItem : public WorkQueueItem {
162 public:
163 LoadHTMLStringItem(const String& content, const String& baseURL, const String& unreachableURL)
164 : m_content(adoptWK(WKStringCreateWithUTF8CString(content.utf8().data())))
165 , m_baseURL(adoptWK(WKURLCreateWithUTF8CString(baseURL.utf8().data())))
166 , m_unreachableURL(adoptWK(WKURLCreateWithUTF8CString(unreachableURL.utf8().data())))
167 {
168 }
169
170 WorkQueueItem::Type invoke() const
171 {
172 WKPageLoadAlternateHTMLString(mainPage(), m_content.get(), m_baseURL.get(), m_unreachableURL.get());
173 return WorkQueueItem::Loading;
174 }
175
176 WKRetainPtr<WKStringRef> m_content;
177 WKRetainPtr<WKURLRef> m_baseURL;
178 WKRetainPtr<WKURLRef> m_unreachableURL;
179 };
180
181 enqueue(new LoadHTMLStringItem(content, baseURL, unreachableURL));
182}
183
184void WorkQueueManager::queueBackNavigation(unsigned howFarBackward)
185{
186 enqueue(new NavigationItem(-howFarBackward));
187}
188
189void WorkQueueManager::queueForwardNavigation(unsigned howFarForward)
190{
191 enqueue(new NavigationItem(howFarForward));
192}
193
194void WorkQueueManager::queueReload()
195{
196 class ReloadItem : public WorkQueueItem {
197 public:
198 WorkQueueItem::Type invoke() const
199 {
200 WKPageReload(mainPage());
201 return WorkQueueItem::Loading;
202 }
203 };
204
205 enqueue(new ReloadItem());
206}
207
208void WorkQueueManager::queueLoadingScript(const String& script)
209{
210 enqueue(new ScriptItem<WorkQueueItem::Loading>(script));
211}
212
213void WorkQueueManager::queueNonLoadingScript(const String& script)
214{
215 enqueue(new ScriptItem<WorkQueueItem::NonLoading>(script));
216}
217
218void WorkQueueManager::enqueue(WorkQueueItem* item)
219{
220 ASSERT(item);
221 if (m_processing) {
222 fprintf(stderr, "Attempt to enqueue a work item while queue is being processed.\n");
223 delete item;
224 return;
225 }
226
227 m_workQueue.append(std::unique_ptr<WorkQueueItem>(item));
228}
229
230} // namespace WTR
231