Home | History | Annotate | Download | only in InjectedBundle
      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 
     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 
     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 
     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 
     67 static int propertyValueInt(JSContextRef context, JSObjectRef object, const char* propertyName)
     68 {
     69     return static_cast<int>(propertyValueDouble(context, object, propertyName));
     70 }
     71 
     72 static double numericWindowPropertyValue(WKBundleFrameRef frame, const char* propertyName)
     73 {
     74     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
     75     return propertyValueDouble(context, JSContextGetGlobalObject(context), propertyName);
     76 }
     77 
     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 
     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 
    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 
    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 
    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 
    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 
    260 InjectedBundlePage::~InjectedBundlePage()
    261 {
    262 }
    263 
    264 void InjectedBundlePage::stopLoading()
    265 {
    266     WKBundlePageStopLoading(m_page);
    267 }
    268 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    331 void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
    332 {
    333     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCancelClientRedirectForFrame(frame);
    334 }
    335 
    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 
    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 
    346 void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
    347 {
    348     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didHandleOnloadEventsForFrame(frame);
    349 }
    350 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    401 void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame)
    402 {
    403 }
    404 
    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 
    420 void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame)
    421 {
    422 }
    423 
    424 enum FrameNamePolicy { ShouldNotIncludeFrameName, ShouldIncludeFrameName };
    425 
    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 
    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 
    450 void InjectedBundlePage::dumpAllFrameScrollPositions()
    451 {
    452     WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
    453     dumpFrameScrollPosition(frame);
    454     dumpDescendantFrameScrollPositions(frame);
    455 }
    456 
    457 static JSRetainPtr<JSStringRef> toJS(const char* string)
    458 {
    459     return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(string));
    460 }
    461 
    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 
    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 
    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 
    506 void InjectedBundlePage::dumpAllFramesText()
    507 {
    508     WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
    509     dumpFrameText(frame);
    510     dumpDescendantFramesText(frame);
    511 }
    512 
    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 
    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 
    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 
    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 
    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 
    616 void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame)
    617 {
    618 }
    619 
    620 void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundleFrameRef frame, WKURLRef url, double delay, double date)
    621 {
    622 }
    623 
    624 void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundleFrameRef frame, WKSameDocumentNavigationType type)
    625 {
    626 }
    627 
    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 
    638 void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundleFrameRef frame)
    639 {
    640 }
    641 
    642 void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef frame)
    643 {
    644 }
    645 
    646 void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef frame)
    647 {
    648 }
    649 
    650 void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef, bool)
    651 {
    652 }
    653 
    654 // Resource Load Client Callbacks
    655 
    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 
    677 void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, WKURLResponseRef)
    678 {
    679 }
    680 
    681 void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, uint64_t)
    682 {
    683 }
    684 
    685 void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t)
    686 {
    687 }
    688 
    689 void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, WKErrorRef)
    690 {
    691 }
    692 
    693 
    694 // Policy Client Callbacks
    695 
    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 
    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 
    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 
    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 
    716 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef request, WKTypeRef*)
    717 {
    718     return WKBundlePagePolicyActionUse;
    719 }
    720 
    721 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKStringRef, WKTypeRef*)
    722 {
    723     return WKBundlePagePolicyActionUse;
    724 }
    725 
    726 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef, WKBundleFrameRef, WKURLResponseRef, WKURLRequestRef, WKTypeRef*)
    727 {
    728     return WKBundlePagePolicyActionUse;
    729 }
    730 
    731 void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*)
    732 {
    733 }
    734 
    735 // UI Client Callbacks
    736 
    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 
    742 void InjectedBundlePage::willSetStatusbarText(WKBundlePageRef page, WKStringRef statusbarText, const void *clientInfo)
    743 {
    744     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSetStatusbarText(statusbarText);
    745 }
    746 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    865 void InjectedBundlePage::didBeginEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
    866 {
    867     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didBeginEditing(notificationName);
    868 }
    869 
    870 void InjectedBundlePage::didEndEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
    871 {
    872     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didEndEditing(notificationName);
    873 }
    874 
    875 void InjectedBundlePage::didChange(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
    876 {
    877     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChange(notificationName);
    878 }
    879 
    880 void InjectedBundlePage::didChangeSelection(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
    881 {
    882     static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChangeSelection(notificationName);
    883 }
    884 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
   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)
   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 
   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 
   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 
   1037 static bool compareByTargetName(WKBundleBackForwardListItemRef item1, WKBundleBackForwardListItemRef item2)
   1038 {
   1039     return toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item1))) < toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item2)));
   1040 }
   1041 
   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 
   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