1 | /* |
2 | * Copyright (C) 2010-2016 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 "ActivateFonts.h" |
30 | #include "InjectedBundle.h" |
31 | #include "StringFunctions.h" |
32 | #include "WebCoreTestSupport.h" |
33 | #include <cmath> |
34 | #include <JavaScriptCore/JSRetainPtr.h> |
35 | #include <WebKit/WKArray.h> |
36 | #include <WebKit/WKBundle.h> |
37 | #include <WebKit/WKBundleBackForwardList.h> |
38 | #include <WebKit/WKBundleBackForwardListItem.h> |
39 | #include <WebKit/WKBundleFrame.h> |
40 | #include <WebKit/WKBundleFramePrivate.h> |
41 | #include <WebKit/WKBundleHitTestResult.h> |
42 | #include <WebKit/WKBundleNavigationAction.h> |
43 | #include <WebKit/WKBundleNavigationActionPrivate.h> |
44 | #include <WebKit/WKBundleNodeHandlePrivate.h> |
45 | #include <WebKit/WKBundlePagePrivate.h> |
46 | #include <WebKit/WKBundlePrivate.h> |
47 | #include <WebKit/WKSecurityOriginRef.h> |
48 | #include <WebKit/WKURLRequest.h> |
49 | #include <wtf/HashMap.h> |
50 | #include <wtf/text/CString.h> |
51 | #include <wtf/text/StringBuilder.h> |
52 | |
53 | #if USE(CF) && !PLATFORM(WIN_CAIRO) |
54 | #include "WebArchiveDumpSupport.h" |
55 | #endif |
56 | |
57 | using namespace std; |
58 | |
59 | namespace WTR { |
60 | |
61 | static JSValueRef propertyValue(JSContextRef context, JSObjectRef object, const char* propertyName) |
62 | { |
63 | if (!object) |
64 | return 0; |
65 | auto propertyNameString = adopt(JSStringCreateWithUTF8CString(propertyName)); |
66 | return JSObjectGetProperty(context, object, propertyNameString.get(), 0); |
67 | } |
68 | |
69 | static double propertyValueDouble(JSContextRef context, JSObjectRef object, const char* propertyName) |
70 | { |
71 | JSValueRef value = propertyValue(context, object, propertyName); |
72 | if (!value) |
73 | return 0; |
74 | return JSValueToNumber(context, value, 0); |
75 | } |
76 | |
77 | static int propertyValueInt(JSContextRef context, JSObjectRef object, const char* propertyName) |
78 | { |
79 | return static_cast<int>(propertyValueDouble(context, object, propertyName)); |
80 | } |
81 | |
82 | static double numericWindowPropertyValue(WKBundleFrameRef frame, const char* propertyName) |
83 | { |
84 | JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame); |
85 | return propertyValueDouble(context, JSContextGetGlobalObject(context), propertyName); |
86 | } |
87 | |
88 | static WTF::String dumpPath(JSGlobalContextRef context, JSObjectRef nodeValue) |
89 | { |
90 | JSValueRef nodeNameValue = propertyValue(context, nodeValue, "nodeName" ); |
91 | auto jsStringNodeName = adopt(JSValueToStringCopy(context, nodeNameValue, 0)); |
92 | WKRetainPtr<WKStringRef> nodeName = toWK(jsStringNodeName); |
93 | |
94 | JSValueRef parentNode = propertyValue(context, nodeValue, "parentNode" ); |
95 | |
96 | StringBuilder stringBuilder; |
97 | stringBuilder.append(toWTFString(nodeName)); |
98 | |
99 | if (parentNode && JSValueIsObject(context, parentNode)) { |
100 | stringBuilder.appendLiteral(" > " ); |
101 | stringBuilder.append(dumpPath(context, (JSObjectRef)parentNode)); |
102 | } |
103 | |
104 | return stringBuilder.toString(); |
105 | } |
106 | |
107 | static WTF::String dumpPath(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleNodeHandleRef node) |
108 | { |
109 | if (!node) |
110 | return "(null)" ; |
111 | |
112 | WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); |
113 | |
114 | JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world); |
115 | JSValueRef nodeValue = WKBundleFrameGetJavaScriptWrapperForNodeForWorld(frame, node, world); |
116 | ASSERT(JSValueIsObject(context, nodeValue)); |
117 | JSObjectRef nodeObject = (JSObjectRef)nodeValue; |
118 | |
119 | return dumpPath(context, nodeObject); |
120 | } |
121 | |
122 | static WTF::String rangeToStr(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleRangeHandleRef rangeRef) |
123 | { |
124 | if (!rangeRef) |
125 | return "(null)" ; |
126 | |
127 | WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); |
128 | |
129 | JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world); |
130 | JSValueRef rangeValue = WKBundleFrameGetJavaScriptWrapperForRangeForWorld(frame, rangeRef, world); |
131 | ASSERT(JSValueIsObject(context, rangeValue)); |
132 | JSObjectRef rangeObject = (JSObjectRef)rangeValue; |
133 | |
134 | JSValueRef startNodeValue = propertyValue(context, rangeObject, "startContainer" ); |
135 | ASSERT(JSValueIsObject(context, startNodeValue)); |
136 | JSObjectRef startNodeObject = (JSObjectRef)startNodeValue; |
137 | |
138 | JSValueRef endNodeValue = propertyValue(context, rangeObject, "endContainer" ); |
139 | ASSERT(JSValueIsObject(context, endNodeValue)); |
140 | JSObjectRef endNodeObject = (JSObjectRef)endNodeValue; |
141 | |
142 | int startOffset = propertyValueInt(context, rangeObject, "startOffset" ); |
143 | int endOffset = propertyValueInt(context, rangeObject, "endOffset" ); |
144 | |
145 | StringBuilder stringBuilder; |
146 | stringBuilder.appendLiteral("range from " ); |
147 | stringBuilder.appendNumber(startOffset); |
148 | stringBuilder.appendLiteral(" of " ); |
149 | stringBuilder.append(dumpPath(context, startNodeObject)); |
150 | stringBuilder.appendLiteral(" to " ); |
151 | stringBuilder.appendNumber(endOffset); |
152 | stringBuilder.appendLiteral(" of " ); |
153 | stringBuilder.append(dumpPath(context, endNodeObject)); |
154 | return stringBuilder.toString(); |
155 | } |
156 | |
157 | static WKRetainPtr<WKStringRef> NavigationTypeToString(WKFrameNavigationType type) |
158 | { |
159 | switch (type) { |
160 | case kWKFrameNavigationTypeLinkClicked: |
161 | return adoptWK(WKStringCreateWithUTF8CString("link clicked" )); |
162 | case kWKFrameNavigationTypeFormSubmitted: |
163 | return adoptWK(WKStringCreateWithUTF8CString("form submitted" )); |
164 | case kWKFrameNavigationTypeBackForward: |
165 | return adoptWK(WKStringCreateWithUTF8CString("back/forward" )); |
166 | case kWKFrameNavigationTypeReload: |
167 | return adoptWK(WKStringCreateWithUTF8CString("reload" )); |
168 | case kWKFrameNavigationTypeFormResubmitted: |
169 | return adoptWK(WKStringCreateWithUTF8CString("form resubmitted" )); |
170 | case kWKFrameNavigationTypeOther: |
171 | return adoptWK(WKStringCreateWithUTF8CString("other" )); |
172 | } |
173 | return adoptWK(WKStringCreateWithUTF8CString("illegal value" )); |
174 | } |
175 | |
176 | static WTF::String styleDecToStr(WKBundleCSSStyleDeclarationRef style) |
177 | { |
178 | // DumpRenderTree calls -[DOMCSSStyleDeclaration description], which just dumps class name and object address. |
179 | // No existing tests actually hit this code path at the time of this writing, because WebCore doesn't call |
180 | // the editing client if the styling operation source is CommandFromDOM or CommandFromDOMWithUserInterface. |
181 | StringBuilder stringBuilder; |
182 | stringBuilder.appendLiteral("<DOMCSSStyleDeclaration ADDRESS>" ); |
183 | return stringBuilder.toString(); |
184 | } |
185 | |
186 | static WTF::String securityOriginToStr(WKSecurityOriginRef origin) |
187 | { |
188 | StringBuilder stringBuilder; |
189 | stringBuilder.append('{'); |
190 | stringBuilder.append(toWTFString(adoptWK(WKSecurityOriginCopyProtocol(origin)))); |
191 | stringBuilder.appendLiteral(", " ); |
192 | stringBuilder.append(toWTFString(adoptWK(WKSecurityOriginCopyHost(origin)))); |
193 | stringBuilder.appendLiteral(", " ); |
194 | stringBuilder.appendNumber(WKSecurityOriginGetPort(origin)); |
195 | stringBuilder.append('}'); |
196 | |
197 | return stringBuilder.toString(); |
198 | } |
199 | |
200 | static WTF::String frameToStr(WKBundleFrameRef frame) |
201 | { |
202 | WKRetainPtr<WKStringRef> name = adoptWK(WKBundleFrameCopyName(frame)); |
203 | StringBuilder stringBuilder; |
204 | if (WKBundleFrameIsMainFrame(frame)) { |
205 | if (!WKStringIsEmpty(name.get())) { |
206 | stringBuilder.appendLiteral("main frame \"" ); |
207 | stringBuilder.append(toWTFString(name)); |
208 | stringBuilder.append('"'); |
209 | } else |
210 | stringBuilder.appendLiteral("main frame" ); |
211 | } else { |
212 | if (!WKStringIsEmpty(name.get())) { |
213 | stringBuilder.appendLiteral("frame \"" ); |
214 | stringBuilder.append(toWTFString(name)); |
215 | stringBuilder.append('"'); |
216 | } |
217 | else |
218 | stringBuilder.appendLiteral("frame (anonymous)" ); |
219 | } |
220 | |
221 | return stringBuilder.toString(); |
222 | } |
223 | |
224 | static inline bool isLocalFileScheme(WKStringRef scheme) |
225 | { |
226 | return WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "file" ); |
227 | } |
228 | |
229 | static const char divider = '/'; |
230 | |
231 | static inline WTF::String pathSuitableForTestResult(WKURLRef fileUrl) |
232 | { |
233 | if (!fileUrl) |
234 | return "(null)" ; |
235 | |
236 | WKRetainPtr<WKStringRef> schemeString = adoptWK(WKURLCopyScheme(fileUrl)); |
237 | if (!isLocalFileScheme(schemeString.get())) |
238 | return toWTFString(adoptWK(WKURLCopyString(fileUrl))); |
239 | |
240 | WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page()); |
241 | WKRetainPtr<WKURLRef> mainFrameURL = adoptWK(WKBundleFrameCopyURL(mainFrame)); |
242 | if (!mainFrameURL) |
243 | mainFrameURL = adoptWK(WKBundleFrameCopyProvisionalURL(mainFrame)); |
244 | |
245 | String pathString = toWTFString(adoptWK(WKURLCopyPath(fileUrl))); |
246 | String mainFrameURLPathString = toWTFString(adoptWK(WKURLCopyPath(mainFrameURL.get()))); |
247 | String basePath = mainFrameURLPathString.substring(0, mainFrameURLPathString.reverseFind(divider) + 1); |
248 | |
249 | if (!basePath.isEmpty() && pathString.startsWith(basePath)) |
250 | return pathString.substring(basePath.length()); |
251 | return toWTFString(adoptWK(WKURLCopyLastPathComponent(fileUrl))); // We lose some information here, but it's better than exposing a full path, which is always machine specific. |
252 | } |
253 | |
254 | static HashMap<uint64_t, String>& assignedUrlsCache() |
255 | { |
256 | static NeverDestroyed<HashMap<uint64_t, String>> cache; |
257 | return cache.get(); |
258 | } |
259 | |
260 | static inline void dumpResourceURL(uint64_t identifier, StringBuilder& stringBuilder) |
261 | { |
262 | if (assignedUrlsCache().contains(identifier)) |
263 | stringBuilder.append(assignedUrlsCache().get(identifier)); |
264 | else |
265 | stringBuilder.appendLiteral("<unknown>" ); |
266 | } |
267 | |
268 | InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page) |
269 | : m_page(page) |
270 | , m_world(adoptWK(WKBundleScriptWorldCreateWorld())) |
271 | { |
272 | WKBundlePageLoaderClientV9 loaderClient = { |
273 | { 9, this }, |
274 | didStartProvisionalLoadForFrame, |
275 | didReceiveServerRedirectForProvisionalLoadForFrame, |
276 | didFailProvisionalLoadWithErrorForFrame, |
277 | didCommitLoadForFrame, |
278 | didFinishDocumentLoadForFrame, |
279 | didFinishLoadForFrame, |
280 | didFailLoadWithErrorForFrame, |
281 | didSameDocumentNavigationForFrame, |
282 | didReceiveTitleForFrame, |
283 | 0, // didFirstLayoutForFrame |
284 | 0, // didFirstVisuallyNonEmptyLayoutForFrame |
285 | 0, // didRemoveFrameFromHierarchy |
286 | didDisplayInsecureContentForFrame, |
287 | didRunInsecureContentForFrame, |
288 | didClearWindowForFrame, |
289 | didCancelClientRedirectForFrame, |
290 | willPerformClientRedirectForFrame, |
291 | didHandleOnloadEventsForFrame, |
292 | 0, // didLayoutForFrame |
293 | 0, // didNewFirstVisuallyNonEmptyLayout_unavailable |
294 | didDetectXSSForFrame, |
295 | 0, // shouldGoToBackForwardListItem |
296 | 0, // didCreateGlobalObjectForFrame |
297 | 0, // willDisconnectDOMWindowExtensionFromGlobalObject |
298 | 0, // didReconnectDOMWindowExtensionToGlobalObject |
299 | 0, // willDestroyGlobalObjectForDOMWindowExtension |
300 | didFinishProgress, // didFinishProgress |
301 | 0, // shouldForceUniversalAccessFromLocalURL |
302 | 0, // didReceiveIntentForFrame |
303 | 0, // registerIntentServiceForFrame |
304 | 0, // didLayout |
305 | 0, // featuresUsedInPage |
306 | 0, // willLoadURLRequest |
307 | 0, // willLoadDataRequest |
308 | 0, // willDestroyFrame_unavailable |
309 | 0, // userAgentForURL |
310 | willInjectUserScriptForFrame |
311 | }; |
312 | WKBundlePageSetPageLoaderClient(m_page, &loaderClient.base); |
313 | |
314 | WKBundlePageResourceLoadClientV1 resourceLoadClient = { |
315 | { 1, this }, |
316 | didInitiateLoadForResource, |
317 | willSendRequestForFrame, |
318 | didReceiveResponseForResource, |
319 | didReceiveContentLengthForResource, |
320 | didFinishLoadForResource, |
321 | didFailLoadForResource, |
322 | shouldCacheResponse, |
323 | 0 // shouldUseCredentialStorage |
324 | }; |
325 | WKBundlePageSetResourceLoadClient(m_page, &resourceLoadClient.base); |
326 | |
327 | WKBundlePagePolicyClientV0 policyClient = { |
328 | { 0, this }, |
329 | decidePolicyForNavigationAction, |
330 | decidePolicyForNewWindowAction, |
331 | decidePolicyForResponse, |
332 | unableToImplementPolicy |
333 | }; |
334 | WKBundlePageSetPolicyClient(m_page, &policyClient.base); |
335 | |
336 | WKBundlePageUIClientV2 uiClient = { |
337 | { 2, this }, |
338 | willAddMessageToConsole, |
339 | willSetStatusbarText, |
340 | willRunJavaScriptAlert, |
341 | willRunJavaScriptConfirm, |
342 | willRunJavaScriptPrompt, |
343 | 0, /*mouseDidMoveOverElement*/ |
344 | 0, /*pageDidScroll*/ |
345 | 0, /*paintCustomOverhangArea*/ |
346 | 0, /*shouldGenerateFileForUpload*/ |
347 | 0, /*generateFileForUpload*/ |
348 | 0, /*shouldRubberBandInDirection*/ |
349 | 0, /*statusBarIsVisible*/ |
350 | 0, /*menuBarIsVisible*/ |
351 | 0, /*toolbarsAreVisible*/ |
352 | didReachApplicationCacheOriginQuota, |
353 | didExceedDatabaseQuota, |
354 | 0, /*plugInStartLabelTitle*/ |
355 | 0, /*plugInStartLabelSubtitle*/ |
356 | 0, /*plugInExtraStyleSheet*/ |
357 | 0, /*plugInExtraScript*/ |
358 | }; |
359 | WKBundlePageSetUIClient(m_page, &uiClient.base); |
360 | |
361 | WKBundlePageEditorClientV1 editorClient = { |
362 | { 1, this }, |
363 | shouldBeginEditing, |
364 | shouldEndEditing, |
365 | shouldInsertNode, |
366 | shouldInsertText, |
367 | shouldDeleteRange, |
368 | shouldChangeSelectedRange, |
369 | shouldApplyStyle, |
370 | didBeginEditing, |
371 | didEndEditing, |
372 | didChange, |
373 | didChangeSelection, |
374 | 0, /* willWriteToPasteboard */ |
375 | 0, /* getPasteboardDataForRange */ |
376 | 0, /* didWriteToPasteboard */ |
377 | 0, /* performTwoStepDrop */ |
378 | }; |
379 | WKBundlePageSetEditorClient(m_page, &editorClient.base); |
380 | |
381 | #if ENABLE(FULLSCREEN_API) |
382 | WKBundlePageFullScreenClientV1 fullScreenClient = { |
383 | { 1, this }, |
384 | supportsFullScreen, |
385 | enterFullScreenForElement, |
386 | exitFullScreenForElement, |
387 | beganEnterFullScreen, |
388 | beganExitFullScreen, |
389 | closeFullScreen, |
390 | }; |
391 | WKBundlePageSetFullScreenClient(m_page, &fullScreenClient.base); |
392 | #endif |
393 | } |
394 | |
395 | InjectedBundlePage::~InjectedBundlePage() |
396 | { |
397 | } |
398 | |
399 | void InjectedBundlePage::stopLoading() |
400 | { |
401 | WKBundlePageStopLoading(m_page); |
402 | } |
403 | |
404 | void InjectedBundlePage::prepare() |
405 | { |
406 | WKBundlePageClearMainFrameName(m_page); |
407 | |
408 | WKBundlePageSetPageZoomFactor(m_page, 1); |
409 | WKBundlePageSetTextZoomFactor(m_page, 1); |
410 | |
411 | WKPoint origin = { 0, 0 }; |
412 | WKBundlePageSetScaleAtOrigin(m_page, 1, origin); |
413 | |
414 | WKBundleClearHistoryForTesting(m_page); |
415 | |
416 | WKBundleFrameClearOpener(WKBundlePageGetMainFrame(m_page)); |
417 | |
418 | WKBundlePageSetTracksRepaints(m_page, false); |
419 | |
420 | // Force consistent "responsive" behavior for WebPage::eventThrottlingDelay() for testing. Tests can override via internals. |
421 | WKEventThrottlingBehavior behavior = kWKEventThrottlingBehaviorResponsive; |
422 | WKBundlePageSetEventThrottlingBehaviorOverride(m_page, &behavior); |
423 | } |
424 | |
425 | void InjectedBundlePage::resetAfterTest() |
426 | { |
427 | WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page); |
428 | |
429 | // WebKit currently doesn't reset focus even when navigating to a new page. This may or may not be a bug |
430 | // (see <https://bugs.webkit.org/show_bug.cgi?id=138334>), however for tests, we want to start each one with a clean state. |
431 | WKBundleFrameFocus(frame); |
432 | |
433 | JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame); |
434 | WebCoreTestSupport::resetInternalsObject(context); |
435 | assignedUrlsCache().clear(); |
436 | |
437 | // User scripts need to be removed after the test and before loading about:blank, as otherwise they would run in about:blank, and potentially leak results into a subsequest test. |
438 | WKBundlePageRemoveAllUserContent(m_page); |
439 | |
440 | uninstallFakeHelvetica(); |
441 | |
442 | InjectedBundle::singleton().resetUserScriptInjectedCount(); |
443 | } |
444 | |
445 | // Loader Client Callbacks |
446 | |
447 | // String output must be identical to -[WebFrame _drt_descriptionSuitableForTestResult]. |
448 | static void dumpFrameDescriptionSuitableForTestResult(WKBundleFrameRef frame, StringBuilder& stringBuilder) |
449 | { |
450 | WKRetainPtr<WKStringRef> name = adoptWK(WKBundleFrameCopyName(frame)); |
451 | if (WKBundleFrameIsMainFrame(frame)) { |
452 | if (WKStringIsEmpty(name.get())) { |
453 | stringBuilder.appendLiteral("main frame" ); |
454 | return; |
455 | } |
456 | |
457 | stringBuilder.appendLiteral("main frame \"" ); |
458 | stringBuilder.append(toWTFString(name)); |
459 | stringBuilder.append('"'); |
460 | return; |
461 | } |
462 | |
463 | if (WKStringIsEmpty(name.get())) { |
464 | stringBuilder.appendLiteral("frame (anonymous)" ); |
465 | return; |
466 | } |
467 | |
468 | stringBuilder.appendLiteral("frame \"" ); |
469 | stringBuilder.append(toWTFString(name)); |
470 | stringBuilder.append('"'); |
471 | } |
472 | |
473 | static void dumpLoadEvent(WKBundleFrameRef frame, const char* eventName) |
474 | { |
475 | StringBuilder stringBuilder; |
476 | dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder); |
477 | stringBuilder.appendLiteral(" - " ); |
478 | stringBuilder.append(eventName); |
479 | stringBuilder.append('\n'); |
480 | InjectedBundle::singleton().outputText(stringBuilder.toString()); |
481 | } |
482 | |
483 | static inline void dumpRequestDescriptionSuitableForTestResult(WKURLRequestRef request, StringBuilder& stringBuilder) |
484 | { |
485 | WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request)); |
486 | WKRetainPtr<WKURLRef> firstParty = adoptWK(WKURLRequestCopyFirstPartyForCookies(request)); |
487 | WKRetainPtr<WKStringRef> httpMethod = adoptWK(WKURLRequestCopyHTTPMethod(request)); |
488 | |
489 | stringBuilder.appendLiteral("<NSURLRequest URL " ); |
490 | stringBuilder.append(pathSuitableForTestResult(url.get())); |
491 | stringBuilder.appendLiteral(", main document URL " ); |
492 | stringBuilder.append(pathSuitableForTestResult(firstParty.get())); |
493 | stringBuilder.appendLiteral(", http method " ); |
494 | |
495 | if (WKStringIsEmpty(httpMethod.get())) |
496 | stringBuilder.appendLiteral("(none)" ); |
497 | else |
498 | stringBuilder.append(toWTFString(httpMethod)); |
499 | |
500 | stringBuilder.append('>'); |
501 | } |
502 | |
503 | static inline void dumpResponseDescriptionSuitableForTestResult(WKURLResponseRef response, StringBuilder& stringBuilder, bool = false) |
504 | { |
505 | WKRetainPtr<WKURLRef> url = adoptWK(WKURLResponseCopyURL(response)); |
506 | if (!url) { |
507 | stringBuilder.appendLiteral("(null)" ); |
508 | return; |
509 | } |
510 | stringBuilder.appendLiteral("<NSURLResponse " ); |
511 | stringBuilder.append(pathSuitableForTestResult(url.get())); |
512 | stringBuilder.appendLiteral(", http status code " ); |
513 | stringBuilder.appendNumber(WKURLResponseHTTPStatusCode(response)); |
514 | |
515 | if (shouldDumpResponseHeaders) { |
516 | stringBuilder.appendLiteral(", " ); |
517 | stringBuilder.appendNumber(InjectedBundlePage::responseHeaderCount(response)); |
518 | stringBuilder.appendLiteral(" headers" ); |
519 | } |
520 | stringBuilder.append('>'); |
521 | } |
522 | |
523 | #if !PLATFORM(COCOA) |
524 | // FIXME: Implement this for non cocoa ports. |
525 | // [GTK][WPE] https://bugs.webkit.org/show_bug.cgi?id=184295 |
526 | uint64_t InjectedBundlePage::(WKURLResponseRef response) |
527 | { |
528 | return 0; |
529 | } |
530 | #endif |
531 | |
532 | static inline void dumpErrorDescriptionSuitableForTestResult(WKErrorRef error, StringBuilder& stringBuilder) |
533 | { |
534 | WKRetainPtr<WKStringRef> errorDomain = adoptWK(WKErrorCopyDomain(error)); |
535 | int errorCode = WKErrorGetErrorCode(error); |
536 | |
537 | // We need to do some error mapping here to match the test expectations (Mac error names are expected). |
538 | if (WKStringIsEqualToUTF8CString(errorDomain.get(), "WebKitNetworkError" )) { |
539 | errorDomain = adoptWK(WKStringCreateWithUTF8CString("NSURLErrorDomain" )); |
540 | errorCode = -999; |
541 | } |
542 | |
543 | if (WKStringIsEqualToUTF8CString(errorDomain.get(), "WebKitPolicyError" )) |
544 | errorDomain = adoptWK(WKStringCreateWithUTF8CString("WebKitErrorDomain" )); |
545 | |
546 | stringBuilder.appendLiteral("<NSError domain " ); |
547 | stringBuilder.append(toWTFString(errorDomain)); |
548 | stringBuilder.appendLiteral(", code " ); |
549 | stringBuilder.appendNumber(errorCode); |
550 | |
551 | WKRetainPtr<WKURLRef> url = adoptWK(WKErrorCopyFailingURL(error)); |
552 | if (url.get()) { |
553 | WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(url.get())); |
554 | stringBuilder.appendLiteral(", failing URL \"" ); |
555 | stringBuilder.append(toWTFString(urlString)); |
556 | stringBuilder.append('"'); |
557 | } |
558 | |
559 | stringBuilder.append('>'); |
560 | } |
561 | |
562 | void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo) |
563 | { |
564 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didStartProvisionalLoadForFrame(frame); |
565 | } |
566 | |
567 | void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo) |
568 | { |
569 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveServerRedirectForProvisionalLoadForFrame(frame); |
570 | } |
571 | |
572 | void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef*, const void *clientInfo) |
573 | { |
574 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailProvisionalLoadWithErrorForFrame(frame, error); |
575 | } |
576 | |
577 | void InjectedBundlePage::didCommitLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo) |
578 | { |
579 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(frame); |
580 | } |
581 | |
582 | void InjectedBundlePage::didFinishLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo) |
583 | { |
584 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(frame); |
585 | } |
586 | |
587 | void InjectedBundlePage::didFinishProgress(WKBundlePageRef, const void *clientInfo) |
588 | { |
589 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishProgress(); |
590 | } |
591 | |
592 | void InjectedBundlePage::willInjectUserScriptForFrame(WKBundlePageRef, WKBundleFrameRef, WKBundleScriptWorldRef, const void* clientInfo) |
593 | { |
594 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willInjectUserScriptForFrame(); |
595 | } |
596 | |
597 | void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo) |
598 | { |
599 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishDocumentLoadForFrame(frame); |
600 | } |
601 | |
602 | void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef*, const void *clientInfo) |
603 | { |
604 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailLoadWithErrorForFrame(frame, error); |
605 | } |
606 | |
607 | void InjectedBundlePage::didReceiveTitleForFrame(WKBundlePageRef page, WKStringRef title, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo) |
608 | { |
609 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveTitleForFrame(title, frame); |
610 | } |
611 | |
612 | void InjectedBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void *clientInfo) |
613 | { |
614 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didClearWindowForFrame(frame, world); |
615 | } |
616 | |
617 | void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo) |
618 | { |
619 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCancelClientRedirectForFrame(frame); |
620 | } |
621 | |
622 | void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKURLRef url, double delay, double date, const void* clientInfo) |
623 | { |
624 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willPerformClientRedirectForFrame(page, frame, url, delay, date); |
625 | } |
626 | |
627 | void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef*, const void* clientInfo) |
628 | { |
629 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didSameDocumentNavigationForFrame(frame, type); |
630 | } |
631 | |
632 | void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo) |
633 | { |
634 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didHandleOnloadEventsForFrame(frame); |
635 | } |
636 | |
637 | void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo) |
638 | { |
639 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didDisplayInsecureContentForFrame(frame); |
640 | } |
641 | |
642 | void InjectedBundlePage::didDetectXSSForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo) |
643 | { |
644 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didDetectXSSForFrame(frame); |
645 | } |
646 | |
647 | void InjectedBundlePage::didRunInsecureContentForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo) |
648 | { |
649 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didRunInsecureContentForFrame(frame); |
650 | } |
651 | |
652 | void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, bool pageLoadIsProvisional, const void* clientInfo) |
653 | { |
654 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didInitiateLoadForResource(page, frame, identifier, request, pageLoadIsProvisional); |
655 | } |
656 | |
657 | WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, WKURLResponseRef redirectResponse, const void* clientInfo) |
658 | { |
659 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSendRequestForFrame(page, frame, identifier, request, redirectResponse); |
660 | } |
661 | |
662 | void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLResponseRef response, const void* clientInfo) |
663 | { |
664 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveResponseForResource(page, frame, identifier, response); |
665 | } |
666 | |
667 | void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, uint64_t length, const void* clientInfo) |
668 | { |
669 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveContentLengthForResource(page, frame, identifier, length); |
670 | } |
671 | |
672 | void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, const void* clientInfo) |
673 | { |
674 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForResource(page, frame, identifier); |
675 | } |
676 | |
677 | void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKErrorRef error, const void* clientInfo) |
678 | { |
679 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailLoadForResource(page, frame, identifier, error); |
680 | } |
681 | |
682 | bool InjectedBundlePage::shouldCacheResponse(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, const void* clientInfo) |
683 | { |
684 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldCacheResponse(page, frame, identifier); |
685 | } |
686 | |
687 | void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame) |
688 | { |
689 | auto& injectedBundle = InjectedBundle::singleton(); |
690 | if (!injectedBundle.isTestRunning()) |
691 | return; |
692 | |
693 | if (!injectedBundle.testRunner()->testURL()) { |
694 | WKRetainPtr<WKURLRef> testURL = adoptWK(WKBundleFrameCopyProvisionalURL(frame)); |
695 | injectedBundle.testRunner()->setTestURL(testURL.get()); |
696 | } |
697 | |
698 | platformDidStartProvisionalLoadForFrame(frame); |
699 | |
700 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
701 | dumpLoadEvent(frame, "didStartProvisionalLoadForFrame" ); |
702 | |
703 | if (!injectedBundle.topLoadingFrame()) |
704 | injectedBundle.setTopLoadingFrame(frame); |
705 | |
706 | if (injectedBundle.testRunner()->shouldStopProvisionalFrameLoads()) |
707 | dumpLoadEvent(frame, "stopping load in didStartProvisionalLoadForFrame callback" ); |
708 | } |
709 | |
710 | void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame) |
711 | { |
712 | auto& injectedBundle = InjectedBundle::singleton(); |
713 | if (!injectedBundle.isTestRunning()) |
714 | return; |
715 | |
716 | if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
717 | return; |
718 | |
719 | dumpLoadEvent(frame, "didReceiveServerRedirectForProvisionalLoadForFrame" ); |
720 | } |
721 | |
722 | void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef error) |
723 | { |
724 | auto& injectedBundle = InjectedBundle::singleton(); |
725 | if (!injectedBundle.isTestRunning()) |
726 | return; |
727 | |
728 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) { |
729 | dumpLoadEvent(frame, "didFailProvisionalLoadWithError" ); |
730 | auto code = WKErrorGetErrorCode(error); |
731 | if (code == kWKErrorCodeCannotShowURL) |
732 | dumpLoadEvent(frame, "(ErrorCodeCannotShowURL)" ); |
733 | else if (code == kWKErrorCodeFrameLoadBlockedByContentBlocker) |
734 | dumpLoadEvent(frame, "(kWKErrorCodeFrameLoadBlockedByContentBlocker)" ); |
735 | } |
736 | |
737 | frameDidChangeLocation(frame); |
738 | } |
739 | |
740 | void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame) |
741 | { |
742 | auto& injectedBundle = InjectedBundle::singleton(); |
743 | if (!injectedBundle.isTestRunning()) |
744 | return; |
745 | |
746 | if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
747 | return; |
748 | |
749 | dumpLoadEvent(frame, "didCommitLoadForFrame" ); |
750 | } |
751 | |
752 | void InjectedBundlePage::didFinishProgress() |
753 | { |
754 | auto& injectedBundle = InjectedBundle::singleton(); |
755 | if (!injectedBundle.isTestRunning()) |
756 | return; |
757 | |
758 | if (!injectedBundle.testRunner()->shouldDumpProgressFinishedCallback()) |
759 | return; |
760 | |
761 | injectedBundle.outputText("postProgressFinishedNotification\n" ); |
762 | } |
763 | |
764 | void InjectedBundlePage::willInjectUserScriptForFrame() |
765 | { |
766 | InjectedBundle::singleton().increaseUserScriptInjectedCount(); |
767 | } |
768 | |
769 | enum FrameNamePolicy { ShouldNotIncludeFrameName, ShouldIncludeFrameName }; |
770 | |
771 | static void dumpFrameScrollPosition(WKBundleFrameRef frame, StringBuilder& stringBuilder, FrameNamePolicy shouldIncludeFrameName = ShouldNotIncludeFrameName) |
772 | { |
773 | double x = numericWindowPropertyValue(frame, "pageXOffset" ); |
774 | double y = numericWindowPropertyValue(frame, "pageYOffset" ); |
775 | if (fabs(x) <= 0.00000001 && fabs(y) <= 0.00000001) |
776 | return; |
777 | |
778 | if (shouldIncludeFrameName) { |
779 | WKRetainPtr<WKStringRef> name = adoptWK(WKBundleFrameCopyName(frame)); |
780 | stringBuilder.appendLiteral("frame '" ); |
781 | stringBuilder.append(toWTFString(name)); |
782 | stringBuilder.appendLiteral("' " ); |
783 | } |
784 | stringBuilder.appendLiteral("scrolled to " ); |
785 | stringBuilder.appendECMAScriptNumber(x); |
786 | stringBuilder.append(','); |
787 | stringBuilder.appendECMAScriptNumber(y); |
788 | stringBuilder.append('\n'); |
789 | } |
790 | |
791 | static void dumpDescendantFrameScrollPositions(WKBundleFrameRef frame, StringBuilder& stringBuilder) |
792 | { |
793 | WKRetainPtr<WKArrayRef> childFrames = adoptWK(WKBundleFrameCopyChildFrames(frame)); |
794 | size_t size = WKArrayGetSize(childFrames.get()); |
795 | for (size_t i = 0; i < size; ++i) { |
796 | WKBundleFrameRef subframe = static_cast<WKBundleFrameRef>(WKArrayGetItemAtIndex(childFrames.get(), i)); |
797 | dumpFrameScrollPosition(subframe, stringBuilder, ShouldIncludeFrameName); |
798 | dumpDescendantFrameScrollPositions(subframe, stringBuilder); |
799 | } |
800 | } |
801 | |
802 | void InjectedBundlePage::dumpAllFrameScrollPositions(StringBuilder& stringBuilder) |
803 | { |
804 | WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page); |
805 | dumpFrameScrollPosition(frame, stringBuilder); |
806 | dumpDescendantFrameScrollPositions(frame, stringBuilder); |
807 | } |
808 | |
809 | static JSRetainPtr<JSStringRef> toJS(const char* string) |
810 | { |
811 | return adopt(JSStringCreateWithUTF8CString(string)); |
812 | } |
813 | |
814 | static bool hasDocumentElement(WKBundleFrameRef frame) |
815 | { |
816 | JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame); |
817 | JSObjectRef globalObject = JSContextGetGlobalObject(context); |
818 | |
819 | JSValueRef documentValue = JSObjectGetProperty(context, globalObject, toJS("document" ).get(), 0); |
820 | if (!documentValue) |
821 | return false; |
822 | |
823 | ASSERT(JSValueIsObject(context, documentValue)); |
824 | JSObjectRef document = JSValueToObject(context, documentValue, 0); |
825 | |
826 | JSValueRef documentElementValue = JSObjectGetProperty(context, document, toJS("documentElement" ).get(), 0); |
827 | if (!documentElementValue) |
828 | return false; |
829 | |
830 | return JSValueToBoolean(context, documentElementValue); |
831 | } |
832 | |
833 | static void dumpFrameText(WKBundleFrameRef frame, StringBuilder& stringBuilder) |
834 | { |
835 | // If the frame doesn't have a document element, its inner text will be an empty string, so |
836 | // we'll end up just appending a single newline below. But DumpRenderTree doesn't append |
837 | // anything in this case, so we shouldn't either. |
838 | if (!hasDocumentElement(frame)) |
839 | return; |
840 | |
841 | WKRetainPtr<WKStringRef> text = adoptWK(WKBundleFrameCopyInnerText(frame)); |
842 | stringBuilder.append(toWTFString(text)); |
843 | stringBuilder.append('\n'); |
844 | } |
845 | |
846 | static void dumpDescendantFramesText(WKBundleFrameRef frame, StringBuilder& stringBuilder) |
847 | { |
848 | WKRetainPtr<WKArrayRef> childFrames = adoptWK(WKBundleFrameCopyChildFrames(frame)); |
849 | size_t size = WKArrayGetSize(childFrames.get()); |
850 | for (size_t i = 0; i < size; ++i) { |
851 | WKBundleFrameRef subframe = static_cast<WKBundleFrameRef>(WKArrayGetItemAtIndex(childFrames.get(), i)); |
852 | WKRetainPtr<WKStringRef> subframeName = adoptWK(WKBundleFrameCopyName(subframe)); |
853 | |
854 | // DumpRenderTree ignores empty frames, so do the same thing here. |
855 | if (!hasDocumentElement(subframe)) |
856 | continue; |
857 | |
858 | stringBuilder.appendLiteral("\n--------\nFrame: '" ); |
859 | stringBuilder.append(toWTFString(subframeName)); |
860 | stringBuilder.appendLiteral("'\n--------\n" ); |
861 | |
862 | dumpFrameText(subframe, stringBuilder); |
863 | dumpDescendantFramesText(subframe, stringBuilder); |
864 | } |
865 | } |
866 | |
867 | void InjectedBundlePage::dumpAllFramesText(StringBuilder& stringBuilder) |
868 | { |
869 | WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page); |
870 | dumpFrameText(frame, stringBuilder); |
871 | dumpDescendantFramesText(frame, stringBuilder); |
872 | } |
873 | |
874 | |
875 | void InjectedBundlePage::dumpDOMAsWebArchive(WKBundleFrameRef frame, StringBuilder& stringBuilder) |
876 | { |
877 | #if USE(CF) && !PLATFORM(WIN_CAIRO) |
878 | WKRetainPtr<WKDataRef> wkData = adoptWK(WKBundleFrameCopyWebArchive(frame)); |
879 | RetainPtr<CFDataRef> cfData = adoptCF(CFDataCreate(0, WKDataGetBytes(wkData.get()), WKDataGetSize(wkData.get()))); |
880 | RetainPtr<CFStringRef> cfString = adoptCF(WebCoreTestSupport::createXMLStringFromWebArchiveData(cfData.get())); |
881 | stringBuilder.append(cfString.get()); |
882 | #endif |
883 | } |
884 | |
885 | void InjectedBundlePage::dump() |
886 | { |
887 | auto& injectedBundle = InjectedBundle::singleton(); |
888 | ASSERT(injectedBundle.isTestRunning()); |
889 | |
890 | // Force a paint before dumping. This matches DumpRenderTree on Windows. (DumpRenderTree on Mac |
891 | // does this at a slightly different time.) See <http://webkit.org/b/55469> for details. |
892 | WKBundlePageForceRepaint(m_page); |
893 | |
894 | WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page); |
895 | WKRetainPtr<WKURLRef> urlRef = adoptWK(WKBundleFrameCopyURL(frame)); |
896 | String url = toWTFString(adoptWK(WKURLCopyString(urlRef.get()))); |
897 | WKRetainPtr<WKStringRef> mimeType = adoptWK(WKBundleFrameCopyMIMETypeForResourceWithURL(frame, urlRef.get())); |
898 | if (url.find("dumpAsText/" ) != notFound || WKStringIsEqualToUTF8CString(mimeType.get(), "text/plain" )) |
899 | injectedBundle.testRunner()->dumpAsText(false); |
900 | |
901 | StringBuilder stringBuilder; |
902 | |
903 | switch (injectedBundle.testRunner()->whatToDump()) { |
904 | case WhatToDump::RenderTree: { |
905 | if (injectedBundle.testRunner()->isPrinting()) |
906 | stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentationForPrinting(m_page)).get())); |
907 | else |
908 | stringBuilder.append(toWTFString(adoptWK(WKBundlePageCopyRenderTreeExternalRepresentation(m_page, injectedBundle.testRunner()->renderTreeDumpOptions())).get())); |
909 | break; |
910 | } |
911 | case WhatToDump::MainFrameText: |
912 | dumpFrameText(WKBundlePageGetMainFrame(m_page), stringBuilder); |
913 | break; |
914 | case WhatToDump::AllFramesText: |
915 | dumpAllFramesText(stringBuilder); |
916 | break; |
917 | case WhatToDump::Audio: |
918 | break; |
919 | case WhatToDump::DOMAsWebArchive: |
920 | dumpDOMAsWebArchive(frame, stringBuilder); |
921 | break; |
922 | } |
923 | |
924 | if (injectedBundle.testRunner()->shouldDumpAllFrameScrollPositions()) |
925 | dumpAllFrameScrollPositions(stringBuilder); |
926 | else if (injectedBundle.testRunner()->shouldDumpMainFrameScrollPosition()) |
927 | dumpFrameScrollPosition(WKBundlePageGetMainFrame(m_page), stringBuilder); |
928 | |
929 | if (injectedBundle.testRunner()->shouldDumpBackForwardListsForAllWindows()) |
930 | injectedBundle.dumpBackForwardListsForAllPages(stringBuilder); |
931 | |
932 | if (injectedBundle.shouldDumpPixels() && injectedBundle.testRunner()->shouldDumpPixels()) { |
933 | bool shouldCreateSnapshot = injectedBundle.testRunner()->isPrinting(); |
934 | if (shouldCreateSnapshot) { |
935 | WKSnapshotOptions options = kWKSnapshotOptionsShareable; |
936 | WKRect snapshotRect = WKBundleFrameGetVisibleContentBounds(WKBundlePageGetMainFrame(m_page)); |
937 | |
938 | if (injectedBundle.testRunner()->isPrinting()) |
939 | options |= kWKSnapshotOptionsPrinting; |
940 | else { |
941 | options |= kWKSnapshotOptionsInViewCoordinates; |
942 | if (injectedBundle.testRunner()->shouldDumpSelectionRect()) |
943 | options |= kWKSnapshotOptionsPaintSelectionRectangle; |
944 | } |
945 | |
946 | injectedBundle.setPixelResult(adoptWK(WKBundlePageCreateSnapshotWithOptions(m_page, snapshotRect, options)).get()); |
947 | } else |
948 | injectedBundle.setPixelResultIsPending(true); |
949 | |
950 | if (WKBundlePageIsTrackingRepaints(m_page) && !injectedBundle.testRunner()->isPrinting()) |
951 | injectedBundle.setRepaintRects(adoptWK(WKBundlePageCopyTrackedRepaintRects(m_page)).get()); |
952 | } |
953 | |
954 | injectedBundle.outputText(stringBuilder.toString()); |
955 | injectedBundle.done(); |
956 | } |
957 | |
958 | void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame) |
959 | { |
960 | auto& injectedBundle = InjectedBundle::singleton(); |
961 | if (!injectedBundle.isTestRunning()) |
962 | return; |
963 | |
964 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
965 | dumpLoadEvent(frame, "didFinishLoadForFrame" ); |
966 | |
967 | frameDidChangeLocation(frame); |
968 | } |
969 | |
970 | void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef) |
971 | { |
972 | auto& injectedBundle = InjectedBundle::singleton(); |
973 | if (!injectedBundle.isTestRunning()) |
974 | return; |
975 | |
976 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
977 | dumpLoadEvent(frame, "didFailLoadWithError" ); |
978 | |
979 | frameDidChangeLocation(frame); |
980 | } |
981 | |
982 | void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef frame) |
983 | { |
984 | auto& injectedBundle = InjectedBundle::singleton(); |
985 | if (!injectedBundle.isTestRunning()) |
986 | return; |
987 | |
988 | StringBuilder stringBuilder; |
989 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) { |
990 | dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder); |
991 | stringBuilder.appendLiteral(" - didReceiveTitle: " ); |
992 | stringBuilder.append(toWTFString(title)); |
993 | stringBuilder.append('\n'); |
994 | } |
995 | |
996 | if (injectedBundle.testRunner()->shouldDumpTitleChanges()) { |
997 | stringBuilder.appendLiteral("TITLE CHANGED: '" ); |
998 | stringBuilder.append(toWTFString(title)); |
999 | stringBuilder.appendLiteral("'\n" ); |
1000 | } |
1001 | |
1002 | injectedBundle.outputText(stringBuilder.toString()); |
1003 | } |
1004 | |
1005 | void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundleScriptWorldRef world) |
1006 | { |
1007 | auto& injectedBundle = InjectedBundle::singleton(); |
1008 | if (!injectedBundle.isTestRunning()) |
1009 | return; |
1010 | |
1011 | JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world); |
1012 | JSObjectRef window = JSContextGetGlobalObject(context); |
1013 | |
1014 | if (WKBundleScriptWorldNormalWorld() != world) { |
1015 | JSObjectSetProperty(context, window, toJS("__worldID" ).get(), JSValueMakeNumber(context, TestRunner::worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0); |
1016 | return; |
1017 | } |
1018 | |
1019 | JSValueRef exception = nullptr; |
1020 | injectedBundle.testRunner()->makeWindowObject(context, window, &exception); |
1021 | injectedBundle.gcController()->makeWindowObject(context, window, &exception); |
1022 | injectedBundle.eventSendingController()->makeWindowObject(context, window, &exception); |
1023 | injectedBundle.textInputController()->makeWindowObject(context, window, &exception); |
1024 | #if HAVE(ACCESSIBILITY) |
1025 | injectedBundle.accessibilityController()->makeWindowObject(context, window, &exception); |
1026 | #endif |
1027 | |
1028 | WebCoreTestSupport::injectInternalsObject(context); |
1029 | } |
1030 | |
1031 | void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame) |
1032 | { |
1033 | auto& injectedBundle = InjectedBundle::singleton(); |
1034 | if (!injectedBundle.isTestRunning()) |
1035 | return; |
1036 | |
1037 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
1038 | dumpLoadEvent(frame, "didCancelClientRedirectForFrame" ); |
1039 | |
1040 | injectedBundle.testRunner()->setDidCancelClientRedirect(true); |
1041 | } |
1042 | |
1043 | void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef, WKBundleFrameRef frame, WKURLRef url, double delay, double date) |
1044 | { |
1045 | auto& injectedBundle = InjectedBundle::singleton(); |
1046 | if (!injectedBundle.isTestRunning()) |
1047 | return; |
1048 | |
1049 | if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
1050 | return; |
1051 | |
1052 | StringBuilder stringBuilder; |
1053 | dumpFrameDescriptionSuitableForTestResult(frame, stringBuilder); |
1054 | stringBuilder.appendLiteral(" - willPerformClientRedirectToURL: " ); |
1055 | stringBuilder.append(pathSuitableForTestResult(url)); |
1056 | stringBuilder.appendLiteral(" \n" ); |
1057 | injectedBundle.outputText(stringBuilder.toString()); |
1058 | } |
1059 | |
1060 | void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundleFrameRef frame, WKSameDocumentNavigationType type) |
1061 | { |
1062 | auto& injectedBundle = InjectedBundle::singleton(); |
1063 | if (!injectedBundle.isTestRunning()) |
1064 | return; |
1065 | |
1066 | if (!injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
1067 | return; |
1068 | |
1069 | if (type != kWKSameDocumentNavigationAnchorNavigation) |
1070 | return; |
1071 | |
1072 | dumpLoadEvent(frame, "didChangeLocationWithinPageForFrame" ); |
1073 | } |
1074 | |
1075 | void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame) |
1076 | { |
1077 | auto& injectedBundle = InjectedBundle::singleton(); |
1078 | if (!injectedBundle.isTestRunning()) |
1079 | return; |
1080 | |
1081 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
1082 | dumpLoadEvent(frame, "didFinishDocumentLoadForFrame" ); |
1083 | |
1084 | unsigned pendingFrameUnloadEvents = WKBundleFrameGetPendingUnloadCount(frame); |
1085 | if (pendingFrameUnloadEvents) { |
1086 | StringBuilder stringBuilder; |
1087 | stringBuilder.append(frameToStr(frame)); |
1088 | stringBuilder.appendLiteral(" - has " ); |
1089 | stringBuilder.appendNumber(pendingFrameUnloadEvents); |
1090 | stringBuilder.appendLiteral(" onunload handler(s)\n" ); |
1091 | injectedBundle.outputText(stringBuilder.toString()); |
1092 | } |
1093 | } |
1094 | |
1095 | void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundleFrameRef frame) |
1096 | { |
1097 | auto& injectedBundle = InjectedBundle::singleton(); |
1098 | if (!injectedBundle.isTestRunning()) |
1099 | return; |
1100 | |
1101 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
1102 | dumpLoadEvent(frame, "didHandleOnloadEventsForFrame" ); |
1103 | } |
1104 | |
1105 | void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef) |
1106 | { |
1107 | auto& injectedBundle = InjectedBundle::singleton(); |
1108 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
1109 | injectedBundle.outputText("didDisplayInsecureContent\n" ); |
1110 | } |
1111 | |
1112 | void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef) |
1113 | { |
1114 | auto& injectedBundle = InjectedBundle::singleton(); |
1115 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
1116 | injectedBundle.outputText("didRunInsecureContent\n" ); |
1117 | } |
1118 | |
1119 | void InjectedBundlePage::didDetectXSSForFrame(WKBundleFrameRef) |
1120 | { |
1121 | auto& injectedBundle = InjectedBundle::singleton(); |
1122 | if (injectedBundle.testRunner()->shouldDumpFrameLoadCallbacks()) |
1123 | injectedBundle.outputText("didDetectXSS\n" ); |
1124 | } |
1125 | |
1126 | void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef request, bool) |
1127 | { |
1128 | if (!InjectedBundle::singleton().isTestRunning()) |
1129 | return; |
1130 | |
1131 | WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request)); |
1132 | assignedUrlsCache().add(identifier, pathSuitableForTestResult(url.get())); |
1133 | } |
1134 | |
1135 | // Resource Load Client Callbacks |
1136 | |
1137 | static inline bool isLocalHost(WKStringRef host) |
1138 | { |
1139 | return WKStringIsEqualToUTF8CString(host, "127.0.0.1" ) || WKStringIsEqualToUTF8CString(host, "localhost" ); |
1140 | } |
1141 | |
1142 | static inline bool isHTTPOrHTTPSScheme(WKStringRef scheme) |
1143 | { |
1144 | return WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "http" ) || WKStringIsEqualToUTF8CStringIgnoringCase(scheme, "https" ); |
1145 | } |
1146 | |
1147 | static inline bool isAllowedHost(WKStringRef host) |
1148 | { |
1149 | return InjectedBundle::singleton().isAllowedHost(host); |
1150 | } |
1151 | |
1152 | WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, WKURLResponseRef response) |
1153 | { |
1154 | auto& injectedBundle = InjectedBundle::singleton(); |
1155 | if (injectedBundle.isTestRunning() |
1156 | && injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) { |
1157 | StringBuilder stringBuilder; |
1158 | dumpResourceURL(identifier, stringBuilder); |
1159 | stringBuilder.appendLiteral(" - willSendRequest " ); |
1160 | dumpRequestDescriptionSuitableForTestResult(request, stringBuilder); |
1161 | stringBuilder.appendLiteral(" redirectResponse " ); |
1162 | dumpResponseDescriptionSuitableForTestResult(response, stringBuilder, injectedBundle.testRunner()->shouldDumpAllHTTPRedirectedResponseHeaders()); |
1163 | stringBuilder.append('\n'); |
1164 | injectedBundle.outputText(stringBuilder.toString()); |
1165 | } |
1166 | |
1167 | if (injectedBundle.isTestRunning() && injectedBundle.testRunner()->willSendRequestReturnsNull()) |
1168 | return nullptr; |
1169 | |
1170 | WKRetainPtr<WKURLRef> redirectURL = adoptWK(WKURLResponseCopyURL(response)); |
1171 | if (injectedBundle.isTestRunning() && injectedBundle.testRunner()->willSendRequestReturnsNullOnRedirect() && redirectURL) { |
1172 | injectedBundle.outputText("Returning null for this redirect\n" ); |
1173 | return nullptr; |
1174 | } |
1175 | |
1176 | WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request)); |
1177 | WKRetainPtr<WKStringRef> host = adoptWK(WKURLCopyHostName(url.get())); |
1178 | WKRetainPtr<WKStringRef> scheme = adoptWK(WKURLCopyScheme(url.get())); |
1179 | WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(url.get())); |
1180 | if (host && !WKStringIsEmpty(host.get()) |
1181 | && isHTTPOrHTTPSScheme(scheme.get()) |
1182 | && !WKStringIsEqualToUTF8CString(host.get(), "255.255.255.255" ) // Used in some tests that expect to get back an error. |
1183 | && !isLocalHost(host.get())) { |
1184 | bool mainFrameIsExternal = false; |
1185 | if (injectedBundle.isTestRunning()) { |
1186 | WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(m_page); |
1187 | WKRetainPtr<WKURLRef> mainFrameURL = adoptWK(WKBundleFrameCopyURL(mainFrame)); |
1188 | if (!mainFrameURL || WKStringIsEqualToUTF8CString(adoptWK(WKURLCopyString(mainFrameURL.get())).get(), "about:blank" )) |
1189 | mainFrameURL = adoptWK(WKBundleFrameCopyProvisionalURL(mainFrame)); |
1190 | |
1191 | WKRetainPtr<WKStringRef> mainFrameHost = adoptWK(WKURLCopyHostName(mainFrameURL.get())); |
1192 | WKRetainPtr<WKStringRef> mainFrameScheme = adoptWK(WKURLCopyScheme(mainFrameURL.get())); |
1193 | mainFrameIsExternal = isHTTPOrHTTPSScheme(mainFrameScheme.get()) && !isLocalHost(mainFrameHost.get()); |
1194 | } |
1195 | if (!mainFrameIsExternal && !isAllowedHost(host.get())) { |
1196 | StringBuilder stringBuilder; |
1197 | stringBuilder.appendLiteral("Blocked access to external URL " ); |
1198 | stringBuilder.append(toWTFString(urlString)); |
1199 | stringBuilder.append('\n'); |
1200 | injectedBundle.outputText(stringBuilder.toString()); |
1201 | return nullptr; |
1202 | } |
1203 | } |
1204 | |
1205 | if (injectedBundle.isTestRunning()) { |
1206 | String body = injectedBundle.testRunner()->willSendRequestHTTPBody(); |
1207 | if (!body.isEmpty()) { |
1208 | CString cBody = body.utf8(); |
1209 | WKRetainPtr<WKDataRef> body = adoptWK(WKDataCreate(reinterpret_cast<const unsigned char*>(cBody.data()), cBody.length())); |
1210 | return WKURLRequestCopySettingHTTPBody(request, body.get()); |
1211 | } |
1212 | } |
1213 | |
1214 | WKRetain(request); |
1215 | return request; |
1216 | } |
1217 | |
1218 | void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef, uint64_t identifier, WKURLResponseRef response) |
1219 | { |
1220 | auto& injectedBundle = InjectedBundle::singleton(); |
1221 | if (!injectedBundle.isTestRunning()) |
1222 | return; |
1223 | |
1224 | if (injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) { |
1225 | StringBuilder stringBuilder; |
1226 | dumpResourceURL(identifier, stringBuilder); |
1227 | stringBuilder.appendLiteral(" - didReceiveResponse " ); |
1228 | dumpResponseDescriptionSuitableForTestResult(response, stringBuilder); |
1229 | stringBuilder.append('\n'); |
1230 | injectedBundle.outputText(stringBuilder.toString()); |
1231 | } |
1232 | |
1233 | |
1234 | if (!injectedBundle.testRunner()->shouldDumpResourceResponseMIMETypes()) |
1235 | return; |
1236 | |
1237 | WKRetainPtr<WKURLRef> url = adoptWK(WKURLResponseCopyURL(response)); |
1238 | WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyLastPathComponent(url.get())); |
1239 | WKRetainPtr<WKStringRef> mimeTypeString = adoptWK(WKURLResponseCopyMIMEType(response)); |
1240 | |
1241 | StringBuilder stringBuilder; |
1242 | stringBuilder.append(toWTFString(urlString)); |
1243 | stringBuilder.appendLiteral(" has MIME type " ); |
1244 | stringBuilder.append(toWTFString(mimeTypeString)); |
1245 | |
1246 | String platformMimeType = platformResponseMimeType(response); |
1247 | if (!platformMimeType.isEmpty() && platformMimeType != toWTFString(mimeTypeString)) { |
1248 | stringBuilder.appendLiteral(" but platform response has " ); |
1249 | stringBuilder.append(platformMimeType); |
1250 | } |
1251 | |
1252 | stringBuilder.append('\n'); |
1253 | |
1254 | injectedBundle.outputText(stringBuilder.toString()); |
1255 | } |
1256 | |
1257 | void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, uint64_t) |
1258 | { |
1259 | } |
1260 | |
1261 | void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier) |
1262 | { |
1263 | auto& injectedBundle = InjectedBundle::singleton(); |
1264 | if (!injectedBundle.isTestRunning()) |
1265 | return; |
1266 | |
1267 | if (!injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) |
1268 | return; |
1269 | |
1270 | StringBuilder stringBuilder; |
1271 | dumpResourceURL(identifier, stringBuilder); |
1272 | stringBuilder.appendLiteral(" - didFinishLoading\n" ); |
1273 | injectedBundle.outputText(stringBuilder.toString()); |
1274 | } |
1275 | |
1276 | void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKErrorRef error) |
1277 | { |
1278 | auto& injectedBundle = InjectedBundle::singleton(); |
1279 | if (!injectedBundle.isTestRunning()) |
1280 | return; |
1281 | |
1282 | if (!injectedBundle.testRunner()->shouldDumpResourceLoadCallbacks()) |
1283 | return; |
1284 | |
1285 | StringBuilder stringBuilder; |
1286 | dumpResourceURL(identifier, stringBuilder); |
1287 | stringBuilder.appendLiteral(" - didFailLoadingWithError: " ); |
1288 | |
1289 | dumpErrorDescriptionSuitableForTestResult(error, stringBuilder); |
1290 | stringBuilder.append('\n'); |
1291 | injectedBundle.outputText(stringBuilder.toString()); |
1292 | } |
1293 | |
1294 | bool InjectedBundlePage::shouldCacheResponse(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier) |
1295 | { |
1296 | auto& injectedBundle = InjectedBundle::singleton(); |
1297 | if (!injectedBundle.isTestRunning()) |
1298 | return true; |
1299 | |
1300 | if (!injectedBundle.testRunner()->shouldDumpWillCacheResponse()) |
1301 | return true; |
1302 | |
1303 | StringBuilder stringBuilder; |
1304 | stringBuilder.appendNumber(identifier); |
1305 | stringBuilder.appendLiteral(" - willCacheResponse: called\n" ); |
1306 | injectedBundle.outputText(stringBuilder.toString()); |
1307 | |
1308 | // The default behavior is the cache the response. |
1309 | return true; |
1310 | } |
1311 | |
1312 | |
1313 | // Policy Client Callbacks |
1314 | |
1315 | WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKTypeRef* userData, const void* clientInfo) |
1316 | { |
1317 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(page, frame, navigationAction, request, userData); |
1318 | } |
1319 | |
1320 | WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKStringRef frameName, WKTypeRef* userData, const void* clientInfo) |
1321 | { |
1322 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForNewWindowAction(page, frame, navigationAction, request, frameName, userData); |
1323 | } |
1324 | |
1325 | WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKTypeRef* userData, const void* clientInfo) |
1326 | { |
1327 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(page, frame, response, request, userData); |
1328 | } |
1329 | |
1330 | void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef* userData, const void* clientInfo) |
1331 | { |
1332 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->unableToImplementPolicy(page, frame, error, userData); |
1333 | } |
1334 | |
1335 | WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKTypeRef* userData) |
1336 | { |
1337 | auto& injectedBundle = InjectedBundle::singleton(); |
1338 | if (!injectedBundle.isTestRunning()) |
1339 | return WKBundlePagePolicyActionUse; |
1340 | |
1341 | if (injectedBundle.testRunner()->shouldDumpPolicyCallbacks()) { |
1342 | StringBuilder stringBuilder; |
1343 | stringBuilder.appendLiteral(" - decidePolicyForNavigationAction \n" ); |
1344 | dumpRequestDescriptionSuitableForTestResult(request, stringBuilder); |
1345 | stringBuilder.appendLiteral(" is main frame - " ); |
1346 | stringBuilder.append(WKBundleFrameIsMainFrame(frame) ? "yes" : "no" ); |
1347 | stringBuilder.appendLiteral(" should open URLs externally - " ); |
1348 | stringBuilder.append(WKBundleNavigationActionGetShouldOpenExternalURLs(navigationAction) ? "yes" : "no" ); |
1349 | stringBuilder.append('\n'); |
1350 | injectedBundle.outputText(stringBuilder.toString()); |
1351 | } |
1352 | |
1353 | if (!injectedBundle.testRunner()->isPolicyDelegateEnabled()) |
1354 | return WKBundlePagePolicyActionPassThrough; |
1355 | |
1356 | WKRetainPtr<WKURLRef> url = adoptWK(WKURLRequestCopyURL(request)); |
1357 | WKRetainPtr<WKStringRef> urlScheme = adoptWK(WKURLCopyScheme(url.get())); |
1358 | |
1359 | StringBuilder stringBuilder; |
1360 | stringBuilder.appendLiteral("Policy delegate: attempt to load " ); |
1361 | if (isLocalFileScheme(urlScheme.get())) { |
1362 | WKRetainPtr<WKStringRef> filename = adoptWK(WKURLCopyLastPathComponent(url.get())); |
1363 | stringBuilder.append(toWTFString(filename)); |
1364 | } else { |
1365 | WKRetainPtr<WKStringRef> urlString = adoptWK(WKURLCopyString(url.get())); |
1366 | stringBuilder.append(toWTFString(urlString)); |
1367 | } |
1368 | stringBuilder.appendLiteral(" with navigation type \'" ); |
1369 | stringBuilder.append(toWTFString(NavigationTypeToString(WKBundleNavigationActionGetNavigationType(navigationAction)))); |
1370 | stringBuilder.appendLiteral("\'" ); |
1371 | WKRetainPtr<WKBundleHitTestResultRef> hitTestResultRef = adoptWK(WKBundleNavigationActionCopyHitTestResult(navigationAction)); |
1372 | if (hitTestResultRef) { |
1373 | WKRetainPtr<WKBundleNodeHandleRef> nodeHandleRef = adoptWK(WKBundleHitTestResultCopyNodeHandle(hitTestResultRef.get())); |
1374 | stringBuilder.appendLiteral(" originating from " ); |
1375 | stringBuilder.append(dumpPath(m_page, m_world.get(), nodeHandleRef.get())); |
1376 | } |
1377 | |
1378 | stringBuilder.append('\n'); |
1379 | injectedBundle.outputText(stringBuilder.toString()); |
1380 | |
1381 | injectedBundle.testRunner()->notifyDone(); |
1382 | |
1383 | return WKBundlePagePolicyActionPassThrough; |
1384 | } |
1385 | |
1386 | WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKStringRef, WKTypeRef*) |
1387 | { |
1388 | return WKBundlePagePolicyActionPassThrough; |
1389 | } |
1390 | |
1391 | WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef, WKURLResponseRef response, WKURLRequestRef, WKTypeRef*) |
1392 | { |
1393 | auto& injectedBundle = InjectedBundle::singleton(); |
1394 | if (injectedBundle.testRunner() && injectedBundle.testRunner()->isPolicyDelegateEnabled() && WKURLResponseIsAttachment(response)) { |
1395 | StringBuilder stringBuilder; |
1396 | WKRetainPtr<WKStringRef> filename = adoptWK(WKURLResponseCopySuggestedFilename(response)); |
1397 | stringBuilder.appendLiteral("Policy delegate: resource is an attachment, suggested file name \'" ); |
1398 | stringBuilder.append(toWTFString(filename)); |
1399 | stringBuilder.appendLiteral("\'\n" ); |
1400 | InjectedBundle::singleton().outputText(stringBuilder.toString()); |
1401 | } |
1402 | |
1403 | return WKBundlePagePolicyActionPassThrough; |
1404 | } |
1405 | |
1406 | void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*) |
1407 | { |
1408 | } |
1409 | |
1410 | // UI Client Callbacks |
1411 | |
1412 | void InjectedBundlePage::willAddMessageToConsole(WKBundlePageRef page, WKStringRef message, uint32_t lineNumber, const void *clientInfo) |
1413 | { |
1414 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willAddMessageToConsole(message, lineNumber); |
1415 | } |
1416 | |
1417 | void InjectedBundlePage::willSetStatusbarText(WKBundlePageRef page, WKStringRef statusbarText, const void *clientInfo) |
1418 | { |
1419 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSetStatusbarText(statusbarText); |
1420 | } |
1421 | |
1422 | void InjectedBundlePage::willRunJavaScriptAlert(WKBundlePageRef page, WKStringRef message, WKBundleFrameRef frame, const void *clientInfo) |
1423 | { |
1424 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptAlert(message, frame); |
1425 | } |
1426 | |
1427 | void InjectedBundlePage::willRunJavaScriptConfirm(WKBundlePageRef page, WKStringRef message, WKBundleFrameRef frame, const void *clientInfo) |
1428 | { |
1429 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptConfirm(message, frame); |
1430 | } |
1431 | |
1432 | void InjectedBundlePage::willRunJavaScriptPrompt(WKBundlePageRef page, WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef frame, const void *clientInfo) |
1433 | { |
1434 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptPrompt(message, defaultValue, frame); |
1435 | } |
1436 | |
1437 | void InjectedBundlePage::didReachApplicationCacheOriginQuota(WKBundlePageRef page, WKSecurityOriginRef origin, int64_t totalBytesNeeded, const void* clientInfo) |
1438 | { |
1439 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReachApplicationCacheOriginQuota(origin, totalBytesNeeded); |
1440 | } |
1441 | |
1442 | uint64_t InjectedBundlePage::didExceedDatabaseQuota(WKBundlePageRef page, WKSecurityOriginRef origin, WKStringRef databaseName, WKStringRef databaseDisplayName, uint64_t currentQuotaBytes, uint64_t currentOriginUsageBytes, uint64_t currentDatabaseUsageBytes, uint64_t expectedUsageBytes, const void* clientInfo) |
1443 | { |
1444 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didExceedDatabaseQuota(origin, databaseName, databaseDisplayName, currentQuotaBytes, currentOriginUsageBytes, currentDatabaseUsageBytes, expectedUsageBytes); |
1445 | } |
1446 | |
1447 | static WTF::String lastFileURLPathComponent(const WTF::String& path) |
1448 | { |
1449 | size_t pos = path.find("file://" ); |
1450 | ASSERT(WTF::notFound != pos); |
1451 | |
1452 | WTF::String tmpPath = path.substring(pos + 7); |
1453 | if (tmpPath.length() < 2) // Keep the lone slash to avoid empty output. |
1454 | return tmpPath; |
1455 | |
1456 | // Remove the trailing delimiter |
1457 | if (tmpPath[tmpPath.length() - 1] == '/') |
1458 | tmpPath.remove(tmpPath.length() - 1); |
1459 | |
1460 | pos = tmpPath.reverseFind('/'); |
1461 | if (WTF::notFound != pos) |
1462 | return tmpPath.substring(pos + 1); |
1463 | |
1464 | return tmpPath; |
1465 | } |
1466 | |
1467 | void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t lineNumber) |
1468 | { |
1469 | auto& injectedBundle = InjectedBundle::singleton(); |
1470 | if (!injectedBundle.isTestRunning()) |
1471 | return; |
1472 | |
1473 | WTF::String messageString = toWTFString(message); |
1474 | size_t nullCharPos = messageString.find(UChar(0)); |
1475 | if (nullCharPos != WTF::notFound) |
1476 | messageString.truncate(nullCharPos); |
1477 | |
1478 | size_t fileProtocolStart = messageString.find("file://" ); |
1479 | if (fileProtocolStart != WTF::notFound) |
1480 | // FIXME: The code below does not handle additional text after url nor multiple urls. This matches DumpRenderTree implementation. |
1481 | messageString = messageString.substring(0, fileProtocolStart) + lastFileURLPathComponent(messageString.substring(fileProtocolStart)); |
1482 | |
1483 | StringBuilder stringBuilder; |
1484 | stringBuilder.appendLiteral("CONSOLE MESSAGE: " ); |
1485 | if (lineNumber) { |
1486 | stringBuilder.appendLiteral("line " ); |
1487 | stringBuilder.appendNumber(lineNumber); |
1488 | stringBuilder.appendLiteral(": " ); |
1489 | } |
1490 | stringBuilder.append(messageString); |
1491 | stringBuilder.append('\n'); |
1492 | |
1493 | if (injectedBundle.dumpJSConsoleLogInStdErr()) |
1494 | injectedBundle.dumpToStdErr(stringBuilder.toString()); |
1495 | else |
1496 | injectedBundle.outputText(stringBuilder.toString()); |
1497 | } |
1498 | |
1499 | void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText) |
1500 | { |
1501 | auto& injectedBundle = InjectedBundle::singleton(); |
1502 | if (!injectedBundle.isTestRunning()) |
1503 | return; |
1504 | |
1505 | if (!injectedBundle.testRunner()->shouldDumpStatusCallbacks()) |
1506 | return; |
1507 | |
1508 | StringBuilder stringBuilder; |
1509 | stringBuilder.appendLiteral("UI DELEGATE STATUS CALLBACK: setStatusText:" ); |
1510 | stringBuilder.append(toWTFString(statusbarText)); |
1511 | stringBuilder.append('\n'); |
1512 | injectedBundle.outputText(stringBuilder.toString()); |
1513 | } |
1514 | |
1515 | void InjectedBundlePage::willRunJavaScriptAlert(WKStringRef message, WKBundleFrameRef) |
1516 | { |
1517 | auto& injectedBundle = InjectedBundle::singleton(); |
1518 | if (!injectedBundle.isTestRunning()) |
1519 | return; |
1520 | |
1521 | StringBuilder stringBuilder; |
1522 | stringBuilder.appendLiteral("ALERT: " ); |
1523 | stringBuilder.append(toWTFString(message)); |
1524 | stringBuilder.append('\n'); |
1525 | injectedBundle.outputText(stringBuilder.toString()); |
1526 | } |
1527 | |
1528 | void InjectedBundlePage::willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef) |
1529 | { |
1530 | auto& injectedBundle = InjectedBundle::singleton(); |
1531 | if (!injectedBundle.isTestRunning()) |
1532 | return; |
1533 | |
1534 | StringBuilder stringBuilder; |
1535 | stringBuilder.appendLiteral("CONFIRM: " ); |
1536 | stringBuilder.append(toWTFString(message)); |
1537 | stringBuilder.append('\n'); |
1538 | injectedBundle.outputText(stringBuilder.toString()); |
1539 | } |
1540 | |
1541 | void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef) |
1542 | { |
1543 | StringBuilder stringBuilder; |
1544 | stringBuilder.appendLiteral("PROMPT: " ); |
1545 | stringBuilder.append(toWTFString(message)); |
1546 | stringBuilder.appendLiteral(", default text: " ); |
1547 | stringBuilder.append(toWTFString(defaultValue)); |
1548 | stringBuilder.append('\n'); |
1549 | InjectedBundle::singleton().outputText(stringBuilder.toString()); |
1550 | } |
1551 | |
1552 | void InjectedBundlePage::didReachApplicationCacheOriginQuota(WKSecurityOriginRef origin, int64_t totalBytesNeeded) |
1553 | { |
1554 | auto& injectedBundle = InjectedBundle::singleton(); |
1555 | if (injectedBundle.testRunner()->shouldDumpApplicationCacheDelegateCallbacks()) { |
1556 | // For example, numbers from 30000 - 39999 will output as 30000. |
1557 | // Rounding up or down does not really matter for these tests. It's |
1558 | // sufficient to just get a range of 10000 to determine if we were |
1559 | // above or below a threshold. |
1560 | int64_t truncatedSpaceNeeded = (totalBytesNeeded / 10000) * 10000; |
1561 | |
1562 | StringBuilder stringBuilder; |
1563 | stringBuilder.appendLiteral("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:" ); |
1564 | stringBuilder.append(securityOriginToStr(origin)); |
1565 | stringBuilder.appendLiteral(" totalSpaceNeeded:~" ); |
1566 | stringBuilder.appendNumber(truncatedSpaceNeeded); |
1567 | stringBuilder.append('\n'); |
1568 | injectedBundle.outputText(stringBuilder.toString()); |
1569 | } |
1570 | |
1571 | if (injectedBundle.testRunner()->shouldDisallowIncreaseForApplicationCacheQuota()) |
1572 | return; |
1573 | |
1574 | // Reset default application cache quota. |
1575 | WKBundlePageResetApplicationCacheOriginQuota(injectedBundle.page()->page(), adoptWK(WKSecurityOriginCopyToString(origin)).get()); |
1576 | } |
1577 | |
1578 | uint64_t InjectedBundlePage::didExceedDatabaseQuota(WKSecurityOriginRef origin, WKStringRef databaseName, WKStringRef databaseDisplayName, uint64_t currentQuotaBytes, uint64_t currentOriginUsageBytes, uint64_t currentDatabaseUsageBytes, uint64_t expectedUsageBytes) |
1579 | { |
1580 | auto& injectedBundle = InjectedBundle::singleton(); |
1581 | if (injectedBundle.testRunner()->shouldDumpDatabaseCallbacks()) { |
1582 | StringBuilder stringBuilder; |
1583 | stringBuilder.appendLiteral("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:" ); |
1584 | stringBuilder.append(securityOriginToStr(origin)); |
1585 | stringBuilder.appendLiteral(" database:" ); |
1586 | stringBuilder.append(toWTFString(databaseName)); |
1587 | stringBuilder.append('\n'); |
1588 | injectedBundle.outputText(stringBuilder.toString()); |
1589 | } |
1590 | |
1591 | uint64_t defaultQuota = 5 * 1024 * 1024; |
1592 | double testDefaultQuota = injectedBundle.testRunner()->databaseDefaultQuota(); |
1593 | if (testDefaultQuota >= 0) |
1594 | defaultQuota = testDefaultQuota; |
1595 | |
1596 | unsigned long long newQuota = defaultQuota; |
1597 | |
1598 | double maxQuota = injectedBundle.testRunner()->databaseMaxQuota(); |
1599 | if (maxQuota >= 0) { |
1600 | if (defaultQuota < expectedUsageBytes && expectedUsageBytes <= maxQuota) { |
1601 | newQuota = expectedUsageBytes; |
1602 | |
1603 | StringBuilder stringBuilder; |
1604 | stringBuilder.appendLiteral("UI DELEGATE DATABASE CALLBACK: increased quota to " ); |
1605 | stringBuilder.appendNumber(newQuota); |
1606 | stringBuilder.append('\n'); |
1607 | injectedBundle.outputText(stringBuilder.toString()); |
1608 | } |
1609 | } |
1610 | return newQuota; |
1611 | } |
1612 | |
1613 | // Editor Client Callbacks |
1614 | |
1615 | bool InjectedBundlePage::shouldBeginEditing(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo) |
1616 | { |
1617 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldBeginEditing(range); |
1618 | } |
1619 | |
1620 | bool InjectedBundlePage::shouldEndEditing(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo) |
1621 | { |
1622 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldEndEditing(range); |
1623 | } |
1624 | |
1625 | bool InjectedBundlePage::shouldInsertNode(WKBundlePageRef page, WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action, const void* clientInfo) |
1626 | { |
1627 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldInsertNode(node, rangeToReplace, action); |
1628 | } |
1629 | |
1630 | bool InjectedBundlePage::shouldInsertText(WKBundlePageRef page, WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action, const void* clientInfo) |
1631 | { |
1632 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldInsertText(text, rangeToReplace, action); |
1633 | } |
1634 | |
1635 | bool InjectedBundlePage::shouldDeleteRange(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo) |
1636 | { |
1637 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldDeleteRange(range); |
1638 | } |
1639 | |
1640 | bool InjectedBundlePage::shouldChangeSelectedRange(WKBundlePageRef page, WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting, const void* clientInfo) |
1641 | { |
1642 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldChangeSelectedRange(fromRange, toRange, affinity, stillSelecting); |
1643 | } |
1644 | |
1645 | bool InjectedBundlePage::shouldApplyStyle(WKBundlePageRef page, WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range, const void* clientInfo) |
1646 | { |
1647 | return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldApplyStyle(style, range); |
1648 | } |
1649 | |
1650 | void InjectedBundlePage::didBeginEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo) |
1651 | { |
1652 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didBeginEditing(notificationName); |
1653 | } |
1654 | |
1655 | void InjectedBundlePage::didEndEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo) |
1656 | { |
1657 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didEndEditing(notificationName); |
1658 | } |
1659 | |
1660 | void InjectedBundlePage::didChange(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo) |
1661 | { |
1662 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChange(notificationName); |
1663 | } |
1664 | |
1665 | void InjectedBundlePage::didChangeSelection(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo) |
1666 | { |
1667 | static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChangeSelection(notificationName); |
1668 | } |
1669 | |
1670 | bool InjectedBundlePage::shouldBeginEditing(WKBundleRangeHandleRef range) |
1671 | { |
1672 | auto& injectedBundle = InjectedBundle::singleton(); |
1673 | if (!injectedBundle.isTestRunning()) |
1674 | return true; |
1675 | |
1676 | if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { |
1677 | StringBuilder stringBuilder; |
1678 | stringBuilder.appendLiteral("EDITING DELEGATE: shouldBeginEditingInDOMRange:" ); |
1679 | stringBuilder.append(rangeToStr(m_page, m_world.get(), range)); |
1680 | stringBuilder.append('\n'); |
1681 | injectedBundle.outputText(stringBuilder.toString()); |
1682 | } |
1683 | return injectedBundle.testRunner()->shouldAllowEditing(); |
1684 | } |
1685 | |
1686 | bool InjectedBundlePage::shouldEndEditing(WKBundleRangeHandleRef range) |
1687 | { |
1688 | auto& injectedBundle = InjectedBundle::singleton(); |
1689 | if (!injectedBundle.isTestRunning()) |
1690 | return true; |
1691 | |
1692 | if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { |
1693 | StringBuilder stringBuilder; |
1694 | stringBuilder.appendLiteral("EDITING DELEGATE: shouldEndEditingInDOMRange:" ); |
1695 | stringBuilder.append(rangeToStr(m_page, m_world.get(), range)); |
1696 | stringBuilder.append('\n'); |
1697 | injectedBundle.outputText(stringBuilder.toString()); |
1698 | } |
1699 | return injectedBundle.testRunner()->shouldAllowEditing(); |
1700 | } |
1701 | |
1702 | bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action) |
1703 | { |
1704 | auto& injectedBundle = InjectedBundle::singleton(); |
1705 | if (!injectedBundle.isTestRunning()) |
1706 | return true; |
1707 | |
1708 | static const char* insertactionstring[] = { |
1709 | "WebViewInsertActionTyped" , |
1710 | "WebViewInsertActionPasted" , |
1711 | "WebViewInsertActionDropped" , |
1712 | }; |
1713 | |
1714 | if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { |
1715 | StringBuilder stringBuilder; |
1716 | stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertNode:" ); |
1717 | stringBuilder.append(dumpPath(m_page, m_world.get(), node)); |
1718 | stringBuilder.appendLiteral(" replacingDOMRange:" ); |
1719 | stringBuilder.append(rangeToStr(m_page, m_world.get(), rangeToReplace)); |
1720 | stringBuilder.appendLiteral(" givenAction:" ); |
1721 | stringBuilder.append(insertactionstring[action]); |
1722 | stringBuilder.append('\n'); |
1723 | injectedBundle.outputText(stringBuilder.toString()); |
1724 | } |
1725 | return injectedBundle.testRunner()->shouldAllowEditing(); |
1726 | } |
1727 | |
1728 | bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action) |
1729 | { |
1730 | auto& injectedBundle = InjectedBundle::singleton(); |
1731 | if (!injectedBundle.isTestRunning()) |
1732 | return true; |
1733 | |
1734 | static const char *insertactionstring[] = { |
1735 | "WebViewInsertActionTyped" , |
1736 | "WebViewInsertActionPasted" , |
1737 | "WebViewInsertActionDropped" , |
1738 | }; |
1739 | |
1740 | if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { |
1741 | StringBuilder stringBuilder; |
1742 | stringBuilder.appendLiteral("EDITING DELEGATE: shouldInsertText:" ); |
1743 | stringBuilder.append(toWTFString(text)); |
1744 | stringBuilder.appendLiteral(" replacingDOMRange:" ); |
1745 | stringBuilder.append(rangeToStr(m_page, m_world.get(), rangeToReplace)); |
1746 | stringBuilder.appendLiteral(" givenAction:" ); |
1747 | stringBuilder.append(insertactionstring[action]); |
1748 | stringBuilder.append('\n'); |
1749 | injectedBundle.outputText(stringBuilder.toString()); |
1750 | } |
1751 | return injectedBundle.testRunner()->shouldAllowEditing(); |
1752 | } |
1753 | |
1754 | bool InjectedBundlePage::shouldDeleteRange(WKBundleRangeHandleRef range) |
1755 | { |
1756 | auto& injectedBundle = InjectedBundle::singleton(); |
1757 | if (!injectedBundle.isTestRunning()) |
1758 | return true; |
1759 | |
1760 | if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { |
1761 | StringBuilder stringBuilder; |
1762 | stringBuilder.appendLiteral("EDITING DELEGATE: shouldDeleteDOMRange:" ); |
1763 | stringBuilder.append(rangeToStr(m_page, m_world.get(), range)); |
1764 | stringBuilder.append('\n'); |
1765 | injectedBundle.outputText(stringBuilder.toString()); |
1766 | } |
1767 | return injectedBundle.testRunner()->shouldAllowEditing(); |
1768 | } |
1769 | |
1770 | bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting) |
1771 | { |
1772 | auto& injectedBundle = InjectedBundle::singleton(); |
1773 | if (!injectedBundle.isTestRunning()) |
1774 | return true; |
1775 | |
1776 | static const char *affinitystring[] = { |
1777 | "NSSelectionAffinityUpstream" , |
1778 | "NSSelectionAffinityDownstream" |
1779 | }; |
1780 | static const char *boolstring[] = { |
1781 | "FALSE" , |
1782 | "TRUE" |
1783 | }; |
1784 | |
1785 | if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { |
1786 | StringBuilder stringBuilder; |
1787 | stringBuilder.appendLiteral("EDITING DELEGATE: shouldChangeSelectedDOMRange:" ); |
1788 | stringBuilder.append(rangeToStr(m_page, m_world.get(), fromRange)); |
1789 | stringBuilder.appendLiteral(" toDOMRange:" ); |
1790 | stringBuilder.append(rangeToStr(m_page, m_world.get(), toRange)); |
1791 | stringBuilder.appendLiteral(" affinity:" ); |
1792 | stringBuilder.append(affinitystring[affinity]); |
1793 | stringBuilder.appendLiteral(" stillSelecting:" ); |
1794 | stringBuilder.append(boolstring[stillSelecting]); |
1795 | stringBuilder.append('\n'); |
1796 | injectedBundle.outputText(stringBuilder.toString()); |
1797 | } |
1798 | return injectedBundle.testRunner()->shouldAllowEditing(); |
1799 | } |
1800 | |
1801 | bool InjectedBundlePage::shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range) |
1802 | { |
1803 | auto& injectedBundle = InjectedBundle::singleton(); |
1804 | if (!injectedBundle.isTestRunning()) |
1805 | return true; |
1806 | |
1807 | if (injectedBundle.testRunner()->shouldDumpEditingCallbacks()) { |
1808 | StringBuilder stringBuilder; |
1809 | stringBuilder.appendLiteral("EDITING DELEGATE: shouldApplyStyle:" ); |
1810 | stringBuilder.append(styleDecToStr(style)); |
1811 | stringBuilder.appendLiteral(" toElementsInDOMRange:" ); |
1812 | stringBuilder.append(rangeToStr(m_page, m_world.get(), range)); |
1813 | stringBuilder.append('\n'); |
1814 | injectedBundle.outputText(stringBuilder.toString()); |
1815 | } |
1816 | return injectedBundle.testRunner()->shouldAllowEditing(); |
1817 | } |
1818 | |
1819 | void InjectedBundlePage::didBeginEditing(WKStringRef notificationName) |
1820 | { |
1821 | auto& injectedBundle = InjectedBundle::singleton(); |
1822 | if (!injectedBundle.isTestRunning()) |
1823 | return; |
1824 | if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks()) |
1825 | return; |
1826 | |
1827 | StringBuilder stringBuilder; |
1828 | stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidBeginEditing:" ); |
1829 | stringBuilder.append(toWTFString(notificationName)); |
1830 | stringBuilder.append('\n'); |
1831 | injectedBundle.outputText(stringBuilder.toString()); |
1832 | } |
1833 | |
1834 | void InjectedBundlePage::didEndEditing(WKStringRef notificationName) |
1835 | { |
1836 | auto& injectedBundle = InjectedBundle::singleton(); |
1837 | if (!injectedBundle.isTestRunning()) |
1838 | return; |
1839 | if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks()) |
1840 | return; |
1841 | |
1842 | StringBuilder stringBuilder; |
1843 | stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidEndEditing:" ); |
1844 | stringBuilder.append(toWTFString(notificationName)); |
1845 | stringBuilder.append('\n'); |
1846 | injectedBundle.outputText(stringBuilder.toString()); |
1847 | } |
1848 | |
1849 | void InjectedBundlePage::didChange(WKStringRef notificationName) |
1850 | { |
1851 | auto& injectedBundle = InjectedBundle::singleton(); |
1852 | if (!injectedBundle.isTestRunning()) |
1853 | return; |
1854 | if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks()) |
1855 | return; |
1856 | |
1857 | StringBuilder stringBuilder; |
1858 | stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChange:" ); |
1859 | stringBuilder.append(toWTFString(notificationName)); |
1860 | stringBuilder.append('\n'); |
1861 | injectedBundle.outputText(stringBuilder.toString()); |
1862 | } |
1863 | |
1864 | void InjectedBundlePage::didChangeSelection(WKStringRef notificationName) |
1865 | { |
1866 | auto& injectedBundle = InjectedBundle::singleton(); |
1867 | if (!injectedBundle.isTestRunning()) |
1868 | return; |
1869 | if (!injectedBundle.testRunner()->shouldDumpEditingCallbacks()) |
1870 | return; |
1871 | |
1872 | StringBuilder stringBuilder; |
1873 | stringBuilder.appendLiteral("EDITING DELEGATE: webViewDidChangeSelection:" ); |
1874 | stringBuilder.append(toWTFString(notificationName)); |
1875 | stringBuilder.append('\n'); |
1876 | injectedBundle.outputText(stringBuilder.toString()); |
1877 | } |
1878 | |
1879 | #if ENABLE(FULLSCREEN_API) |
1880 | bool InjectedBundlePage::supportsFullScreen(WKBundlePageRef , WKFullScreenKeyboardRequestType requestType) |
1881 | { |
1882 | auto& injectedBundle = InjectedBundle::singleton(); |
1883 | if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) |
1884 | injectedBundle.outputText("supportsFullScreen() == true\n" ); |
1885 | return true; |
1886 | } |
1887 | |
1888 | void InjectedBundlePage::enterFullScreenForElement(WKBundlePageRef , WKBundleNodeHandleRef elementRef) |
1889 | { |
1890 | auto& injectedBundle = InjectedBundle::singleton(); |
1891 | if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) |
1892 | injectedBundle.outputText("enterFullScreenForElement()\n" ); |
1893 | |
1894 | if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) { |
1895 | WKBundlePageWillEnterFullScreen(pageRef); |
1896 | WKBundlePageDidEnterFullScreen(pageRef); |
1897 | } |
1898 | } |
1899 | |
1900 | void InjectedBundlePage::exitFullScreenForElement(WKBundlePageRef , WKBundleNodeHandleRef elementRef) |
1901 | { |
1902 | auto& injectedBundle = InjectedBundle::singleton(); |
1903 | if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) |
1904 | injectedBundle.outputText("exitFullScreenForElement()\n" ); |
1905 | |
1906 | if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) { |
1907 | WKBundlePageWillExitFullScreen(pageRef); |
1908 | WKBundlePageDidExitFullScreen(pageRef); |
1909 | } |
1910 | } |
1911 | |
1912 | void InjectedBundlePage::beganEnterFullScreen(WKBundlePageRef, WKRect, WKRect) |
1913 | { |
1914 | auto& injectedBundle = InjectedBundle::singleton(); |
1915 | if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) |
1916 | injectedBundle.outputText("beganEnterFullScreen()\n" ); |
1917 | } |
1918 | |
1919 | void InjectedBundlePage::beganExitFullScreen(WKBundlePageRef, WKRect, WKRect) |
1920 | { |
1921 | auto& injectedBundle = InjectedBundle::singleton(); |
1922 | if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) |
1923 | injectedBundle.outputText("beganExitFullScreen()\n" ); |
1924 | } |
1925 | |
1926 | void InjectedBundlePage::closeFullScreen(WKBundlePageRef ) |
1927 | { |
1928 | auto& injectedBundle = InjectedBundle::singleton(); |
1929 | if (injectedBundle.testRunner()->shouldDumpFullScreenCallbacks()) |
1930 | injectedBundle.outputText("closeFullScreen()\n" ); |
1931 | |
1932 | if (!injectedBundle.testRunner()->hasCustomFullScreenBehavior()) { |
1933 | WKBundlePageWillExitFullScreen(pageRef); |
1934 | WKBundlePageDidExitFullScreen(pageRef); |
1935 | } |
1936 | } |
1937 | #endif |
1938 | |
1939 | String InjectedBundlePage::dumpHistory() |
1940 | { |
1941 | return makeString( |
1942 | "\n============== Back Forward List ==============\n" , |
1943 | toWTFString(adoptWK(WKBundlePageDumpHistoryForTesting(m_page, toWK("/LayoutTests/" ).get())).get()), |
1944 | "===============================================\n" |
1945 | ); |
1946 | } |
1947 | |
1948 | #if !PLATFORM(COCOA) |
1949 | void InjectedBundlePage::platformDidStartProvisionalLoadForFrame(WKBundleFrameRef) |
1950 | { |
1951 | } |
1952 | |
1953 | String InjectedBundlePage::platformResponseMimeType(WKURLResponseRef) |
1954 | { |
1955 | return String(); |
1956 | } |
1957 | #endif |
1958 | |
1959 | void InjectedBundlePage::frameDidChangeLocation(WKBundleFrameRef frame) |
1960 | { |
1961 | auto& injectedBundle = InjectedBundle::singleton(); |
1962 | if (frame != injectedBundle.topLoadingFrame()) |
1963 | return; |
1964 | |
1965 | injectedBundle.setTopLoadingFrame(nullptr); |
1966 | |
1967 | if (injectedBundle.testRunner()->shouldWaitUntilDone()) |
1968 | return; |
1969 | |
1970 | if (injectedBundle.shouldProcessWorkQueue()) { |
1971 | injectedBundle.processWorkQueue(); |
1972 | return; |
1973 | } |
1974 | |
1975 | if (injectedBundle.pageCount()) |
1976 | injectedBundle.page()->dump(); |
1977 | else |
1978 | injectedBundle.done(); |
1979 | } |
1980 | |
1981 | } // namespace WTR |
1982 | |