1 /*
2 * Copyright (C) 2010 Apple Inc. 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 "InjectedBundlePage.h"
28
29 #include "InjectedBundle.h"
30 #include "StringFunctions.h"
31 #include <cmath>
32 #include <JavaScriptCore/JSRetainPtr.h>
33 #include <WebKit2/WKArray.h>
34 #include <WebKit2/WKBundle.h>
35 #include <WebKit2/WKBundleBackForwardList.h>
36 #include <WebKit2/WKBundleBackForwardListItem.h>
37 #include <WebKit2/WKBundleFrame.h>
38 #include <WebKit2/WKBundleFramePrivate.h>
39 #include <WebKit2/WKBundlePagePrivate.h>
40 #include <WebKit2/WKURLRequest.h>
41
42 using namespace std;
43
44 namespace WTR {
45
hasPrefix(const string & searchString,const string & prefix)46 static bool hasPrefix(const string& searchString, const string& prefix)
47 {
48 return searchString.length() >= prefix.length() && searchString.substr(0, prefix.length()) == prefix;
49 }
50
propertyValue(JSContextRef context,JSObjectRef object,const char * propertyName)51 static JSValueRef propertyValue(JSContextRef context, JSObjectRef object, const char* propertyName)
52 {
53 if (!object)
54 return 0;
55 JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName));
56 return JSObjectGetProperty(context, object, propertyNameString.get(), 0);
57 }
58
propertyValueDouble(JSContextRef context,JSObjectRef object,const char * propertyName)59 static double propertyValueDouble(JSContextRef context, JSObjectRef object, const char* propertyName)
60 {
61 JSValueRef value = propertyValue(context, object, propertyName);
62 if (!value)
63 return 0;
64 return JSValueToNumber(context, value, 0);
65 }
66
propertyValueInt(JSContextRef context,JSObjectRef object,const char * propertyName)67 static int propertyValueInt(JSContextRef context, JSObjectRef object, const char* propertyName)
68 {
69 return static_cast<int>(propertyValueDouble(context, object, propertyName));
70 }
71
numericWindowPropertyValue(WKBundleFrameRef frame,const char * propertyName)72 static double numericWindowPropertyValue(WKBundleFrameRef frame, const char* propertyName)
73 {
74 JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
75 return propertyValueDouble(context, JSContextGetGlobalObject(context), propertyName);
76 }
77
dumpPath(JSGlobalContextRef context,JSObjectRef nodeValue)78 static string dumpPath(JSGlobalContextRef context, JSObjectRef nodeValue)
79 {
80 JSValueRef nodeNameValue = propertyValue(context, nodeValue, "nodeName");
81 JSRetainPtr<JSStringRef> jsStringNodeName(Adopt, JSValueToStringCopy(context, nodeNameValue, 0));
82 WKRetainPtr<WKStringRef> nodeName = toWK(jsStringNodeName);
83
84 JSValueRef parentNode = propertyValue(context, nodeValue, "parentNode");
85
86 ostringstream out;
87 out << nodeName;
88
89 if (parentNode && JSValueIsObject(context, parentNode))
90 out << " > " << dumpPath(context, (JSObjectRef)parentNode);
91
92 return out.str();
93 }
94
dumpPath(WKBundlePageRef page,WKBundleScriptWorldRef world,WKBundleNodeHandleRef node)95 static string dumpPath(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleNodeHandleRef node)
96 {
97 if (!node)
98 return "(null)";
99
100 WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
101
102 JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
103 JSValueRef nodeValue = WKBundleFrameGetJavaScriptWrapperForNodeForWorld(frame, node, world);
104 ASSERT(JSValueIsObject(context, nodeValue));
105 JSObjectRef nodeObject = (JSObjectRef)nodeValue;
106
107 return dumpPath(context, nodeObject);
108 }
109
toStr(WKBundlePageRef page,WKBundleScriptWorldRef world,WKBundleRangeHandleRef rangeRef)110 static string toStr(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleRangeHandleRef rangeRef)
111 {
112 if (!rangeRef)
113 return "(null)";
114
115 WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
116
117 JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
118 JSValueRef rangeValue = WKBundleFrameGetJavaScriptWrapperForRangeForWorld(frame, rangeRef, world);
119 ASSERT(JSValueIsObject(context, rangeValue));
120 JSObjectRef rangeObject = (JSObjectRef)rangeValue;
121
122 JSValueRef startNodeValue = propertyValue(context, rangeObject, "startContainer");
123 ASSERT(JSValueIsObject(context, startNodeValue));
124 JSObjectRef startNodeObject = (JSObjectRef)startNodeValue;
125
126 JSValueRef endNodeValue = propertyValue(context, rangeObject, "endContainer");
127 ASSERT(JSValueIsObject(context, endNodeValue));
128 JSObjectRef endNodeObject = (JSObjectRef)endNodeValue;
129
130 int startOffset = propertyValueInt(context, rangeObject, "startOffset");
131 int endOffset = propertyValueInt(context, rangeObject, "endOffset");
132
133 ostringstream out;
134 out << "range from " << startOffset << " of " << dumpPath(context, startNodeObject) << " to " << endOffset << " of " << dumpPath(context, endNodeObject);
135 return out.str();
136 }
137
operator <<(ostream & out,WKBundleCSSStyleDeclarationRef style)138 static ostream& operator<<(ostream& out, WKBundleCSSStyleDeclarationRef style)
139 {
140 // DumpRenderTree calls -[DOMCSSStyleDeclaration description], which just dumps class name and object address.
141 // No existing tests actually hit this code path at the time of this writing, because WebCore doesn't call
142 // the editing client if the styling operation source is CommandFromDOM or CommandFromDOMWithUserInterface.
143 out << "<DOMCSSStyleDeclaration ADDRESS>";
144 return out;
145 }
146
operator <<(ostream & out,WKBundleFrameRef frame)147 static ostream& operator<<(ostream& out, WKBundleFrameRef frame)
148 {
149 WKRetainPtr<WKStringRef> name(AdoptWK, WKBundleFrameCopyName(frame));
150 if (WKBundleFrameIsMainFrame(frame)) {
151 if (!WKStringIsEmpty(name.get()))
152 out << "main frame \"" << name << "\"";
153 else
154 out << "main frame";
155 } else {
156 if (!WKStringIsEmpty(name.get()))
157 out << "frame \"" << name << "\"";
158 else
159 out << "frame (anonymous)";
160 }
161
162 return out;
163 }
164
InjectedBundlePage(WKBundlePageRef page)165 InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
166 : m_page(page)
167 , m_world(AdoptWK, WKBundleScriptWorldCreateWorld())
168 {
169 WKBundlePageLoaderClient loaderClient = {
170 0,
171 this,
172 didStartProvisionalLoadForFrame,
173 didReceiveServerRedirectForProvisionalLoadForFrame,
174 didFailProvisionalLoadWithErrorForFrame,
175 didCommitLoadForFrame,
176 didFinishDocumentLoadForFrame,
177 didFinishLoadForFrame,
178 didFailLoadWithErrorForFrame,
179 didSameDocumentNavigationForFrame,
180 didReceiveTitleForFrame,
181 0,
182 0,
183 0,
184 didDisplayInsecureContentForFrame,
185 didRunInsecureContentForFrame,
186 didClearWindowForFrame,
187 didCancelClientRedirectForFrame,
188 willPerformClientRedirectForFrame,
189 didHandleOnloadEventsForFrame,
190 };
191 WKBundlePageSetPageLoaderClient(m_page, &loaderClient);
192
193 WKBundlePageResourceLoadClient resourceLoadClient = {
194 0,
195 this,
196 didInitiateLoadForResource,
197 willSendRequestForFrame,
198 didReceiveResponseForResource,
199 didReceiveContentLengthForResource,
200 didFinishLoadForResource,
201 didFailLoadForResource
202 };
203 WKBundlePageSetResourceLoadClient(m_page, &resourceLoadClient);
204
205 WKBundlePagePolicyClient policyClient = {
206 0,
207 this,
208 decidePolicyForNavigationAction,
209 decidePolicyForNewWindowAction,
210 decidePolicyForResponse,
211 unableToImplementPolicy
212 };
213 WKBundlePageSetPolicyClient(m_page, &policyClient);
214
215 WKBundlePageUIClient uiClient = {
216 0,
217 this,
218 willAddMessageToConsole,
219 willSetStatusbarText,
220 willRunJavaScriptAlert,
221 willRunJavaScriptConfirm,
222 willRunJavaScriptPrompt,
223 0, /*mouseDidMoveOverElement*/
224 0, /*pageDidScroll*/
225 0, /*paintCustomOverhangArea*/
226 0, /*shouldGenerateFileForUpload*/
227 0, /*generateFileForUpload*/
228 };
229 WKBundlePageSetUIClient(m_page, &uiClient);
230
231 WKBundlePageEditorClient editorClient = {
232 0,
233 this,
234 shouldBeginEditing,
235 shouldEndEditing,
236 shouldInsertNode,
237 shouldInsertText,
238 shouldDeleteRange,
239 shouldChangeSelectedRange,
240 shouldApplyStyle,
241 didBeginEditing,
242 didEndEditing,
243 didChange,
244 didChangeSelection
245 };
246 WKBundlePageSetEditorClient(m_page, &editorClient);
247
248 #if ENABLE(FULLSCREEN_API)
249 WKBundlePageFullScreenClient fullScreenClient = {
250 0,
251 this,
252 supportsFullScreen,
253 enterFullScreenForElement,
254 exitFullScreenForElement,
255 };
256 WKBundlePageSetFullScreenClient(m_page, &fullScreenClient);
257 #endif
258 }
259
~InjectedBundlePage()260 InjectedBundlePage::~InjectedBundlePage()
261 {
262 }
263
stopLoading()264 void InjectedBundlePage::stopLoading()
265 {
266 WKBundlePageStopLoading(m_page);
267 }
268
reset()269 void InjectedBundlePage::reset()
270 {
271 WKBundlePageClearMainFrameName(m_page);
272
273 WKBundlePageSetPageZoomFactor(m_page, 1);
274 WKBundlePageSetTextZoomFactor(m_page, 1);
275
276 WKPoint origin = { 0, 0 };
277 WKBundlePageSetScaleAtOrigin(m_page, 1, origin);
278
279 m_previousTestBackForwardListItem = adoptWK(WKBundleBackForwardListCopyItemAtIndex(WKBundlePageGetBackForwardList(m_page), 0));
280
281 WKBundleFrameClearOpener(WKBundlePageGetMainFrame(m_page));
282 }
283
284 // Loader Client Callbacks
285
didStartProvisionalLoadForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKTypeRef *,const void * clientInfo)286 void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
287 {
288 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didStartProvisionalLoadForFrame(frame);
289 }
290
didReceiveServerRedirectForProvisionalLoadForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKTypeRef *,const void * clientInfo)291 void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
292 {
293 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveServerRedirectForProvisionalLoadForFrame(frame);
294 }
295
didFailProvisionalLoadWithErrorForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKErrorRef error,WKTypeRef *,const void * clientInfo)296 void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef*, const void *clientInfo)
297 {
298 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailProvisionalLoadWithErrorForFrame(frame, error);
299 }
300
didCommitLoadForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKTypeRef *,const void * clientInfo)301 void InjectedBundlePage::didCommitLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
302 {
303 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(frame);
304 }
305
didFinishLoadForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKTypeRef *,const void * clientInfo)306 void InjectedBundlePage::didFinishLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
307 {
308 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(frame);
309 }
310
didFinishDocumentLoadForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKTypeRef *,const void * clientInfo)311 void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
312 {
313 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishDocumentLoadForFrame(frame);
314 }
315
didFailLoadWithErrorForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKErrorRef error,WKTypeRef *,const void * clientInfo)316 void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef*, const void *clientInfo)
317 {
318 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailLoadWithErrorForFrame(frame, error);
319 }
320
didReceiveTitleForFrame(WKBundlePageRef page,WKStringRef title,WKBundleFrameRef frame,WKTypeRef *,const void * clientInfo)321 void InjectedBundlePage::didReceiveTitleForFrame(WKBundlePageRef page, WKStringRef title, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
322 {
323 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveTitleForFrame(title, frame);
324 }
325
didClearWindowForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKBundleScriptWorldRef world,const void * clientInfo)326 void InjectedBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void *clientInfo)
327 {
328 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didClearWindowForFrame(frame, world);
329 }
330
didCancelClientRedirectForFrame(WKBundlePageRef page,WKBundleFrameRef frame,const void * clientInfo)331 void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
332 {
333 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCancelClientRedirectForFrame(frame);
334 }
335
willPerformClientRedirectForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKURLRef url,double delay,double date,const void * clientInfo)336 void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKURLRef url, double delay, double date, const void* clientInfo)
337 {
338 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willPerformClientRedirectForFrame(frame, url, delay, date);
339 }
340
didSameDocumentNavigationForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKSameDocumentNavigationType type,WKTypeRef *,const void * clientInfo)341 void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef*, const void* clientInfo)
342 {
343 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didSameDocumentNavigationForFrame(frame, type);
344 }
345
didHandleOnloadEventsForFrame(WKBundlePageRef page,WKBundleFrameRef frame,const void * clientInfo)346 void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
347 {
348 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didHandleOnloadEventsForFrame(frame);
349 }
350
didDisplayInsecureContentForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKTypeRef *,const void * clientInfo)351 void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
352 {
353 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didDisplayInsecureContentForFrame(frame);
354 }
355
didRunInsecureContentForFrame(WKBundlePageRef page,WKBundleFrameRef frame,WKTypeRef *,const void * clientInfo)356 void InjectedBundlePage::didRunInsecureContentForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
357 {
358 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didRunInsecureContentForFrame(frame);
359 }
360
didInitiateLoadForResource(WKBundlePageRef page,WKBundleFrameRef frame,uint64_t identifier,WKURLRequestRef request,bool pageLoadIsProvisional,const void * clientInfo)361 void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, bool pageLoadIsProvisional, const void* clientInfo)
362 {
363 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didInitiateLoadForResource(page, frame, identifier, request, pageLoadIsProvisional);
364 }
365
willSendRequestForFrame(WKBundlePageRef page,WKBundleFrameRef frame,uint64_t identifier,WKURLRequestRef request,WKURLResponseRef redirectResponse,const void * clientInfo)366 WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, WKURLResponseRef redirectResponse, const void* clientInfo)
367 {
368 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSendRequestForFrame(page, frame, identifier, request, redirectResponse);
369 }
370
didReceiveResponseForResource(WKBundlePageRef page,WKBundleFrameRef frame,uint64_t identifier,WKURLResponseRef response,const void * clientInfo)371 void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLResponseRef response, const void* clientInfo)
372 {
373 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveResponseForResource(page, frame, identifier, response);
374 }
375
didReceiveContentLengthForResource(WKBundlePageRef page,WKBundleFrameRef frame,uint64_t identifier,uint64_t length,const void * clientInfo)376 void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, uint64_t length, const void* clientInfo)
377 {
378 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveContentLengthForResource(page, frame, identifier, length);
379 }
380
didFinishLoadForResource(WKBundlePageRef page,WKBundleFrameRef frame,uint64_t identifier,const void * clientInfo)381 void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, const void* clientInfo)
382 {
383 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForResource(page, frame, identifier);
384 }
385
didFailLoadForResource(WKBundlePageRef page,WKBundleFrameRef frame,uint64_t identifier,WKErrorRef error,const void * clientInfo)386 void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKErrorRef error, const void* clientInfo)
387 {
388 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForResource(page, frame, identifier, error);
389 }
390
didStartProvisionalLoadForFrame(WKBundleFrameRef frame)391 void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame)
392 {
393 if (!InjectedBundle::shared().isTestRunning())
394 return;
395
396 if (InjectedBundle::shared().topLoadingFrame())
397 return;
398 InjectedBundle::shared().setTopLoadingFrame(frame);
399 }
400
didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame)401 void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame)
402 {
403 }
404
didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame,WKErrorRef error)405 void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef error)
406 {
407 if (!InjectedBundle::shared().isTestRunning())
408 return;
409
410 if (frame != InjectedBundle::shared().topLoadingFrame())
411 return;
412 InjectedBundle::shared().setTopLoadingFrame(0);
413
414 if (InjectedBundle::shared().layoutTestController()->waitToDump())
415 return;
416
417 InjectedBundle::shared().done();
418 }
419
didCommitLoadForFrame(WKBundleFrameRef frame)420 void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame)
421 {
422 }
423
424 enum FrameNamePolicy { ShouldNotIncludeFrameName, ShouldIncludeFrameName };
425
dumpFrameScrollPosition(WKBundleFrameRef frame,FrameNamePolicy shouldIncludeFrameName=ShouldNotIncludeFrameName)426 static void dumpFrameScrollPosition(WKBundleFrameRef frame, FrameNamePolicy shouldIncludeFrameName = ShouldNotIncludeFrameName)
427 {
428 double x = numericWindowPropertyValue(frame, "pageXOffset");
429 double y = numericWindowPropertyValue(frame, "pageYOffset");
430 if (fabs(x) > 0.00000001 || fabs(y) > 0.00000001) {
431 if (shouldIncludeFrameName) {
432 WKRetainPtr<WKStringRef> name(AdoptWK, WKBundleFrameCopyName(frame));
433 InjectedBundle::shared().os() << "frame '" << name << "' ";
434 }
435 InjectedBundle::shared().os() << "scrolled to " << x << "," << y << "\n";
436 }
437 }
438
dumpDescendantFrameScrollPositions(WKBundleFrameRef frame)439 static void dumpDescendantFrameScrollPositions(WKBundleFrameRef frame)
440 {
441 WKRetainPtr<WKArrayRef> childFrames(AdoptWK, WKBundleFrameCopyChildFrames(frame));
442 size_t size = WKArrayGetSize(childFrames.get());
443 for (size_t i = 0; i < size; ++i) {
444 WKBundleFrameRef subframe = static_cast<WKBundleFrameRef>(WKArrayGetItemAtIndex(childFrames.get(), i));
445 dumpFrameScrollPosition(subframe, ShouldIncludeFrameName);
446 dumpDescendantFrameScrollPositions(subframe);
447 }
448 }
449
dumpAllFrameScrollPositions()450 void InjectedBundlePage::dumpAllFrameScrollPositions()
451 {
452 WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
453 dumpFrameScrollPosition(frame);
454 dumpDescendantFrameScrollPositions(frame);
455 }
456
toJS(const char * string)457 static JSRetainPtr<JSStringRef> toJS(const char* string)
458 {
459 return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(string));
460 }
461
hasDocumentElement(WKBundleFrameRef frame)462 static bool hasDocumentElement(WKBundleFrameRef frame)
463 {
464 JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
465 JSObjectRef globalObject = JSContextGetGlobalObject(context);
466
467 JSValueRef documentValue = JSObjectGetProperty(context, globalObject, toJS("document").get(), 0);
468 if (!documentValue)
469 return false;
470
471 ASSERT(JSValueIsObject(context, documentValue));
472 JSObjectRef document = JSValueToObject(context, documentValue, 0);
473
474 JSValueRef documentElementValue = JSObjectGetProperty(context, document, toJS("documentElement").get(), 0);
475 if (!documentElementValue)
476 return false;
477
478 return JSValueToBoolean(context, documentElementValue);
479 }
480
dumpFrameText(WKBundleFrameRef frame)481 static void dumpFrameText(WKBundleFrameRef frame)
482 {
483 // If the frame doesn't have a document element, its inner text will be an empty string, so
484 // we'll end up just appending a single newline below. But DumpRenderTree doesn't append
485 // anything in this case, so we shouldn't either.
486 if (!hasDocumentElement(frame))
487 return;
488
489 WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyInnerText(frame));
490 InjectedBundle::shared().os() << text << "\n";
491 }
492
dumpDescendantFramesText(WKBundleFrameRef frame)493 static void dumpDescendantFramesText(WKBundleFrameRef frame)
494 {
495 WKRetainPtr<WKArrayRef> childFrames(AdoptWK, WKBundleFrameCopyChildFrames(frame));
496 size_t size = WKArrayGetSize(childFrames.get());
497 for (size_t i = 0; i < size; ++i) {
498 WKBundleFrameRef subframe = static_cast<WKBundleFrameRef>(WKArrayGetItemAtIndex(childFrames.get(), i));
499 WKRetainPtr<WKStringRef> subframeName(AdoptWK, WKBundleFrameCopyName(subframe));
500 InjectedBundle::shared().os() << "\n--------\nFrame: '" << subframeName << "'\n--------\n";
501 dumpFrameText(subframe);
502 dumpDescendantFramesText(subframe);
503 }
504 }
505
dumpAllFramesText()506 void InjectedBundlePage::dumpAllFramesText()
507 {
508 WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
509 dumpFrameText(frame);
510 dumpDescendantFramesText(frame);
511 }
512
dump()513 void InjectedBundlePage::dump()
514 {
515 ASSERT(InjectedBundle::shared().isTestRunning());
516
517 InjectedBundle::shared().layoutTestController()->invalidateWaitToDumpWatchdogTimer();
518
519 // Force a paint before dumping. This matches DumpRenderTree on Windows. (DumpRenderTree on Mac
520 // does this at a slightly different time.) See <http://webkit.org/b/55469> for details.
521 WKBundlePageForceRepaint(m_page);
522
523 WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
524 string url = toSTD(adoptWK(WKURLCopyString(adoptWK(WKBundleFrameCopyURL(frame)).get())));
525 if (strstr(url.c_str(), "dumpAsText/"))
526 InjectedBundle::shared().layoutTestController()->dumpAsText();
527
528 switch (InjectedBundle::shared().layoutTestController()->whatToDump()) {
529 case LayoutTestController::RenderTree: {
530 WKRetainPtr<WKStringRef> text(AdoptWK, WKBundlePageCopyRenderTreeExternalRepresentation(m_page));
531 InjectedBundle::shared().os() << text;
532 break;
533 }
534 case LayoutTestController::MainFrameText:
535 dumpFrameText(WKBundlePageGetMainFrame(m_page));
536 break;
537 case LayoutTestController::AllFramesText:
538 dumpAllFramesText();
539 break;
540 }
541
542 if (InjectedBundle::shared().layoutTestController()->shouldDumpAllFrameScrollPositions())
543 dumpAllFrameScrollPositions();
544 else if (InjectedBundle::shared().layoutTestController()->shouldDumpMainFrameScrollPosition())
545 dumpFrameScrollPosition(WKBundlePageGetMainFrame(m_page));
546
547 if (InjectedBundle::shared().layoutTestController()->shouldDumpBackForwardListsForAllWindows())
548 InjectedBundle::shared().dumpBackForwardListsForAllPages();
549
550 if (InjectedBundle::shared().shouldDumpPixels() && InjectedBundle::shared().layoutTestController()->shouldDumpPixels())
551 InjectedBundle::shared().setPixelResult(adoptWK(WKBundlePageCreateSnapshotInViewCoordinates(m_page, WKBundleFrameGetVisibleContentBounds(WKBundlePageGetMainFrame(m_page)), kWKImageOptionsShareable)).get());
552
553 InjectedBundle::shared().done();
554 }
555
didFinishLoadForFrame(WKBundleFrameRef frame)556 void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame)
557 {
558 if (!InjectedBundle::shared().isTestRunning())
559 return;
560
561 if (frame != InjectedBundle::shared().topLoadingFrame())
562 return;
563 InjectedBundle::shared().setTopLoadingFrame(0);
564
565 if (InjectedBundle::shared().layoutTestController()->waitToDump())
566 return;
567
568 InjectedBundle::shared().page()->dump();
569 }
570
didFailLoadWithErrorForFrame(WKBundleFrameRef frame,WKErrorRef)571 void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef)
572 {
573 if (!InjectedBundle::shared().isTestRunning())
574 return;
575
576 if (frame != InjectedBundle::shared().topLoadingFrame())
577 return;
578 InjectedBundle::shared().setTopLoadingFrame(0);
579
580 if (InjectedBundle::shared().layoutTestController()->waitToDump())
581 return;
582
583 InjectedBundle::shared().done();
584 }
585
didReceiveTitleForFrame(WKStringRef title,WKBundleFrameRef frame)586 void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef frame)
587 {
588 if (!InjectedBundle::shared().isTestRunning())
589 return;
590
591 if (!InjectedBundle::shared().layoutTestController()->shouldDumpTitleChanges())
592 return;
593
594 InjectedBundle::shared().os() << "TITLE CHANGED: " << title << "\n";
595 }
596
didClearWindowForFrame(WKBundleFrameRef frame,WKBundleScriptWorldRef world)597 void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundleScriptWorldRef world)
598 {
599 if (!InjectedBundle::shared().isTestRunning())
600 return;
601
602 JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
603 JSObjectRef window = JSContextGetGlobalObject(context);
604
605 if (WKBundleScriptWorldNormalWorld() != world) {
606 JSObjectSetProperty(context, window, toJS("__worldID").get(), JSValueMakeNumber(context, LayoutTestController::worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0);
607 return;
608 }
609
610 JSValueRef exception = 0;
611 InjectedBundle::shared().layoutTestController()->makeWindowObject(context, window, &exception);
612 InjectedBundle::shared().gcController()->makeWindowObject(context, window, &exception);
613 InjectedBundle::shared().eventSendingController()->makeWindowObject(context, window, &exception);
614 }
615
didCancelClientRedirectForFrame(WKBundleFrameRef frame)616 void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame)
617 {
618 }
619
willPerformClientRedirectForFrame(WKBundleFrameRef frame,WKURLRef url,double delay,double date)620 void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundleFrameRef frame, WKURLRef url, double delay, double date)
621 {
622 }
623
didSameDocumentNavigationForFrame(WKBundleFrameRef frame,WKSameDocumentNavigationType type)624 void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundleFrameRef frame, WKSameDocumentNavigationType type)
625 {
626 }
627
didFinishDocumentLoadForFrame(WKBundleFrameRef frame)628 void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame)
629 {
630 if (!InjectedBundle::shared().isTestRunning())
631 return;
632
633 unsigned pendingFrameUnloadEvents = WKBundleFrameGetPendingUnloadCount(frame);
634 if (pendingFrameUnloadEvents)
635 InjectedBundle::shared().os() << frame << " - has " << pendingFrameUnloadEvents << " onunload handler(s)\n";
636 }
637
didHandleOnloadEventsForFrame(WKBundleFrameRef frame)638 void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundleFrameRef frame)
639 {
640 }
641
didDisplayInsecureContentForFrame(WKBundleFrameRef frame)642 void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef frame)
643 {
644 }
645
didRunInsecureContentForFrame(WKBundleFrameRef frame)646 void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef frame)
647 {
648 }
649
didInitiateLoadForResource(WKBundlePageRef,WKBundleFrameRef,uint64_t identifier,WKURLRequestRef,bool)650 void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef, bool)
651 {
652 }
653
654 // Resource Load Client Callbacks
655
willSendRequestForFrame(WKBundlePageRef,WKBundleFrameRef,uint64_t,WKURLRequestRef request,WKURLResponseRef)656 WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef, WKBundleFrameRef, uint64_t, WKURLRequestRef request, WKURLResponseRef)
657 {
658 if (InjectedBundle::shared().isTestRunning() && InjectedBundle::shared().layoutTestController()->willSendRequestReturnsNull())
659 return 0;
660
661 WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request));
662 WKRetainPtr<WKStringRef> host = adoptWK(WKURLCopyHostName(url.get()));
663 WKRetainPtr<WKStringRef> scheme = adoptWK(WKURLCopyScheme(url.get()));
664 if (host && !WKStringIsEmpty(host.get())
665 && (WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "http") || WKStringIsEqualToUTF8CStringIgnoringCase(scheme.get(), "https"))
666 && !WKStringIsEqualToUTF8CString(host.get(), "127.0.0.1")
667 && !WKStringIsEqualToUTF8CString(host.get(), "255.255.255.255") // Used in some tests that expect to get back an error.
668 && !WKStringIsEqualToUTF8CStringIgnoringCase(host.get(), "localhost")) {
669 InjectedBundle::shared().os() << "Blocked access to external URL " << url << "\n";
670 return 0;
671 }
672
673 WKRetain(request);
674 return request;
675 }
676
didReceiveResponseForResource(WKBundlePageRef,WKBundleFrameRef,uint64_t,WKURLResponseRef)677 void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, WKURLResponseRef)
678 {
679 }
680
didReceiveContentLengthForResource(WKBundlePageRef,WKBundleFrameRef,uint64_t,uint64_t)681 void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, uint64_t)
682 {
683 }
684
didFinishLoadForResource(WKBundlePageRef,WKBundleFrameRef,uint64_t)685 void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t)
686 {
687 }
688
didFailLoadForResource(WKBundlePageRef,WKBundleFrameRef,uint64_t,WKErrorRef)689 void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, WKErrorRef)
690 {
691 }
692
693
694 // Policy Client Callbacks
695
decidePolicyForNavigationAction(WKBundlePageRef page,WKBundleFrameRef frame,WKBundleNavigationActionRef navigationAction,WKURLRequestRef request,WKTypeRef * userData,const void * clientInfo)696 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKTypeRef* userData, const void* clientInfo)
697 {
698 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(page, frame, navigationAction, request, userData);
699 }
700
decidePolicyForNewWindowAction(WKBundlePageRef page,WKBundleFrameRef frame,WKBundleNavigationActionRef navigationAction,WKURLRequestRef request,WKStringRef frameName,WKTypeRef * userData,const void * clientInfo)701 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKStringRef frameName, WKTypeRef* userData, const void* clientInfo)
702 {
703 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForNewWindowAction(page, frame, navigationAction, request, frameName, userData);
704 }
705
decidePolicyForResponse(WKBundlePageRef page,WKBundleFrameRef frame,WKURLResponseRef response,WKURLRequestRef request,WKTypeRef * userData,const void * clientInfo)706 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKTypeRef* userData, const void* clientInfo)
707 {
708 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(page, frame, response, request, userData);
709 }
710
unableToImplementPolicy(WKBundlePageRef page,WKBundleFrameRef frame,WKErrorRef error,WKTypeRef * userData,const void * clientInfo)711 void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef* userData, const void* clientInfo)
712 {
713 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->unableToImplementPolicy(page, frame, error, userData);
714 }
715
decidePolicyForNavigationAction(WKBundlePageRef,WKBundleFrameRef,WKBundleNavigationActionRef,WKURLRequestRef request,WKTypeRef *)716 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef request, WKTypeRef*)
717 {
718 return WKBundlePagePolicyActionUse;
719 }
720
decidePolicyForNewWindowAction(WKBundlePageRef,WKBundleFrameRef,WKBundleNavigationActionRef,WKURLRequestRef,WKStringRef,WKTypeRef *)721 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKStringRef, WKTypeRef*)
722 {
723 return WKBundlePagePolicyActionUse;
724 }
725
decidePolicyForResponse(WKBundlePageRef,WKBundleFrameRef,WKURLResponseRef,WKURLRequestRef,WKTypeRef *)726 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef, WKBundleFrameRef, WKURLResponseRef, WKURLRequestRef, WKTypeRef*)
727 {
728 return WKBundlePagePolicyActionUse;
729 }
730
unableToImplementPolicy(WKBundlePageRef,WKBundleFrameRef,WKErrorRef,WKTypeRef *)731 void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*)
732 {
733 }
734
735 // UI Client Callbacks
736
willAddMessageToConsole(WKBundlePageRef page,WKStringRef message,uint32_t lineNumber,const void * clientInfo)737 void InjectedBundlePage::willAddMessageToConsole(WKBundlePageRef page, WKStringRef message, uint32_t lineNumber, const void *clientInfo)
738 {
739 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willAddMessageToConsole(message, lineNumber);
740 }
741
willSetStatusbarText(WKBundlePageRef page,WKStringRef statusbarText,const void * clientInfo)742 void InjectedBundlePage::willSetStatusbarText(WKBundlePageRef page, WKStringRef statusbarText, const void *clientInfo)
743 {
744 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSetStatusbarText(statusbarText);
745 }
746
willRunJavaScriptAlert(WKBundlePageRef page,WKStringRef message,WKBundleFrameRef frame,const void * clientInfo)747 void InjectedBundlePage::willRunJavaScriptAlert(WKBundlePageRef page, WKStringRef message, WKBundleFrameRef frame, const void *clientInfo)
748 {
749 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptAlert(message, frame);
750 }
751
willRunJavaScriptConfirm(WKBundlePageRef page,WKStringRef message,WKBundleFrameRef frame,const void * clientInfo)752 void InjectedBundlePage::willRunJavaScriptConfirm(WKBundlePageRef page, WKStringRef message, WKBundleFrameRef frame, const void *clientInfo)
753 {
754 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptConfirm(message, frame);
755 }
756
willRunJavaScriptPrompt(WKBundlePageRef page,WKStringRef message,WKStringRef defaultValue,WKBundleFrameRef frame,const void * clientInfo)757 void InjectedBundlePage::willRunJavaScriptPrompt(WKBundlePageRef page, WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef frame, const void *clientInfo)
758 {
759 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptPrompt(message, defaultValue, frame);
760 }
761
lastFileURLPathComponent(const string & path)762 static string lastFileURLPathComponent(const string& path)
763 {
764 size_t pos = path.find("file://");
765 ASSERT(string::npos != pos);
766
767 string tmpPath = path.substr(pos + 7);
768 if (tmpPath.empty())
769 return tmpPath;
770
771 // Remove the trailing delimiter
772 if (tmpPath[tmpPath.length() - 1] == '/')
773 tmpPath.erase(tmpPath.length() - 1);
774
775 pos = tmpPath.rfind('/');
776 if (string::npos != pos)
777 return tmpPath.substr(pos + 1);
778
779 return tmpPath;
780 }
781
willAddMessageToConsole(WKStringRef message,uint32_t lineNumber)782 void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t lineNumber)
783 {
784 if (!InjectedBundle::shared().isTestRunning())
785 return;
786
787 string messageString = toSTD(message);
788 size_t fileProtocolStart = messageString.find("file://");
789 if (fileProtocolStart != string::npos)
790 // FIXME: The code below does not handle additional text after url nor multiple urls. This matches DumpRenderTree implementation.
791 messageString = messageString.substr(0, fileProtocolStart) + lastFileURLPathComponent(messageString.substr(fileProtocolStart));
792
793 InjectedBundle::shared().os() << "CONSOLE MESSAGE: line " << lineNumber << ": " << messageString << "\n";
794 }
795
willSetStatusbarText(WKStringRef statusbarText)796 void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText)
797 {
798 if (!InjectedBundle::shared().isTestRunning())
799 return;
800
801 if (!InjectedBundle::shared().layoutTestController()->shouldDumpStatusCallbacks())
802 return;
803
804 InjectedBundle::shared().os() << "UI DELEGATE STATUS CALLBACK: setStatusText:" << statusbarText << "\n";
805 }
806
willRunJavaScriptAlert(WKStringRef message,WKBundleFrameRef)807 void InjectedBundlePage::willRunJavaScriptAlert(WKStringRef message, WKBundleFrameRef)
808 {
809 if (!InjectedBundle::shared().isTestRunning())
810 return;
811
812 InjectedBundle::shared().os() << "ALERT: " << message << "\n";
813 }
814
willRunJavaScriptConfirm(WKStringRef message,WKBundleFrameRef)815 void InjectedBundlePage::willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef)
816 {
817 if (!InjectedBundle::shared().isTestRunning())
818 return;
819
820 InjectedBundle::shared().os() << "CONFIRM: " << message << "\n";
821 }
822
willRunJavaScriptPrompt(WKStringRef message,WKStringRef defaultValue,WKBundleFrameRef)823 void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef)
824 {
825 InjectedBundle::shared().os() << "PROMPT: " << message << ", default text: " << defaultValue << "\n";
826 }
827
828 // Editor Client Callbacks
829
shouldBeginEditing(WKBundlePageRef page,WKBundleRangeHandleRef range,const void * clientInfo)830 bool InjectedBundlePage::shouldBeginEditing(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
831 {
832 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldBeginEditing(range);
833 }
834
shouldEndEditing(WKBundlePageRef page,WKBundleRangeHandleRef range,const void * clientInfo)835 bool InjectedBundlePage::shouldEndEditing(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
836 {
837 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldEndEditing(range);
838 }
839
shouldInsertNode(WKBundlePageRef page,WKBundleNodeHandleRef node,WKBundleRangeHandleRef rangeToReplace,WKInsertActionType action,const void * clientInfo)840 bool InjectedBundlePage::shouldInsertNode(WKBundlePageRef page, WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action, const void* clientInfo)
841 {
842 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldInsertNode(node, rangeToReplace, action);
843 }
844
shouldInsertText(WKBundlePageRef page,WKStringRef text,WKBundleRangeHandleRef rangeToReplace,WKInsertActionType action,const void * clientInfo)845 bool InjectedBundlePage::shouldInsertText(WKBundlePageRef page, WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action, const void* clientInfo)
846 {
847 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldInsertText(text, rangeToReplace, action);
848 }
849
shouldDeleteRange(WKBundlePageRef page,WKBundleRangeHandleRef range,const void * clientInfo)850 bool InjectedBundlePage::shouldDeleteRange(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
851 {
852 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldDeleteRange(range);
853 }
854
shouldChangeSelectedRange(WKBundlePageRef page,WKBundleRangeHandleRef fromRange,WKBundleRangeHandleRef toRange,WKAffinityType affinity,bool stillSelecting,const void * clientInfo)855 bool InjectedBundlePage::shouldChangeSelectedRange(WKBundlePageRef page, WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting, const void* clientInfo)
856 {
857 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldChangeSelectedRange(fromRange, toRange, affinity, stillSelecting);
858 }
859
shouldApplyStyle(WKBundlePageRef page,WKBundleCSSStyleDeclarationRef style,WKBundleRangeHandleRef range,const void * clientInfo)860 bool InjectedBundlePage::shouldApplyStyle(WKBundlePageRef page, WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range, const void* clientInfo)
861 {
862 return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldApplyStyle(style, range);
863 }
864
didBeginEditing(WKBundlePageRef page,WKStringRef notificationName,const void * clientInfo)865 void InjectedBundlePage::didBeginEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
866 {
867 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didBeginEditing(notificationName);
868 }
869
didEndEditing(WKBundlePageRef page,WKStringRef notificationName,const void * clientInfo)870 void InjectedBundlePage::didEndEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
871 {
872 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didEndEditing(notificationName);
873 }
874
didChange(WKBundlePageRef page,WKStringRef notificationName,const void * clientInfo)875 void InjectedBundlePage::didChange(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
876 {
877 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChange(notificationName);
878 }
879
didChangeSelection(WKBundlePageRef page,WKStringRef notificationName,const void * clientInfo)880 void InjectedBundlePage::didChangeSelection(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
881 {
882 static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChangeSelection(notificationName);
883 }
884
shouldBeginEditing(WKBundleRangeHandleRef range)885 bool InjectedBundlePage::shouldBeginEditing(WKBundleRangeHandleRef range)
886 {
887 if (!InjectedBundle::shared().isTestRunning())
888 return true;
889
890 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
891 InjectedBundle::shared().os() << "EDITING DELEGATE: shouldBeginEditingInDOMRange:" << toStr(m_page, m_world.get(), range) << "\n";
892 return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
893 }
894
shouldEndEditing(WKBundleRangeHandleRef range)895 bool InjectedBundlePage::shouldEndEditing(WKBundleRangeHandleRef range)
896 {
897 if (!InjectedBundle::shared().isTestRunning())
898 return true;
899
900 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
901 InjectedBundle::shared().os() << "EDITING DELEGATE: shouldEndEditingInDOMRange:" << toStr(m_page, m_world.get(), range) << "\n";
902 return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
903 }
904
shouldInsertNode(WKBundleNodeHandleRef node,WKBundleRangeHandleRef rangeToReplace,WKInsertActionType action)905 bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action)
906 {
907 if (!InjectedBundle::shared().isTestRunning())
908 return true;
909
910 static const char* insertactionstring[] = {
911 "WebViewInsertActionTyped",
912 "WebViewInsertActionPasted",
913 "WebViewInsertActionDropped",
914 };
915
916 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
917 InjectedBundle::shared().os() << "EDITING DELEGATE: shouldInsertNode:" << dumpPath(m_page, m_world.get(), node) << " replacingDOMRange:" << toStr(m_page, m_world.get(), rangeToReplace) << " givenAction:" << insertactionstring[action] << "\n";
918 return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
919 }
920
shouldInsertText(WKStringRef text,WKBundleRangeHandleRef rangeToReplace,WKInsertActionType action)921 bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action)
922 {
923 if (!InjectedBundle::shared().isTestRunning())
924 return true;
925
926 static const char *insertactionstring[] = {
927 "WebViewInsertActionTyped",
928 "WebViewInsertActionPasted",
929 "WebViewInsertActionDropped",
930 };
931
932 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
933 InjectedBundle::shared().os() << "EDITING DELEGATE: shouldInsertText:" << text << " replacingDOMRange:" << toStr(m_page, m_world.get(), rangeToReplace) << " givenAction:" << insertactionstring[action] << "\n";
934 return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
935 }
936
shouldDeleteRange(WKBundleRangeHandleRef range)937 bool InjectedBundlePage::shouldDeleteRange(WKBundleRangeHandleRef range)
938 {
939 if (!InjectedBundle::shared().isTestRunning())
940 return true;
941
942 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
943 InjectedBundle::shared().os() << "EDITING DELEGATE: shouldDeleteDOMRange:" << toStr(m_page, m_world.get(), range) << "\n";
944 return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
945 }
946
shouldChangeSelectedRange(WKBundleRangeHandleRef fromRange,WKBundleRangeHandleRef toRange,WKAffinityType affinity,bool stillSelecting)947 bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting)
948 {
949 if (!InjectedBundle::shared().isTestRunning())
950 return true;
951
952 static const char *affinitystring[] = {
953 "NSSelectionAffinityUpstream",
954 "NSSelectionAffinityDownstream"
955 };
956 static const char *boolstring[] = {
957 "FALSE",
958 "TRUE"
959 };
960
961 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
962 InjectedBundle::shared().os() << "EDITING DELEGATE: shouldChangeSelectedDOMRange:" << toStr(m_page, m_world.get(), fromRange) << " toDOMRange:" << toStr(m_page, m_world.get(), toRange) << " affinity:" << affinitystring[affinity] << " stillSelecting:" << boolstring[stillSelecting] << "\n";
963 return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
964 }
965
shouldApplyStyle(WKBundleCSSStyleDeclarationRef style,WKBundleRangeHandleRef range)966 bool InjectedBundlePage::shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range)
967 {
968 if (!InjectedBundle::shared().isTestRunning())
969 return true;
970
971 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
972 InjectedBundle::shared().os() << "EDITING DELEGATE: shouldApplyStyle:" << style << " toElementsInDOMRange:" << toStr(m_page, m_world.get(), range) << "\n";
973 return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
974 }
975
didBeginEditing(WKStringRef notificationName)976 void InjectedBundlePage::didBeginEditing(WKStringRef notificationName)
977 {
978 if (!InjectedBundle::shared().isTestRunning())
979 return;
980
981 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
982 InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidBeginEditing:" << notificationName << "\n";
983 }
984
didEndEditing(WKStringRef notificationName)985 void InjectedBundlePage::didEndEditing(WKStringRef notificationName)
986 {
987 if (!InjectedBundle::shared().isTestRunning())
988 return;
989
990 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
991 InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidEndEditing:" << notificationName << "\n";
992 }
993
didChange(WKStringRef notificationName)994 void InjectedBundlePage::didChange(WKStringRef notificationName)
995 {
996 if (!InjectedBundle::shared().isTestRunning())
997 return;
998
999 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
1000 InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidChange:" << notificationName << "\n";
1001 }
1002
didChangeSelection(WKStringRef notificationName)1003 void InjectedBundlePage::didChangeSelection(WKStringRef notificationName)
1004 {
1005 if (!InjectedBundle::shared().isTestRunning())
1006 return;
1007
1008 if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
1009 InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidChangeSelection:" << notificationName << "\n";
1010 }
1011
1012 #if ENABLE(FULLSCREEN_API)
supportsFullScreen(WKBundlePageRef pageRef,WKFullScreenKeyboardRequestType requestType)1013 bool InjectedBundlePage::supportsFullScreen(WKBundlePageRef pageRef, WKFullScreenKeyboardRequestType requestType)
1014 {
1015 if (InjectedBundle::shared().layoutTestController()->shouldDumpFullScreenCallbacks())
1016 InjectedBundle::shared().os() << "supportsFullScreen() == true\n";
1017 return true;
1018 }
1019
enterFullScreenForElement(WKBundlePageRef pageRef,WKBundleNodeHandleRef elementRef)1020 void InjectedBundlePage::enterFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef)
1021 {
1022 if (InjectedBundle::shared().layoutTestController()->shouldDumpFullScreenCallbacks())
1023 InjectedBundle::shared().os() << "enterFullScreenForElement()\n";
1024 WKBundlePageWillEnterFullScreen(pageRef);
1025 WKBundlePageDidEnterFullScreen(pageRef);
1026 }
1027
exitFullScreenForElement(WKBundlePageRef pageRef,WKBundleNodeHandleRef elementRef)1028 void InjectedBundlePage::exitFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef)
1029 {
1030 if (InjectedBundle::shared().layoutTestController()->shouldDumpFullScreenCallbacks())
1031 InjectedBundle::shared().os() << "exitFullScreenForElement()\n";
1032 WKBundlePageWillExitFullScreen(pageRef);
1033 WKBundlePageDidExitFullScreen(pageRef);
1034 }
1035 #endif
1036
compareByTargetName(WKBundleBackForwardListItemRef item1,WKBundleBackForwardListItemRef item2)1037 static bool compareByTargetName(WKBundleBackForwardListItemRef item1, WKBundleBackForwardListItemRef item2)
1038 {
1039 return toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item1))) < toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item2)));
1040 }
1041
dumpBackForwardListItem(WKBundleBackForwardListItemRef item,unsigned indent,bool isCurrentItem)1042 static void dumpBackForwardListItem(WKBundleBackForwardListItemRef item, unsigned indent, bool isCurrentItem)
1043 {
1044 unsigned column = 0;
1045 if (isCurrentItem) {
1046 InjectedBundle::shared().os() << "curr->";
1047 column = 6;
1048 }
1049 for (unsigned i = column; i < indent; i++)
1050 InjectedBundle::shared().os() << ' ';
1051
1052 string url = toSTD(adoptWK(WKURLCopyString(adoptWK(WKBundleBackForwardListItemCopyURL(item)).get())));
1053 if (hasPrefix(url, "file:")) {
1054 string directoryName = "/LayoutTests/";
1055 size_t start = url.find(directoryName);
1056 if (start == string::npos)
1057 start = 0;
1058 else
1059 start += directoryName.size();
1060 InjectedBundle::shared().os() << "(file test):" << url.substr(start);
1061 } else
1062 InjectedBundle::shared().os() << url;
1063
1064 string target = toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item)));
1065 if (target.length())
1066 InjectedBundle::shared().os() << " (in frame \"" << target << "\")";
1067
1068 // FIXME: Need WKBackForwardListItemIsTargetItem.
1069 if (WKBundleBackForwardListItemIsTargetItem(item))
1070 InjectedBundle::shared().os() << " **nav target**";
1071
1072 InjectedBundle::shared().os() << '\n';
1073
1074 if (WKRetainPtr<WKArrayRef> kids = adoptWK(WKBundleBackForwardListItemCopyChildren(item))) {
1075 // Sort to eliminate arbitrary result ordering which defeats reproducible testing.
1076 size_t size = WKArrayGetSize(kids.get());
1077 Vector<WKBundleBackForwardListItemRef> sortedKids(size);
1078 for (size_t i = 0; i < size; ++i)
1079 sortedKids[i] = static_cast<WKBundleBackForwardListItemRef>(WKArrayGetItemAtIndex(kids.get(), i));
1080 stable_sort(sortedKids.begin(), sortedKids.end(), compareByTargetName);
1081 for (size_t i = 0; i < size; ++i)
1082 dumpBackForwardListItem(sortedKids[i], indent + 4, false);
1083 }
1084 }
1085
dumpBackForwardList()1086 void InjectedBundlePage::dumpBackForwardList()
1087 {
1088 InjectedBundle::shared().os() << "\n============== Back Forward List ==============\n";
1089
1090 WKBundleBackForwardListRef list = WKBundlePageGetBackForwardList(m_page);
1091
1092 // Print out all items in the list after m_previousTestBackForwardListItem.
1093 // Gather items from the end of the list, then print them out from oldest to newest.
1094 Vector<WKRetainPtr<WKBundleBackForwardListItemRef> > itemsToPrint;
1095 for (unsigned i = WKBundleBackForwardListGetForwardListCount(list); i; --i) {
1096 WKRetainPtr<WKBundleBackForwardListItemRef> item = adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, i));
1097 // Something is wrong if the item from the last test is in the forward part of the list.
1098 ASSERT(!WKBundleBackForwardListItemIsSame(item.get(), m_previousTestBackForwardListItem.get()));
1099 itemsToPrint.append(item);
1100 }
1101
1102 ASSERT(!WKBundleBackForwardListItemIsSame(adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, 0)).get(), m_previousTestBackForwardListItem.get()));
1103
1104 itemsToPrint.append(adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, 0)));
1105
1106 int currentItemIndex = itemsToPrint.size() - 1;
1107
1108 int backListCount = WKBundleBackForwardListGetBackListCount(list);
1109 for (int i = -1; i >= -backListCount; --i) {
1110 WKRetainPtr<WKBundleBackForwardListItemRef> item = adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, i));
1111 if (WKBundleBackForwardListItemIsSame(item.get(), m_previousTestBackForwardListItem.get()))
1112 break;
1113 itemsToPrint.append(item);
1114 }
1115
1116 for (int i = itemsToPrint.size() - 1; i >= 0; i--)
1117 dumpBackForwardListItem(itemsToPrint[i].get(), 8, i == currentItemIndex);
1118
1119 InjectedBundle::shared().os() << "===============================================\n";
1120 }
1121
1122 } // namespace WTR
1123