1 /* 2 * Copyright (C) 2012 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "public/testing/WebTestProxy.h" 32 33 #include "AccessibilityControllerChromium.h" 34 #include "EventSender.h" 35 #include "MockColorChooser.h" 36 #include "MockWebSpeechInputController.h" 37 #include "MockWebSpeechRecognizer.h" 38 #include "MockWebValidationMessageClient.h" 39 #include "SpellCheckClient.h" 40 #include "TestCommon.h" 41 #include "TestInterfaces.h" 42 #include "TestPlugin.h" 43 #include "TestRunner.h" 44 #include "WebUserMediaClientMock.h" 45 #include "public/platform/WebCString.h" 46 #include "public/platform/WebURLError.h" 47 #include "public/platform/WebURLRequest.h" 48 #include "public/platform/WebURLResponse.h" 49 #include "public/testing/WebTestDelegate.h" 50 #include "public/testing/WebTestInterfaces.h" 51 #include "public/testing/WebTestRunner.h" 52 #include "public/web/WebAccessibilityNotification.h" 53 #include "public/web/WebAccessibilityObject.h" 54 #include "public/web/WebCachedURLRequest.h" 55 #include "public/web/WebConsoleMessage.h" 56 #include "public/web/WebDataSource.h" 57 #include "public/web/WebDeviceOrientationClientMock.h" 58 #include "public/web/WebDocument.h" 59 #include "public/web/WebElement.h" 60 #include "public/web/WebFrame.h" 61 #include "public/web/WebGeolocationClientMock.h" 62 #include "public/web/WebHistoryItem.h" 63 #include "public/web/WebNode.h" 64 #include "public/web/WebPluginParams.h" 65 #include "public/web/WebPrintParams.h" 66 #include "public/web/WebRange.h" 67 #include "public/web/WebScriptController.h" 68 #include "public/web/WebUserGestureIndicator.h" 69 #include "public/web/WebView.h" 70 71 // FIXME: Including platform_canvas.h here is a layering violation. 72 #include <cctype> 73 #include "skia/ext/platform_canvas.h" 74 75 using namespace WebKit; 76 using namespace std; 77 78 namespace WebTestRunner { 79 80 namespace { 81 82 class HostMethodTask : public WebMethodTask<WebTestProxyBase> { 83 public: 84 typedef void (WebTestProxyBase::*CallbackMethodType)(); 85 HostMethodTask(WebTestProxyBase* object, CallbackMethodType callback) 86 : WebMethodTask<WebTestProxyBase>(object) 87 , m_callback(callback) 88 { } 89 90 virtual void runIfValid() { (m_object->*m_callback)(); } 91 92 private: 93 CallbackMethodType m_callback; 94 }; 95 96 void printNodeDescription(WebTestDelegate* delegate, const WebNode& node, int exception) 97 { 98 if (exception) { 99 delegate->printMessage("ERROR"); 100 return; 101 } 102 if (node.isNull()) { 103 delegate->printMessage("(null)"); 104 return; 105 } 106 delegate->printMessage(node.nodeName().utf8().data()); 107 const WebNode& parent = node.parentNode(); 108 if (!parent.isNull()) { 109 delegate->printMessage(" > "); 110 printNodeDescription(delegate, parent, 0); 111 } 112 } 113 114 void printRangeDescription(WebTestDelegate* delegate, const WebRange& range) 115 { 116 if (range.isNull()) { 117 delegate->printMessage("(null)"); 118 return; 119 } 120 char buffer[100]; 121 snprintf(buffer, sizeof(buffer), "range from %d of ", range.startOffset()); 122 delegate->printMessage(buffer); 123 int exception = 0; 124 WebNode startNode = range.startContainer(exception); 125 printNodeDescription(delegate, startNode, exception); 126 snprintf(buffer, sizeof(buffer), " to %d of ", range.endOffset()); 127 delegate->printMessage(buffer); 128 WebNode endNode = range.endContainer(exception); 129 printNodeDescription(delegate, endNode, exception); 130 } 131 132 string editingActionDescription(WebEditingAction action) 133 { 134 switch (action) { 135 case WebKit::WebEditingActionTyped: 136 return "WebViewInsertActionTyped"; 137 case WebKit::WebEditingActionPasted: 138 return "WebViewInsertActionPasted"; 139 case WebKit::WebEditingActionDropped: 140 return "WebViewInsertActionDropped"; 141 } 142 return "(UNKNOWN ACTION)"; 143 } 144 145 string textAffinityDescription(WebTextAffinity affinity) 146 { 147 switch (affinity) { 148 case WebKit::WebTextAffinityUpstream: 149 return "NSSelectionAffinityUpstream"; 150 case WebKit::WebTextAffinityDownstream: 151 return "NSSelectionAffinityDownstream"; 152 } 153 return "(UNKNOWN AFFINITY)"; 154 } 155 156 void printFrameDescription(WebTestDelegate* delegate, WebFrame* frame) 157 { 158 string name8 = frame->uniqueName().utf8(); 159 if (frame == frame->view()->mainFrame()) { 160 if (!name8.length()) { 161 delegate->printMessage("main frame"); 162 return; 163 } 164 delegate->printMessage(string("main frame \"") + name8 + "\""); 165 return; 166 } 167 if (!name8.length()) { 168 delegate->printMessage("frame (anonymous)"); 169 return; 170 } 171 delegate->printMessage(string("frame \"") + name8 + "\""); 172 } 173 174 void printFrameUserGestureStatus(WebTestDelegate* delegate, WebFrame* frame, const char* msg) 175 { 176 bool isUserGesture = WebUserGestureIndicator::isProcessingUserGesture(); 177 delegate->printMessage(string("Frame with user gesture \"") + (isUserGesture ? "true" : "false") + "\"" + msg); 178 } 179 180 // Used to write a platform neutral file:/// URL by taking the 181 // filename and its directory. (e.g., converts 182 // "file:///tmp/foo/bar.txt" to just "bar.txt"). 183 string descriptionSuitableForTestResult(const string& url) 184 { 185 if (url.empty() || string::npos == url.find("file://")) 186 return url; 187 188 size_t pos = url.rfind('/'); 189 if (pos == string::npos || !pos) 190 return "ERROR:" + url; 191 pos = url.rfind('/', pos - 1); 192 if (pos == string::npos) 193 return "ERROR:" + url; 194 195 return url.substr(pos + 1); 196 } 197 198 void printResponseDescription(WebTestDelegate* delegate, const WebURLResponse& response) 199 { 200 if (response.isNull()) { 201 delegate->printMessage("(null)"); 202 return; 203 } 204 string url = response.url().spec(); 205 char data[100]; 206 snprintf(data, sizeof(data), "%d", response. httpStatusCode()); 207 delegate->printMessage(string("<NSURLResponse ") + descriptionSuitableForTestResult(url) + ", http status code " + data + ">"); 208 } 209 210 string URLDescription(const GURL& url) 211 { 212 if (url.SchemeIs("file")) 213 return url.ExtractFileName(); 214 return url.possibly_invalid_spec(); 215 } 216 217 string PriorityDescription(const WebURLRequest::Priority& priority) 218 { 219 switch (priority) { 220 case WebURLRequest::PriorityVeryLow: 221 return "VeryLow"; 222 case WebURLRequest::PriorityLow: 223 return "Low"; 224 case WebURLRequest::PriorityMedium: 225 return "Medium"; 226 case WebURLRequest::PriorityHigh: 227 return "High"; 228 case WebURLRequest::PriorityVeryHigh: 229 return "VeryHigh"; 230 case WebURLRequest::PriorityUnresolved: 231 default: 232 return "Unresolved"; 233 } 234 } 235 236 void blockRequest(WebURLRequest& request) 237 { 238 request.setURL(GURL("255.255.255.255")); 239 } 240 241 bool isLocalhost(const string& host) 242 { 243 return host == "127.0.0.1" || host == "localhost"; 244 } 245 246 bool hostIsUsedBySomeTestsToGenerateError(const string& host) 247 { 248 return host == "255.255.255.255"; 249 } 250 251 // Used to write a platform neutral file:/// URL by only taking the filename 252 // (e.g., converts "file:///tmp/foo.txt" to just "foo.txt"). 253 string urlSuitableForTestResult(const string& url) 254 { 255 if (url.empty() || string::npos == url.find("file://")) 256 return url; 257 258 size_t pos = url.rfind('/'); 259 if (pos == string::npos) { 260 #ifdef WIN32 261 pos = url.rfind('\\'); 262 if (pos == string::npos) 263 pos = 0; 264 #else 265 pos = 0; 266 #endif 267 } 268 string filename = url.substr(pos + 1); 269 if (filename.empty()) 270 return "file:"; // A WebKit test has this in its expected output. 271 return filename; 272 } 273 274 // WebNavigationType debugging strings taken from PolicyDelegate.mm. 275 const char* linkClickedString = "link clicked"; 276 const char* formSubmittedString = "form submitted"; 277 const char* backForwardString = "back/forward"; 278 const char* reloadString = "reload"; 279 const char* formResubmittedString = "form resubmitted"; 280 const char* otherString = "other"; 281 const char* illegalString = "illegal value"; 282 283 // Get a debugging string from a WebNavigationType. 284 const char* webNavigationTypeToString(WebNavigationType type) 285 { 286 switch (type) { 287 case WebKit::WebNavigationTypeLinkClicked: 288 return linkClickedString; 289 case WebKit::WebNavigationTypeFormSubmitted: 290 return formSubmittedString; 291 case WebKit::WebNavigationTypeBackForward: 292 return backForwardString; 293 case WebKit::WebNavigationTypeReload: 294 return reloadString; 295 case WebKit::WebNavigationTypeFormResubmitted: 296 return formResubmittedString; 297 case WebKit::WebNavigationTypeOther: 298 return otherString; 299 } 300 return illegalString; 301 } 302 303 string dumpDocumentText(WebFrame* frame) 304 { 305 // We use the document element's text instead of the body text here because 306 // not all documents have a body, such as XML documents. 307 WebElement documentElement = frame->document().documentElement(); 308 if (documentElement.isNull()) 309 return string(); 310 return documentElement.innerText().utf8(); 311 } 312 313 string dumpFramesAsText(WebFrame* frame, bool recursive) 314 { 315 string result; 316 317 // Add header for all but the main frame. Skip empty frames. 318 if (frame->parent() && !frame->document().documentElement().isNull()) { 319 result.append("\n--------\nFrame: '"); 320 result.append(frame->uniqueName().utf8().data()); 321 result.append("'\n--------\n"); 322 } 323 324 result.append(dumpDocumentText(frame)); 325 result.append("\n"); 326 327 if (recursive) { 328 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling()) 329 result.append(dumpFramesAsText(child, recursive)); 330 } 331 332 return result; 333 } 334 335 string dumpFramesAsPrintedText(WebFrame* frame, bool recursive) 336 { 337 string result; 338 339 // Cannot do printed format for anything other than HTML 340 if (!frame->document().isHTMLDocument()) 341 return string(); 342 343 // Add header for all but the main frame. Skip empty frames. 344 if (frame->parent() && !frame->document().documentElement().isNull()) { 345 result.append("\n--------\nFrame: '"); 346 result.append(frame->uniqueName().utf8().data()); 347 result.append("'\n--------\n"); 348 } 349 350 result.append(frame->renderTreeAsText(WebFrame::RenderAsTextPrinting).utf8()); 351 result.append("\n"); 352 353 if (recursive) { 354 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling()) 355 result.append(dumpFramesAsPrintedText(child, recursive)); 356 } 357 358 return result; 359 } 360 361 string dumpFrameScrollPosition(WebFrame* frame, bool recursive) 362 { 363 string result; 364 WebSize offset = frame->scrollOffset(); 365 if (offset.width > 0 || offset.height > 0) { 366 if (frame->parent()) 367 result = string("frame '") + frame->uniqueName().utf8().data() + "' "; 368 char data[100]; 369 snprintf(data, sizeof(data), "scrolled to %d,%d\n", offset.width, offset.height); 370 result += data; 371 } 372 373 if (!recursive) 374 return result; 375 for (WebFrame* child = frame->firstChild(); child; child = child->nextSibling()) 376 result += dumpFrameScrollPosition(child, recursive); 377 return result; 378 } 379 380 struct ToLower { 381 char16 operator()(char16 c) { return tolower(c); } 382 }; 383 384 // Returns True if item1 < item2. 385 bool HistoryItemCompareLess(const WebHistoryItem& item1, const WebHistoryItem& item2) 386 { 387 string16 target1 = item1.target(); 388 string16 target2 = item2.target(); 389 std::transform(target1.begin(), target1.end(), target1.begin(), ToLower()); 390 std::transform(target2.begin(), target2.end(), target2.begin(), ToLower()); 391 return target1 < target2; 392 } 393 394 string dumpHistoryItem(const WebHistoryItem& item, int indent, bool isCurrent) 395 { 396 string result; 397 398 if (isCurrent) { 399 result.append("curr->"); 400 result.append(indent - 6, ' '); // 6 == "curr->".length() 401 } else 402 result.append(indent, ' '); 403 404 string url = normalizeLayoutTestURL(item.urlString().utf8()); 405 result.append(url); 406 if (!item.target().isEmpty()) { 407 result.append(" (in frame \""); 408 result.append(item.target().utf8()); 409 result.append("\")"); 410 } 411 if (item.isTargetItem()) 412 result.append(" **nav target**"); 413 result.append("\n"); 414 415 const WebVector<WebHistoryItem>& children = item.children(); 416 if (!children.isEmpty()) { 417 // Must sort to eliminate arbitrary result ordering which defeats 418 // reproducible testing. 419 // FIXME: WebVector should probably just be a std::vector!! 420 std::vector<WebHistoryItem> sortedChildren; 421 for (size_t i = 0; i < children.size(); ++i) 422 sortedChildren.push_back(children[i]); 423 std::sort(sortedChildren.begin(), sortedChildren.end(), HistoryItemCompareLess); 424 for (size_t i = 0; i < sortedChildren.size(); ++i) 425 result += dumpHistoryItem(sortedChildren[i], indent + 4, false); 426 } 427 428 return result; 429 } 430 431 void dumpBackForwardList(const WebVector<WebHistoryItem>& history, size_t currentEntryIndex, string& result) 432 { 433 result.append("\n============== Back Forward List ==============\n"); 434 for (size_t index = 0; index < history.size(); ++index) 435 result.append(dumpHistoryItem(history[index], 8, index == currentEntryIndex)); 436 result.append("===============================================\n"); 437 } 438 439 string dumpAllBackForwardLists(TestInterfaces* interfaces, WebTestDelegate* delegate) 440 { 441 string result; 442 const vector<WebTestProxyBase*>& windowList = interfaces->windowList(); 443 for (unsigned i = 0; i < windowList.size(); ++i) { 444 size_t currentEntryIndex = 0; 445 WebVector<WebHistoryItem> history; 446 delegate->captureHistoryForWindow(windowList.at(i), &history, ¤tEntryIndex); 447 dumpBackForwardList(history, currentEntryIndex, result); 448 } 449 return result; 450 } 451 452 } 453 454 WebTestProxyBase::WebTestProxyBase() 455 : m_testInterfaces(0) 456 , m_delegate(0) 457 , m_webWidget(0) 458 , m_spellcheck(new SpellCheckClient) 459 , m_chooserCount(0) 460 , m_validationMessageClient(new MockWebValidationMessageClient()) 461 { 462 reset(); 463 } 464 465 WebTestProxyBase::~WebTestProxyBase() 466 { 467 m_testInterfaces->windowClosed(this); 468 } 469 470 void WebTestProxyBase::setInterfaces(WebTestInterfaces* interfaces) 471 { 472 m_testInterfaces = interfaces->testInterfaces(); 473 m_testInterfaces->windowOpened(this); 474 } 475 476 void WebTestProxyBase::setDelegate(WebTestDelegate* delegate) 477 { 478 m_delegate = delegate; 479 m_spellcheck->setDelegate(delegate); 480 m_validationMessageClient->setDelegate(delegate); 481 #if ENABLE_INPUT_SPEECH 482 if (m_speechInputController.get()) 483 m_speechInputController->setDelegate(delegate); 484 #endif 485 if (m_speechRecognizer.get()) 486 m_speechRecognizer->setDelegate(delegate); 487 } 488 489 void WebTestProxyBase::setWidget(WebWidget* widget) 490 { 491 m_webWidget = widget; 492 } 493 494 WebWidget* WebTestProxyBase::webWidget() 495 { 496 return m_webWidget; 497 } 498 499 WebView* WebTestProxyBase::webView() 500 { 501 WEBKIT_ASSERT(m_webWidget); 502 // TestRunner does not support popup widgets. So m_webWidget is always a WebView. 503 return static_cast<WebView*>(m_webWidget); 504 } 505 506 void WebTestProxyBase::reset() 507 { 508 m_paintRect = WebRect(); 509 m_canvas.reset(); 510 m_isPainting = false; 511 m_animateScheduled = false; 512 m_resourceIdentifierMap.clear(); 513 m_logConsoleOutput = true; 514 if (m_geolocationClient.get()) 515 m_geolocationClient->resetMock(); 516 #if ENABLE_INPUT_SPEECH 517 if (m_speechInputController.get()) 518 m_speechInputController->clearResults(); 519 #endif 520 } 521 522 WebSpellCheckClient* WebTestProxyBase::spellCheckClient() const 523 { 524 return m_spellcheck.get(); 525 } 526 527 WebValidationMessageClient* WebTestProxyBase::validationMessageClient() 528 { 529 return m_validationMessageClient.get(); 530 } 531 532 WebColorChooser* WebTestProxyBase::createColorChooser(WebColorChooserClient* client, const WebKit::WebColor& color) 533 { 534 // This instance is deleted by WebCore::ColorInputType 535 return new MockColorChooser(client, m_delegate, this); 536 } 537 538 string WebTestProxyBase::captureTree(bool debugRenderTree) 539 { 540 WebScriptController::flushConsoleMessages(); 541 542 bool shouldDumpAsText = m_testInterfaces->testRunner()->shouldDumpAsText(); 543 bool shouldDumpAsPrinted = m_testInterfaces->testRunner()->isPrinting(); 544 WebFrame* frame = webView()->mainFrame(); 545 string dataUtf8; 546 if (shouldDumpAsText) { 547 bool recursive = m_testInterfaces->testRunner()->shouldDumpChildFramesAsText(); 548 dataUtf8 = shouldDumpAsPrinted ? dumpFramesAsPrintedText(frame, recursive) : dumpFramesAsText(frame, recursive); 549 } else { 550 bool recursive = m_testInterfaces->testRunner()->shouldDumpChildFrameScrollPositions(); 551 WebFrame::RenderAsTextControls renderTextBehavior = WebFrame::RenderAsTextNormal; 552 if (shouldDumpAsPrinted) 553 renderTextBehavior |= WebFrame::RenderAsTextPrinting; 554 if (debugRenderTree) 555 renderTextBehavior |= WebFrame::RenderAsTextDebug; 556 dataUtf8 = frame->renderTreeAsText(renderTextBehavior).utf8(); 557 dataUtf8 += dumpFrameScrollPosition(frame, recursive); 558 } 559 560 if (m_testInterfaces->testRunner()->shouldDumpBackForwardList()) 561 dataUtf8 += dumpAllBackForwardLists(m_testInterfaces, m_delegate); 562 563 return dataUtf8; 564 } 565 566 SkCanvas* WebTestProxyBase::capturePixels() 567 { 568 webWidget()->layout(); 569 if (m_testInterfaces->testRunner()->testRepaint()) { 570 WebSize viewSize = webWidget()->size(); 571 int width = viewSize.width; 572 int height = viewSize.height; 573 if (m_testInterfaces->testRunner()->sweepHorizontally()) { 574 for (WebRect column(0, 0, 1, height); column.x < width; column.x++) 575 paintRect(column); 576 } else { 577 for (WebRect line(0, 0, width, 1); line.y < height; line.y++) 578 paintRect(line); 579 } 580 } else if (m_testInterfaces->testRunner()->isPrinting()) 581 paintPagesWithBoundaries(); 582 else 583 paintInvalidatedRegion(); 584 585 // See if we need to draw the selection bounds rect. Selection bounds 586 // rect is the rect enclosing the (possibly transformed) selection. 587 // The rect should be drawn after everything is laid out and painted. 588 if (m_testInterfaces->testRunner()->shouldDumpSelectionRect()) { 589 // If there is a selection rect - draw a red 1px border enclosing rect 590 WebRect wr = webView()->mainFrame()->selectionBoundsRect(); 591 if (!wr.isEmpty()) { 592 // Render a red rectangle bounding selection rect 593 SkPaint paint; 594 paint.setColor(0xFFFF0000); // Fully opaque red 595 paint.setStyle(SkPaint::kStroke_Style); 596 paint.setFlags(SkPaint::kAntiAlias_Flag); 597 paint.setStrokeWidth(1.0f); 598 SkIRect rect; // Bounding rect 599 rect.set(wr.x, wr.y, wr.x + wr.width, wr.y + wr.height); 600 canvas()->drawIRect(rect, paint); 601 } 602 } 603 604 return canvas(); 605 } 606 607 void WebTestProxyBase::setLogConsoleOutput(bool enabled) 608 { 609 m_logConsoleOutput = enabled; 610 } 611 612 void WebTestProxyBase::paintRect(const WebRect& rect) 613 { 614 WEBKIT_ASSERT(!m_isPainting); 615 WEBKIT_ASSERT(canvas()); 616 m_isPainting = true; 617 float deviceScaleFactor = webView()->deviceScaleFactor(); 618 int scaledX = static_cast<int>(static_cast<float>(rect.x) * deviceScaleFactor); 619 int scaledY = static_cast<int>(static_cast<float>(rect.y) * deviceScaleFactor); 620 int scaledWidth = static_cast<int>(ceil(static_cast<float>(rect.width) * deviceScaleFactor)); 621 int scaledHeight = static_cast<int>(ceil(static_cast<float>(rect.height) * deviceScaleFactor)); 622 WebRect deviceRect(scaledX, scaledY, scaledWidth, scaledHeight); 623 webWidget()->paint(canvas(), deviceRect); 624 m_isPainting = false; 625 } 626 627 void WebTestProxyBase::paintInvalidatedRegion() 628 { 629 webWidget()->animate(0.0); 630 webWidget()->layout(); 631 WebSize widgetSize = webWidget()->size(); 632 WebRect clientRect(0, 0, widgetSize.width, widgetSize.height); 633 634 // Paint the canvas if necessary. Allow painting to generate extra rects 635 // for the first two calls. This is necessary because some WebCore rendering 636 // objects update their layout only when painted. 637 // Store the total area painted in total_paint. Then tell the gdk window 638 // to update that area after we're done painting it. 639 for (int i = 0; i < 3; ++i) { 640 // rect = intersect(m_paintRect , clientRect) 641 WebRect damageRect = m_paintRect; 642 int left = max(damageRect.x, clientRect.x); 643 int top = max(damageRect.y, clientRect.y); 644 int right = min(damageRect.x + damageRect.width, clientRect.x + clientRect.width); 645 int bottom = min(damageRect.y + damageRect.height, clientRect.y + clientRect.height); 646 WebRect rect; 647 if (left < right && top < bottom) 648 rect = WebRect(left, top, right - left, bottom - top); 649 650 m_paintRect = WebRect(); 651 if (rect.isEmpty()) 652 continue; 653 paintRect(rect); 654 } 655 WEBKIT_ASSERT(m_paintRect.isEmpty()); 656 } 657 658 void WebTestProxyBase::paintPagesWithBoundaries() 659 { 660 WEBKIT_ASSERT(!m_isPainting); 661 WEBKIT_ASSERT(canvas()); 662 m_isPainting = true; 663 664 WebSize pageSizeInPixels = webWidget()->size(); 665 WebFrame* webFrame = webView()->mainFrame(); 666 667 int pageCount = webFrame->printBegin(pageSizeInPixels); 668 int totalHeight = pageCount * (pageSizeInPixels.height + 1) - 1; 669 670 SkCanvas* testCanvas = skia::TryCreateBitmapCanvas(pageSizeInPixels.width, totalHeight, true); 671 if (testCanvas) { 672 discardBackingStore(); 673 m_canvas.reset(testCanvas); 674 } else { 675 webFrame->printEnd(); 676 return; 677 } 678 679 webFrame->printPagesWithBoundaries(canvas(), pageSizeInPixels); 680 webFrame->printEnd(); 681 682 m_isPainting = false; 683 } 684 685 SkCanvas* WebTestProxyBase::canvas() 686 { 687 if (m_canvas.get()) 688 return m_canvas.get(); 689 WebSize widgetSize = webWidget()->size(); 690 float deviceScaleFactor = webView()->deviceScaleFactor(); 691 int scaledWidth = static_cast<int>(ceil(static_cast<float>(widgetSize.width) * deviceScaleFactor)); 692 int scaledHeight = static_cast<int>(ceil(static_cast<float>(widgetSize.height) * deviceScaleFactor)); 693 m_canvas.reset(skia::CreateBitmapCanvas(scaledWidth, scaledHeight, true)); 694 return m_canvas.get(); 695 } 696 697 // Paints the entire canvas a semi-transparent black (grayish). This is used 698 // by the layout tests in fast/repaint. The alpha value matches upstream. 699 void WebTestProxyBase::displayRepaintMask() 700 { 701 canvas()->drawARGB(167, 0, 0, 0); 702 } 703 704 void WebTestProxyBase::display() 705 { 706 const WebKit::WebSize& size = webWidget()->size(); 707 WebRect rect(0, 0, size.width, size.height); 708 m_paintRect = rect; 709 paintInvalidatedRegion(); 710 displayRepaintMask(); 711 } 712 713 void WebTestProxyBase::displayInvalidatedRegion() 714 { 715 paintInvalidatedRegion(); 716 displayRepaintMask(); 717 } 718 719 void WebTestProxyBase::discardBackingStore() 720 { 721 m_canvas.reset(); 722 } 723 724 WebGeolocationClientMock* WebTestProxyBase::geolocationClientMock() 725 { 726 if (!m_geolocationClient.get()) 727 m_geolocationClient.reset(WebGeolocationClientMock::create()); 728 return m_geolocationClient.get(); 729 } 730 731 WebDeviceOrientationClientMock* WebTestProxyBase::deviceOrientationClientMock() 732 { 733 if (!m_deviceOrientationClient.get()) 734 m_deviceOrientationClient.reset(WebDeviceOrientationClientMock::create()); 735 return m_deviceOrientationClient.get(); 736 } 737 738 #if ENABLE_INPUT_SPEECH 739 MockWebSpeechInputController* WebTestProxyBase::speechInputControllerMock() 740 { 741 WEBKIT_ASSERT(m_speechInputController.get()); 742 return m_speechInputController.get(); 743 } 744 #endif 745 746 MockWebSpeechRecognizer* WebTestProxyBase::speechRecognizerMock() 747 { 748 if (!m_speechRecognizer.get()) { 749 m_speechRecognizer.reset(new MockWebSpeechRecognizer()); 750 m_speechRecognizer->setDelegate(m_delegate); 751 } 752 return m_speechRecognizer.get(); 753 } 754 755 void WebTestProxyBase::didInvalidateRect(const WebRect& rect) 756 { 757 // m_paintRect = m_paintRect U rect 758 if (rect.isEmpty()) 759 return; 760 if (m_paintRect.isEmpty()) { 761 m_paintRect = rect; 762 return; 763 } 764 int left = min(m_paintRect.x, rect.x); 765 int top = min(m_paintRect.y, rect.y); 766 int right = max(m_paintRect.x + m_paintRect.width, rect.x + rect.width); 767 int bottom = max(m_paintRect.y + m_paintRect.height, rect.y + rect.height); 768 m_paintRect = WebRect(left, top, right - left, bottom - top); 769 } 770 771 void WebTestProxyBase::didScrollRect(int, int, const WebRect& clipRect) 772 { 773 didInvalidateRect(clipRect); 774 } 775 776 void WebTestProxyBase::invalidateAll() 777 { 778 m_paintRect = WebRect(0, 0, INT_MAX, INT_MAX); 779 } 780 781 void WebTestProxyBase::scheduleComposite() 782 { 783 invalidateAll(); 784 } 785 786 void WebTestProxyBase::scheduleAnimation() 787 { 788 if (!m_testInterfaces->testRunner()->testIsRunning()) 789 return; 790 791 if (!m_animateScheduled) { 792 m_animateScheduled = true; 793 m_delegate->postDelayedTask(new HostMethodTask(this, &WebTestProxyBase::animateNow), 1); 794 } 795 } 796 797 void WebTestProxyBase::animateNow() 798 { 799 if (m_animateScheduled) { 800 m_animateScheduled = false; 801 webWidget()->animate(0.0); 802 } 803 } 804 805 void WebTestProxyBase::show(WebNavigationPolicy) 806 { 807 invalidateAll(); 808 } 809 810 void WebTestProxyBase::setWindowRect(const WebRect& rect) 811 { 812 invalidateAll(); 813 discardBackingStore(); 814 } 815 816 void WebTestProxyBase::didAutoResize(const WebSize&) 817 { 818 invalidateAll(); 819 } 820 821 void WebTestProxyBase::postAccessibilityNotification(const WebKit::WebAccessibilityObject& obj, WebKit::WebAccessibilityNotification notification) 822 { 823 if (notification == WebKit::WebAccessibilityNotificationFocusedUIElementChanged) 824 m_testInterfaces->accessibilityController()->setFocusedElement(obj); 825 826 const char* notificationName; 827 switch (notification) { 828 case WebKit::WebAccessibilityNotificationActiveDescendantChanged: 829 notificationName = "ActiveDescendantChanged"; 830 break; 831 case WebKit::WebAccessibilityNotificationAutocorrectionOccured: 832 notificationName = "AutocorrectionOccured"; 833 break; 834 case WebKit::WebAccessibilityNotificationCheckedStateChanged: 835 notificationName = "CheckedStateChanged"; 836 break; 837 case WebKit::WebAccessibilityNotificationChildrenChanged: 838 notificationName = "ChildrenChanged"; 839 break; 840 case WebKit::WebAccessibilityNotificationFocusedUIElementChanged: 841 notificationName = "FocusedUIElementChanged"; 842 break; 843 case WebKit::WebAccessibilityNotificationLayoutComplete: 844 notificationName = "LayoutComplete"; 845 break; 846 case WebKit::WebAccessibilityNotificationLoadComplete: 847 notificationName = "LoadComplete"; 848 break; 849 case WebKit::WebAccessibilityNotificationSelectedChildrenChanged: 850 notificationName = "SelectedChildrenChanged"; 851 break; 852 case WebKit::WebAccessibilityNotificationSelectedTextChanged: 853 notificationName = "SelectedTextChanged"; 854 break; 855 case WebKit::WebAccessibilityNotificationValueChanged: 856 notificationName = "ValueChanged"; 857 break; 858 case WebKit::WebAccessibilityNotificationScrolledToAnchor: 859 notificationName = "ScrolledToAnchor"; 860 break; 861 case WebKit::WebAccessibilityNotificationLiveRegionChanged: 862 notificationName = "LiveRegionChanged"; 863 break; 864 case WebKit::WebAccessibilityNotificationMenuListItemSelected: 865 notificationName = "MenuListItemSelected"; 866 break; 867 case WebKit::WebAccessibilityNotificationMenuListValueChanged: 868 notificationName = "MenuListValueChanged"; 869 break; 870 case WebKit::WebAccessibilityNotificationRowCountChanged: 871 notificationName = "RowCountChanged"; 872 break; 873 case WebKit::WebAccessibilityNotificationRowCollapsed: 874 notificationName = "RowCollapsed"; 875 break; 876 case WebKit::WebAccessibilityNotificationRowExpanded: 877 notificationName = "RowExpanded"; 878 break; 879 case WebKit::WebAccessibilityNotificationInvalidStatusChanged: 880 notificationName = "InvalidStatusChanged"; 881 break; 882 case WebKit::WebAccessibilityNotificationTextChanged: 883 notificationName = "TextChanged"; 884 break; 885 case WebKit::WebAccessibilityNotificationAriaAttributeChanged: 886 notificationName = "AriaAttributeChanged"; 887 break; 888 default: 889 notificationName = "UnknownNotification"; 890 break; 891 } 892 893 m_testInterfaces->accessibilityController()->notificationReceived(obj, notificationName); 894 895 if (m_testInterfaces->accessibilityController()->shouldLogAccessibilityEvents()) { 896 string message("AccessibilityNotification - "); 897 message += notificationName; 898 899 WebKit::WebNode node = obj.node(); 900 if (!node.isNull() && node.isElementNode()) { 901 WebKit::WebElement element = node.to<WebKit::WebElement>(); 902 if (element.hasAttribute("id")) { 903 message += " - id:"; 904 message += element.getAttribute("id").utf8().data(); 905 } 906 } 907 908 m_delegate->printMessage(message + "\n"); 909 } 910 } 911 912 void WebTestProxyBase::startDragging(WebFrame*, const WebDragData& data, WebDragOperationsMask mask, const WebImage&, const WebPoint&) 913 { 914 // When running a test, we need to fake a drag drop operation otherwise 915 // Windows waits for real mouse events to know when the drag is over. 916 m_testInterfaces->eventSender()->doDragDrop(data, mask); 917 } 918 919 // The output from these methods in layout test mode should match that 920 // expected by the layout tests. See EditingDelegate.m in DumpRenderTree. 921 922 bool WebTestProxyBase::shouldBeginEditing(const WebRange& range) 923 { 924 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) { 925 m_delegate->printMessage("EDITING DELEGATE: shouldBeginEditingInDOMRange:"); 926 printRangeDescription(m_delegate, range); 927 m_delegate->printMessage("\n"); 928 } 929 return true; 930 } 931 932 bool WebTestProxyBase::shouldEndEditing(const WebRange& range) 933 { 934 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) { 935 m_delegate->printMessage("EDITING DELEGATE: shouldEndEditingInDOMRange:"); 936 printRangeDescription(m_delegate, range); 937 m_delegate->printMessage("\n"); 938 } 939 return true; 940 } 941 942 bool WebTestProxyBase::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action) 943 { 944 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) { 945 m_delegate->printMessage("EDITING DELEGATE: shouldInsertNode:"); 946 printNodeDescription(m_delegate, node, 0); 947 m_delegate->printMessage(" replacingDOMRange:"); 948 printRangeDescription(m_delegate, range); 949 m_delegate->printMessage(string(" givenAction:") + editingActionDescription(action) + "\n"); 950 } 951 return true; 952 } 953 954 bool WebTestProxyBase::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action) 955 { 956 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) { 957 m_delegate->printMessage(string("EDITING DELEGATE: shouldInsertText:") + text.utf8().data() + " replacingDOMRange:"); 958 printRangeDescription(m_delegate, range); 959 m_delegate->printMessage(string(" givenAction:") + editingActionDescription(action) + "\n"); 960 } 961 return true; 962 } 963 964 bool WebTestProxyBase::shouldChangeSelectedRange( 965 const WebRange& fromRange, const WebRange& toRange, WebTextAffinity affinity, bool stillSelecting) 966 { 967 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) { 968 m_delegate->printMessage("EDITING DELEGATE: shouldChangeSelectedDOMRange:"); 969 printRangeDescription(m_delegate, fromRange); 970 m_delegate->printMessage(" toDOMRange:"); 971 printRangeDescription(m_delegate, toRange); 972 m_delegate->printMessage(string(" affinity:") + textAffinityDescription(affinity) + " stillSelecting:" + (stillSelecting ? "TRUE" : "FALSE") + "\n"); 973 } 974 return true; 975 } 976 977 bool WebTestProxyBase::shouldDeleteRange(const WebRange& range) 978 { 979 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) { 980 m_delegate->printMessage("EDITING DELEGATE: shouldDeleteDOMRange:"); 981 printRangeDescription(m_delegate, range); 982 m_delegate->printMessage("\n"); 983 } 984 return true; 985 } 986 987 bool WebTestProxyBase::shouldApplyStyle(const WebString& style, const WebRange& range) 988 { 989 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) { 990 m_delegate->printMessage(string("EDITING DELEGATE: shouldApplyStyle:") + style.utf8().data() + " toElementsInDOMRange:"); 991 printRangeDescription(m_delegate, range); 992 m_delegate->printMessage("\n"); 993 } 994 return true; 995 } 996 997 void WebTestProxyBase::didBeginEditing() 998 { 999 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) 1000 m_delegate->printMessage("EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification\n"); 1001 } 1002 1003 void WebTestProxyBase::didChangeSelection(bool isEmptySelection) 1004 { 1005 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) 1006 m_delegate->printMessage("EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification\n"); 1007 } 1008 1009 void WebTestProxyBase::didChangeContents() 1010 { 1011 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) 1012 m_delegate->printMessage("EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification\n"); 1013 } 1014 1015 void WebTestProxyBase::didEndEditing() 1016 { 1017 if (m_testInterfaces->testRunner()->shouldDumpEditingCallbacks()) 1018 m_delegate->printMessage("EDITING DELEGATE: webViewDidEndEditing:WebViewDidEndEditingNotification\n"); 1019 } 1020 1021 bool WebTestProxyBase::createView(WebFrame*, const WebURLRequest& request, const WebWindowFeatures&, const WebString&, WebNavigationPolicy) 1022 { 1023 if (!m_testInterfaces->testRunner()->canOpenWindows()) 1024 return false; 1025 if (m_testInterfaces->testRunner()->shouldDumpCreateView()) 1026 m_delegate->printMessage(string("createView(") + URLDescription(request.url()) + ")\n"); 1027 return true; 1028 } 1029 1030 WebPlugin* WebTestProxyBase::createPlugin(WebFrame* frame, const WebPluginParams& params) 1031 { 1032 if (params.mimeType == TestPlugin::mimeType()) 1033 return TestPlugin::create(frame, params, m_delegate); 1034 return 0; 1035 } 1036 1037 void WebTestProxyBase::setStatusText(const WebString& text) 1038 { 1039 if (!m_testInterfaces->testRunner()->shouldDumpStatusCallbacks()) 1040 return; 1041 m_delegate->printMessage(string("UI DELEGATE STATUS CALLBACK: setStatusText:") + text.utf8().data() + "\n"); 1042 } 1043 1044 void WebTestProxyBase::didStopLoading() 1045 { 1046 if (m_testInterfaces->testRunner()->shouldDumpProgressFinishedCallback()) 1047 m_delegate->printMessage("postProgressFinishedNotification\n"); 1048 } 1049 1050 void WebTestProxyBase::showContextMenu(WebFrame*, const WebContextMenuData& contextMenuData) 1051 { 1052 m_testInterfaces->eventSender()->setContextMenuData(contextMenuData); 1053 } 1054 1055 WebUserMediaClient* WebTestProxyBase::userMediaClient() 1056 { 1057 if (!m_userMediaClient.get()) 1058 m_userMediaClient.reset(new WebUserMediaClientMock(m_delegate)); 1059 return m_userMediaClient.get(); 1060 } 1061 1062 // Simulate a print by going into print mode and then exit straight away. 1063 void WebTestProxyBase::printPage(WebFrame* frame) 1064 { 1065 WebSize pageSizeInPixels = webWidget()->size(); 1066 if (pageSizeInPixels.isEmpty()) 1067 return; 1068 WebPrintParams printParams(pageSizeInPixels); 1069 frame->printBegin(printParams); 1070 frame->printEnd(); 1071 } 1072 1073 WebNotificationPresenter* WebTestProxyBase::notificationPresenter() 1074 { 1075 #if ENABLE_NOTIFICATIONS 1076 return m_testInterfaces->testRunner()->notificationPresenter(); 1077 #else 1078 return 0; 1079 #endif 1080 } 1081 1082 WebGeolocationClient* WebTestProxyBase::geolocationClient() 1083 { 1084 return geolocationClientMock(); 1085 } 1086 1087 WebSpeechInputController* WebTestProxyBase::speechInputController(WebSpeechInputListener* listener) 1088 { 1089 #if ENABLE_INPUT_SPEECH 1090 if (!m_speechInputController.get()) { 1091 m_speechInputController.reset(new MockWebSpeechInputController(listener)); 1092 m_speechInputController->setDelegate(m_delegate); 1093 } 1094 return m_speechInputController.get(); 1095 #else 1096 WEBKIT_ASSERT(listener); 1097 return 0; 1098 #endif 1099 } 1100 1101 WebSpeechRecognizer* WebTestProxyBase::speechRecognizer() 1102 { 1103 return speechRecognizerMock(); 1104 } 1105 1106 WebDeviceOrientationClient* WebTestProxyBase::deviceOrientationClient() 1107 { 1108 return deviceOrientationClientMock(); 1109 } 1110 1111 bool WebTestProxyBase::requestPointerLock() 1112 { 1113 return m_testInterfaces->testRunner()->requestPointerLock(); 1114 } 1115 1116 void WebTestProxyBase::requestPointerUnlock() 1117 { 1118 m_testInterfaces->testRunner()->requestPointerUnlock(); 1119 } 1120 1121 bool WebTestProxyBase::isPointerLocked() 1122 { 1123 return m_testInterfaces->testRunner()->isPointerLocked(); 1124 } 1125 1126 void WebTestProxyBase::didFocus() 1127 { 1128 m_delegate->setFocus(this, true); 1129 } 1130 1131 void WebTestProxyBase::didBlur() 1132 { 1133 m_delegate->setFocus(this, false); 1134 } 1135 1136 void WebTestProxyBase::setToolTipText(const WebString& text, WebTextDirection) 1137 { 1138 m_testInterfaces->testRunner()->setToolTipText(text); 1139 } 1140 1141 void WebTestProxyBase::didOpenChooser() 1142 { 1143 m_chooserCount++; 1144 } 1145 1146 void WebTestProxyBase::didCloseChooser() 1147 { 1148 m_chooserCount--; 1149 } 1150 1151 bool WebTestProxyBase::isChooserShown() 1152 { 1153 return 0 < m_chooserCount; 1154 } 1155 1156 void WebTestProxyBase::didStartProvisionalLoad(WebFrame* frame) 1157 { 1158 if (!m_testInterfaces->testRunner()->topLoadingFrame()) 1159 m_testInterfaces->testRunner()->setTopLoadingFrame(frame, false); 1160 1161 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1162 printFrameDescription(m_delegate, frame); 1163 m_delegate->printMessage(" - didStartProvisionalLoadForFrame\n"); 1164 } 1165 1166 if (m_testInterfaces->testRunner()->shouldDumpUserGestureInFrameLoadCallbacks()) 1167 printFrameUserGestureStatus(m_delegate, frame, " - in didStartProvisionalLoadForFrame\n"); 1168 } 1169 1170 void WebTestProxyBase::didReceiveServerRedirectForProvisionalLoad(WebFrame* frame) 1171 { 1172 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1173 printFrameDescription(m_delegate, frame); 1174 m_delegate->printMessage(" - didReceiveServerRedirectForProvisionalLoadForFrame\n"); 1175 } 1176 } 1177 1178 bool WebTestProxyBase::didFailProvisionalLoad(WebFrame* frame, const WebURLError&) 1179 { 1180 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1181 printFrameDescription(m_delegate, frame); 1182 m_delegate->printMessage(" - didFailProvisionalLoadWithError\n"); 1183 } 1184 locationChangeDone(frame); 1185 return !frame->provisionalDataSource(); 1186 } 1187 1188 void WebTestProxyBase::didCommitProvisionalLoad(WebFrame* frame, bool) 1189 { 1190 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1191 printFrameDescription(m_delegate, frame); 1192 m_delegate->printMessage(" - didCommitLoadForFrame\n"); 1193 } 1194 } 1195 1196 void WebTestProxyBase::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction) 1197 { 1198 WebCString title8 = title.utf8(); 1199 1200 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1201 printFrameDescription(m_delegate, frame); 1202 m_delegate->printMessage(string(" - didReceiveTitle: ") + title8.data() + "\n"); 1203 } 1204 1205 if (m_testInterfaces->testRunner()->shouldDumpTitleChanges()) 1206 m_delegate->printMessage(string("TITLE CHANGED: '") + title8.data() + "'\n"); 1207 1208 m_testInterfaces->testRunner()->setTitleTextDirection(direction); 1209 } 1210 1211 void WebTestProxyBase::didChangeIcon(WebFrame* frame, WebIconURL::Type) 1212 { 1213 if (m_testInterfaces->testRunner()->shouldDumpIconChanges()) { 1214 printFrameDescription(m_delegate, frame); 1215 m_delegate->printMessage(string(" - didChangeIcons\n")); 1216 } 1217 } 1218 1219 void WebTestProxyBase::didFinishDocumentLoad(WebFrame* frame) 1220 { 1221 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1222 printFrameDescription(m_delegate, frame); 1223 m_delegate->printMessage(" - didFinishDocumentLoadForFrame\n"); 1224 } else { 1225 unsigned pendingUnloadEvents = frame->unloadListenerCount(); 1226 if (pendingUnloadEvents) { 1227 printFrameDescription(m_delegate, frame); 1228 char buffer[100]; 1229 snprintf(buffer, sizeof(buffer), " - has %u onunload handler(s)\n", pendingUnloadEvents); 1230 m_delegate->printMessage(buffer); 1231 } 1232 } 1233 } 1234 1235 void WebTestProxyBase::didHandleOnloadEvents(WebFrame* frame) 1236 { 1237 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1238 printFrameDescription(m_delegate, frame); 1239 m_delegate->printMessage(" - didHandleOnloadEventsForFrame\n"); 1240 } 1241 } 1242 1243 void WebTestProxyBase::didFailLoad(WebFrame* frame, const WebURLError&) 1244 { 1245 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1246 printFrameDescription(m_delegate, frame); 1247 m_delegate->printMessage(" - didFailLoadWithError\n"); 1248 } 1249 locationChangeDone(frame); 1250 } 1251 1252 void WebTestProxyBase::didFinishLoad(WebFrame* frame) 1253 { 1254 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) { 1255 printFrameDescription(m_delegate, frame); 1256 m_delegate->printMessage(" - didFinishLoadForFrame\n"); 1257 } 1258 locationChangeDone(frame); 1259 } 1260 1261 void WebTestProxyBase::didDetectXSS(WebFrame*, const WebURL&, bool) 1262 { 1263 if (m_testInterfaces->testRunner()->shouldDumpFrameLoadCallbacks()) 1264 m_delegate->printMessage("didDetectXSS\n"); 1265 } 1266 1267 void WebTestProxyBase::didDispatchPingLoader(WebFrame*, const WebURL& url) 1268 { 1269 if (m_testInterfaces->testRunner()->shouldDumpPingLoaderCallbacks()) 1270 m_delegate->printMessage(string("PingLoader dispatched to '") + URLDescription(url).c_str() + "'.\n"); 1271 } 1272 1273 void WebTestProxyBase::willRequestResource(WebFrame* frame, const WebKit::WebCachedURLRequest& request) 1274 { 1275 if (m_testInterfaces->testRunner()->shouldDumpResourceRequestCallbacks()) { 1276 printFrameDescription(m_delegate, frame); 1277 m_delegate->printMessage(string(" - ") + request.initiatorName().utf8().data()); 1278 m_delegate->printMessage(string(" requested '") + URLDescription(request.urlRequest().url()).c_str() + "'\n"); 1279 } 1280 } 1281 1282 void WebTestProxyBase::didCreateDataSource(WebFrame*, WebDataSource* ds) 1283 { 1284 if (!m_testInterfaces->testRunner()->deferMainResourceDataLoad()) 1285 ds->setDeferMainResourceDataLoad(false); 1286 } 1287 1288 void WebTestProxyBase::willSendRequest(WebFrame*, unsigned identifier, WebKit::WebURLRequest& request, const WebKit::WebURLResponse& redirectResponse) 1289 { 1290 // Need to use GURL for host() and SchemeIs() 1291 GURL url = request.url(); 1292 string requestURL = url.possibly_invalid_spec(); 1293 1294 GURL mainDocumentURL = request.firstPartyForCookies(); 1295 1296 if (redirectResponse.isNull() && (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks() || m_testInterfaces->testRunner()->shouldDumpResourcePriorities())) { 1297 WEBKIT_ASSERT(m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end()); 1298 m_resourceIdentifierMap[identifier] = descriptionSuitableForTestResult(requestURL); 1299 } 1300 1301 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) { 1302 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end()) 1303 m_delegate->printMessage("<unknown>"); 1304 else 1305 m_delegate->printMessage(m_resourceIdentifierMap[identifier]); 1306 m_delegate->printMessage(" - willSendRequest <NSURLRequest URL "); 1307 m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str()); 1308 m_delegate->printMessage(", main document URL "); 1309 m_delegate->printMessage(URLDescription(mainDocumentURL).c_str()); 1310 m_delegate->printMessage(", http method "); 1311 m_delegate->printMessage(request.httpMethod().utf8().data()); 1312 m_delegate->printMessage("> redirectResponse "); 1313 printResponseDescription(m_delegate, redirectResponse); 1314 m_delegate->printMessage("\n"); 1315 } 1316 1317 if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) { 1318 m_delegate->printMessage(descriptionSuitableForTestResult(requestURL).c_str()); 1319 m_delegate->printMessage(" has priority "); 1320 m_delegate->printMessage(PriorityDescription(request.priority())); 1321 m_delegate->printMessage("\n"); 1322 } 1323 1324 if (m_testInterfaces->testRunner()->httpHeadersToClear()) { 1325 const set<string> *clearHeaders = m_testInterfaces->testRunner()->httpHeadersToClear(); 1326 for (set<string>::const_iterator header = clearHeaders->begin(); header != clearHeaders->end(); ++header) 1327 request.clearHTTPHeaderField(WebString::fromUTF8(*header)); 1328 } 1329 1330 string host = url.host(); 1331 if (!host.empty() && (url.SchemeIs("http") || url.SchemeIs("https"))) { 1332 if (!isLocalhost(host) && !hostIsUsedBySomeTestsToGenerateError(host) 1333 && ((!mainDocumentURL.SchemeIs("http") && !mainDocumentURL.SchemeIs("https")) || isLocalhost(mainDocumentURL.host())) 1334 && !m_delegate->allowExternalPages()) { 1335 m_delegate->printMessage(string("Blocked access to external URL ") + requestURL + "\n"); 1336 blockRequest(request); 1337 return; 1338 } 1339 } 1340 1341 // Set the new substituted URL. 1342 request.setURL(m_delegate->rewriteLayoutTestsURL(request.url().spec())); 1343 } 1344 1345 void WebTestProxyBase::didReceiveResponse(WebFrame*, unsigned identifier, const WebKit::WebURLResponse& response) 1346 { 1347 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) { 1348 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end()) 1349 m_delegate->printMessage("<unknown>"); 1350 else 1351 m_delegate->printMessage(m_resourceIdentifierMap[identifier]); 1352 m_delegate->printMessage(" - didReceiveResponse "); 1353 printResponseDescription(m_delegate, response); 1354 m_delegate->printMessage("\n"); 1355 } 1356 if (m_testInterfaces->testRunner()->shouldDumpResourceResponseMIMETypes()) { 1357 GURL url = response.url(); 1358 WebString mimeType = response.mimeType(); 1359 m_delegate->printMessage(url.ExtractFileName()); 1360 m_delegate->printMessage(" has MIME type "); 1361 // Simulate NSURLResponse's mapping of empty/unknown MIME types to application/octet-stream 1362 m_delegate->printMessage(mimeType.isEmpty() ? "application/octet-stream" : mimeType.utf8().data()); 1363 m_delegate->printMessage("\n"); 1364 } 1365 } 1366 1367 void WebTestProxyBase::didChangeResourcePriority(WebFrame*, unsigned identifier, const WebKit::WebURLRequest::Priority& priority) 1368 { 1369 if (m_testInterfaces->testRunner()->shouldDumpResourcePriorities()) { 1370 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end()) 1371 m_delegate->printMessage("<unknown>"); 1372 else 1373 m_delegate->printMessage(m_resourceIdentifierMap[identifier]); 1374 m_delegate->printMessage(" changed priority to "); 1375 m_delegate->printMessage(PriorityDescription(priority)); 1376 m_delegate->printMessage("\n"); 1377 } 1378 } 1379 1380 void WebTestProxyBase::didFinishResourceLoad(WebFrame*, unsigned identifier) 1381 { 1382 if (m_testInterfaces->testRunner()->shouldDumpResourceLoadCallbacks()) { 1383 if (m_resourceIdentifierMap.find(identifier) == m_resourceIdentifierMap.end()) 1384 m_delegate->printMessage("<unknown>"); 1385 else 1386 m_delegate->printMessage(m_resourceIdentifierMap[identifier]); 1387 m_delegate->printMessage(" - didFinishLoading\n"); 1388 } 1389 m_resourceIdentifierMap.erase(identifier); 1390 } 1391 1392 void WebTestProxyBase::didAddMessageToConsole(const WebConsoleMessage& message, const WebString& sourceName, unsigned sourceLine) 1393 { 1394 // This matches win DumpRenderTree's UIDelegate.cpp. 1395 if (!m_logConsoleOutput) 1396 return; 1397 m_delegate->printMessage(string("CONSOLE MESSAGE: ")); 1398 if (sourceLine) { 1399 char buffer[40]; 1400 snprintf(buffer, sizeof(buffer), "line %d: ", sourceLine); 1401 m_delegate->printMessage(buffer); 1402 } 1403 if (!message.text.isEmpty()) { 1404 string newMessage; 1405 newMessage = message.text.utf8(); 1406 size_t fileProtocol = newMessage.find("file://"); 1407 if (fileProtocol != string::npos) { 1408 newMessage = newMessage.substr(0, fileProtocol) 1409 + urlSuitableForTestResult(newMessage.substr(fileProtocol)); 1410 } 1411 m_delegate->printMessage(newMessage); 1412 } 1413 m_delegate->printMessage(string("\n")); 1414 } 1415 1416 void WebTestProxyBase::runModalAlertDialog(WebFrame*, const WebString& message) 1417 { 1418 m_delegate->printMessage(string("ALERT: ") + message.utf8().data() + "\n"); 1419 } 1420 1421 bool WebTestProxyBase::runModalConfirmDialog(WebFrame*, const WebString& message) 1422 { 1423 m_delegate->printMessage(string("CONFIRM: ") + message.utf8().data() + "\n"); 1424 return true; 1425 } 1426 1427 bool WebTestProxyBase::runModalPromptDialog(WebFrame* frame, const WebString& message, const WebString& defaultValue, WebString*) 1428 { 1429 m_delegate->printMessage(string("PROMPT: ") + message.utf8().data() + ", default text: " + defaultValue.utf8().data() + "\n"); 1430 return true; 1431 } 1432 1433 bool WebTestProxyBase::runModalBeforeUnloadDialog(WebFrame*, const WebString& message) 1434 { 1435 m_delegate->printMessage(string("CONFIRM NAVIGATION: ") + message.utf8().data() + "\n"); 1436 return !m_testInterfaces->testRunner()->shouldStayOnPageAfterHandlingBeforeUnload(); 1437 } 1438 1439 void WebTestProxyBase::locationChangeDone(WebFrame* frame) 1440 { 1441 if (frame != m_testInterfaces->testRunner()->topLoadingFrame()) 1442 return; 1443 m_testInterfaces->testRunner()->setTopLoadingFrame(frame, true); 1444 } 1445 1446 WebNavigationPolicy WebTestProxyBase::decidePolicyForNavigation(WebFrame*, WebDataSource::ExtraData*, const WebURLRequest& request, WebNavigationType type, WebNavigationPolicy defaultPolicy, bool isRedirect) 1447 { 1448 WebNavigationPolicy result; 1449 if (!m_testInterfaces->testRunner()->policyDelegateEnabled()) 1450 return defaultPolicy; 1451 1452 m_delegate->printMessage(string("Policy delegate: attempt to load ") + URLDescription(request.url()) + " with navigation type '" + webNavigationTypeToString(type) + "'\n"); 1453 if (m_testInterfaces->testRunner()->policyDelegateIsPermissive()) 1454 result = WebKit::WebNavigationPolicyCurrentTab; 1455 else 1456 result = WebKit::WebNavigationPolicyIgnore; 1457 1458 if (m_testInterfaces->testRunner()->policyDelegateShouldNotifyDone()) 1459 m_testInterfaces->testRunner()->policyDelegateDone(); 1460 return result; 1461 } 1462 1463 bool WebTestProxyBase::willCheckAndDispatchMessageEvent(WebFrame*, WebFrame*, WebSecurityOrigin, WebDOMMessageEvent) 1464 { 1465 if (m_testInterfaces->testRunner()->shouldInterceptPostMessage()) { 1466 m_delegate->printMessage("intercepted postMessage\n"); 1467 return true; 1468 } 1469 1470 return false; 1471 } 1472 1473 void WebTestProxyBase::resetInputMethod() 1474 { 1475 // If a composition text exists, then we need to let the browser process 1476 // to cancel the input method's ongoing composition session. 1477 if (m_webWidget) 1478 m_webWidget->confirmComposition(); 1479 } 1480 1481 } 1482