• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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