1/* 2 * Copyright (C) 2006, 2007, 2009, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) 4 * Copyright (C) 2012, Samsung Electronics. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22#include "config.h" 23#include "Chrome.h" 24 25#include "ChromeClient.h" 26#include "DNS.h" 27#include "DateTimeChooser.h" 28#include "Document.h" 29#include "FileIconLoader.h" 30#include "FileChooser.h" 31#include "FileList.h" 32#include "FloatRect.h" 33#include "Frame.h" 34#include "FrameTree.h" 35#include "Geolocation.h" 36#include "HTMLFormElement.h" 37#include "HTMLInputElement.h" 38#include "HTMLNames.h" 39#include "HitTestResult.h" 40#include "Icon.h" 41#include "InspectorInstrumentation.h" 42#include "Page.h" 43#include "PageGroupLoadDeferrer.h" 44#include "PopupOpeningObserver.h" 45#include "RenderObject.h" 46#include "ResourceHandle.h" 47#include "SecurityOrigin.h" 48#include "Settings.h" 49#include "StorageNamespace.h" 50#include "WindowFeatures.h" 51#include <wtf/PassRefPtr.h> 52#include <wtf/RefPtr.h> 53#include <wtf/Vector.h> 54#include <wtf/text/StringBuilder.h> 55 56#if ENABLE(INPUT_TYPE_COLOR) 57#include "ColorChooser.h" 58#endif 59 60namespace WebCore { 61 62using namespace HTMLNames; 63using namespace std; 64 65Chrome::Chrome(Page* page, ChromeClient* client) 66 : m_page(page) 67 , m_client(client) 68{ 69 ASSERT(m_client); 70} 71 72Chrome::~Chrome() 73{ 74 m_client->chromeDestroyed(); 75} 76 77PassOwnPtr<Chrome> Chrome::create(Page* page, ChromeClient* client) 78{ 79 return adoptPtr(new Chrome(page, client)); 80} 81 82void Chrome::invalidateRootView(const IntRect& updateRect, bool immediate) 83{ 84 m_client->invalidateRootView(updateRect, immediate); 85} 86 87void Chrome::invalidateContentsAndRootView(const IntRect& updateRect, bool immediate) 88{ 89 m_client->invalidateContentsAndRootView(updateRect, immediate); 90} 91 92void Chrome::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) 93{ 94 m_client->invalidateContentsForSlowScroll(updateRect, immediate); 95} 96 97void Chrome::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) 98{ 99 m_client->scroll(scrollDelta, rectToScroll, clipRect); 100 InspectorInstrumentation::didScroll(m_page); 101} 102 103#if USE(TILED_BACKING_STORE) 104void Chrome::delegatedScrollRequested(const IntPoint& scrollPoint) 105{ 106 m_client->delegatedScrollRequested(scrollPoint); 107} 108#endif 109 110IntPoint Chrome::screenToRootView(const IntPoint& point) const 111{ 112 return m_client->screenToRootView(point); 113} 114 115IntRect Chrome::rootViewToScreen(const IntRect& rect) const 116{ 117 return m_client->rootViewToScreen(rect); 118} 119 120PlatformPageClient Chrome::platformPageClient() const 121{ 122 return m_client->platformPageClient(); 123} 124 125void Chrome::contentsSizeChanged(Frame* frame, const IntSize& size) const 126{ 127 m_client->contentsSizeChanged(frame, size); 128} 129 130void Chrome::layoutUpdated(Frame* frame) const 131{ 132 m_client->layoutUpdated(frame); 133} 134 135void Chrome::scrollRectIntoView(const IntRect& rect) const 136{ 137 m_client->scrollRectIntoView(rect); 138} 139 140void Chrome::scrollbarsModeDidChange() const 141{ 142 m_client->scrollbarsModeDidChange(); 143} 144 145void Chrome::setWindowRect(const FloatRect& rect) const 146{ 147 m_client->setWindowRect(rect); 148} 149 150FloatRect Chrome::windowRect() const 151{ 152 return m_client->windowRect(); 153} 154 155FloatRect Chrome::pageRect() const 156{ 157 return m_client->pageRect(); 158} 159 160void Chrome::focus() const 161{ 162 m_client->focus(); 163} 164 165void Chrome::unfocus() const 166{ 167 m_client->unfocus(); 168} 169 170bool Chrome::canTakeFocus(FocusDirection direction) const 171{ 172 return m_client->canTakeFocus(direction); 173} 174 175void Chrome::takeFocus(FocusDirection direction) const 176{ 177 m_client->takeFocus(direction); 178} 179 180void Chrome::focusedNodeChanged(Node* node) const 181{ 182 m_client->focusedNodeChanged(node); 183} 184 185void Chrome::focusedFrameChanged(Frame* frame) const 186{ 187 m_client->focusedFrameChanged(frame); 188} 189 190Page* Chrome::createWindow(Frame* frame, const FrameLoadRequest& request, const WindowFeatures& features, const NavigationAction& action) const 191{ 192 Page* newPage = m_client->createWindow(frame, request, features, action); 193 if (!newPage) 194 return 0; 195 196 if (StorageNamespace* oldSessionStorage = m_page->sessionStorage(false)) 197 newPage->setSessionStorage(oldSessionStorage->copy(newPage)); 198 199 return newPage; 200} 201 202void Chrome::show() const 203{ 204 m_client->show(); 205} 206 207bool Chrome::canRunModal() const 208{ 209 return m_client->canRunModal(); 210} 211 212static bool canRunModalIfDuringPageDismissal(Page* page, ChromeClient::DialogType dialog, const String& message) 213{ 214 for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { 215 FrameLoader::PageDismissalType dismissal = frame->loader()->pageDismissalEventBeingDispatched(); 216 if (dismissal != FrameLoader::NoDismissal) 217 return page->chrome().client()->shouldRunModalDialogDuringPageDismissal(dialog, message, dismissal); 218 } 219 return true; 220} 221 222bool Chrome::canRunModalNow() const 223{ 224 // If loads are blocked, we can't run modal because the contents 225 // of the modal dialog will never show up! 226 return canRunModal() && !ResourceHandle::loadsBlocked() 227 && canRunModalIfDuringPageDismissal(m_page, ChromeClient::HTMLDialog, String()); 228} 229 230void Chrome::runModal() const 231{ 232 // Defer callbacks in all the other pages in this group, so we don't try to run JavaScript 233 // in a way that could interact with this view. 234 PageGroupLoadDeferrer deferrer(m_page, false); 235 236 TimerBase::fireTimersInNestedEventLoop(); 237 m_client->runModal(); 238} 239 240void Chrome::setToolbarsVisible(bool b) const 241{ 242 m_client->setToolbarsVisible(b); 243} 244 245bool Chrome::toolbarsVisible() const 246{ 247 return m_client->toolbarsVisible(); 248} 249 250void Chrome::setStatusbarVisible(bool b) const 251{ 252 m_client->setStatusbarVisible(b); 253} 254 255bool Chrome::statusbarVisible() const 256{ 257 return m_client->statusbarVisible(); 258} 259 260void Chrome::setScrollbarsVisible(bool b) const 261{ 262 m_client->setScrollbarsVisible(b); 263} 264 265bool Chrome::scrollbarsVisible() const 266{ 267 return m_client->scrollbarsVisible(); 268} 269 270void Chrome::setMenubarVisible(bool b) const 271{ 272 m_client->setMenubarVisible(b); 273} 274 275bool Chrome::menubarVisible() const 276{ 277 return m_client->menubarVisible(); 278} 279 280void Chrome::setResizable(bool b) const 281{ 282 m_client->setResizable(b); 283} 284 285bool Chrome::canRunBeforeUnloadConfirmPanel() 286{ 287 return m_client->canRunBeforeUnloadConfirmPanel(); 288} 289 290bool Chrome::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 291{ 292 // Defer loads in case the client method runs a new event loop that would 293 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 294 PageGroupLoadDeferrer deferrer(m_page, true); 295 296 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, message); 297 bool ok = m_client->runBeforeUnloadConfirmPanel(message, frame); 298 InspectorInstrumentation::didRunJavaScriptDialog(cookie); 299 return ok; 300} 301 302void Chrome::closeWindowSoon() 303{ 304 m_client->closeWindowSoon(); 305} 306 307void Chrome::runJavaScriptAlert(Frame* frame, const String& message) 308{ 309 if (!canRunModalIfDuringPageDismissal(m_page, ChromeClient::AlertDialog, message)) 310 return; 311 312 // Defer loads in case the client method runs a new event loop that would 313 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 314 PageGroupLoadDeferrer deferrer(m_page, true); 315 316 ASSERT(frame); 317 notifyPopupOpeningObservers(); 318 String displayMessage = frame->displayStringModifiedByEncoding(message); 319 320 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, displayMessage); 321 m_client->runJavaScriptAlert(frame, displayMessage); 322 InspectorInstrumentation::didRunJavaScriptDialog(cookie); 323} 324 325bool Chrome::runJavaScriptConfirm(Frame* frame, const String& message) 326{ 327 if (!canRunModalIfDuringPageDismissal(m_page, ChromeClient::ConfirmDialog, message)) 328 return false; 329 330 // Defer loads in case the client method runs a new event loop that would 331 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 332 PageGroupLoadDeferrer deferrer(m_page, true); 333 334 ASSERT(frame); 335 notifyPopupOpeningObservers(); 336 String displayMessage = frame->displayStringModifiedByEncoding(message); 337 338 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, displayMessage); 339 bool ok = m_client->runJavaScriptConfirm(frame, displayMessage); 340 InspectorInstrumentation::didRunJavaScriptDialog(cookie); 341 return ok; 342} 343 344bool Chrome::runJavaScriptPrompt(Frame* frame, const String& prompt, const String& defaultValue, String& result) 345{ 346 if (!canRunModalIfDuringPageDismissal(m_page, ChromeClient::PromptDialog, prompt)) 347 return false; 348 349 // Defer loads in case the client method runs a new event loop that would 350 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 351 PageGroupLoadDeferrer deferrer(m_page, true); 352 353 ASSERT(frame); 354 notifyPopupOpeningObservers(); 355 String displayPrompt = frame->displayStringModifiedByEncoding(prompt); 356 357 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, displayPrompt); 358 bool ok = m_client->runJavaScriptPrompt(frame, displayPrompt, frame->displayStringModifiedByEncoding(defaultValue), result); 359 InspectorInstrumentation::didRunJavaScriptDialog(cookie); 360 361 if (ok) 362 result = frame->displayStringModifiedByEncoding(result); 363 364 return ok; 365} 366 367void Chrome::setStatusbarText(Frame* frame, const String& status) 368{ 369 ASSERT(frame); 370 m_client->setStatusbarText(frame->displayStringModifiedByEncoding(status)); 371} 372 373bool Chrome::shouldInterruptJavaScript() 374{ 375 // Defer loads in case the client method runs a new event loop that would 376 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 377 PageGroupLoadDeferrer deferrer(m_page, true); 378 379 return m_client->shouldInterruptJavaScript(); 380} 381 382IntRect Chrome::windowResizerRect() const 383{ 384 return m_client->windowResizerRect(); 385} 386 387void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) 388{ 389 if (result.innerNode()) { 390 Document* document = result.innerNode()->document(); 391 if (document && document->isDNSPrefetchEnabled()) 392 prefetchDNS(result.absoluteLinkURL().host()); 393 } 394 m_client->mouseDidMoveOverElement(result, modifierFlags); 395 396 InspectorInstrumentation::mouseDidMoveOverElement(m_page, result, modifierFlags); 397} 398 399void Chrome::setToolTip(const HitTestResult& result) 400{ 401 // First priority is a potential toolTip representing a spelling or grammar error 402 TextDirection toolTipDirection; 403 String toolTip = result.spellingToolTip(toolTipDirection); 404 405 // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those). 406 if (toolTip.isEmpty() && m_page->settings()->showsURLsInToolTips()) { 407 if (Node* node = result.innerNonSharedNode()) { 408 // Get tooltip representing form action, if relevant 409 if (node->hasTagName(inputTag)) { 410 HTMLInputElement* input = static_cast<HTMLInputElement*>(node); 411 if (input->isSubmitButton()) 412 if (HTMLFormElement* form = input->form()) { 413 toolTip = form->action(); 414 if (form->renderer()) 415 toolTipDirection = form->renderer()->style()->direction(); 416 else 417 toolTipDirection = LTR; 418 } 419 } 420 } 421 422 // Get tooltip representing link's URL 423 if (toolTip.isEmpty()) { 424 // FIXME: Need to pass this URL through userVisibleString once that's in WebCore 425 toolTip = result.absoluteLinkURL().string(); 426 // URL always display as LTR. 427 toolTipDirection = LTR; 428 } 429 } 430 431 // Next we'll consider a tooltip for element with "title" attribute 432 if (toolTip.isEmpty()) 433 toolTip = result.title(toolTipDirection); 434 435 if (toolTip.isEmpty() && m_page->settings()->showsToolTipOverTruncatedText()) 436 toolTip = result.innerTextIfTruncated(toolTipDirection); 437 438 // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames 439 if (toolTip.isEmpty()) { 440 if (Node* node = result.innerNonSharedNode()) { 441 if (node->hasTagName(inputTag)) { 442 HTMLInputElement* input = static_cast<HTMLInputElement*>(node); 443 toolTip = input->defaultToolTip(); 444 445 // FIXME: We should obtain text direction of tooltip from 446 // ChromeClient or platform. As of October 2011, all client 447 // implementations don't use text direction information for 448 // ChromeClient::setToolTip. We'll work on tooltip text 449 // direction during bidi cleanup in form inputs. 450 toolTipDirection = LTR; 451 } 452 } 453 } 454 455 m_client->setToolTip(toolTip, toolTipDirection); 456} 457 458void Chrome::print(Frame* frame) 459{ 460 // FIXME: This should have PageGroupLoadDeferrer, like runModal() or runJavaScriptAlert(), becasue it's no different from those. 461 m_client->print(frame); 462} 463 464void Chrome::enableSuddenTermination() 465{ 466 m_client->enableSuddenTermination(); 467} 468 469void Chrome::disableSuddenTermination() 470{ 471 m_client->disableSuddenTermination(); 472} 473 474#if ENABLE(DIRECTORY_UPLOAD) 475void Chrome::enumerateChosenDirectory(FileChooser* fileChooser) 476{ 477 m_client->enumerateChosenDirectory(fileChooser); 478} 479#endif 480 481#if ENABLE(INPUT_TYPE_COLOR) 482PassOwnPtr<ColorChooser> Chrome::createColorChooser(ColorChooserClient* client, const Color& initialColor) 483{ 484 notifyPopupOpeningObservers(); 485 return m_client->createColorChooser(client, initialColor); 486} 487#endif 488 489#if ENABLE(DATE_AND_TIME_INPUT_TYPES) 490PassRefPtr<DateTimeChooser> Chrome::openDateTimeChooser(DateTimeChooserClient* client, const DateTimeChooserParameters& parameters) 491{ 492 notifyPopupOpeningObservers(); 493 return m_client->openDateTimeChooser(client, parameters); 494} 495#endif 496 497void Chrome::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> fileChooser) 498{ 499 notifyPopupOpeningObservers(); 500 m_client->runOpenPanel(frame, fileChooser); 501} 502 503void Chrome::loadIconForFiles(const Vector<String>& filenames, FileIconLoader* loader) 504{ 505 m_client->loadIconForFiles(filenames, loader); 506} 507 508void Chrome::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments) const 509{ 510 m_client->dispatchViewportPropertiesDidChange(arguments); 511} 512 513void Chrome::setCursor(const Cursor& cursor) 514{ 515 m_client->setCursor(cursor); 516} 517 518void Chrome::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves) 519{ 520 m_client->setCursorHiddenUntilMouseMoves(hiddenUntilMouseMoves); 521} 522 523#if ENABLE(REQUEST_ANIMATION_FRAME) 524void Chrome::scheduleAnimation() 525{ 526#if !USE(REQUEST_ANIMATION_FRAME_TIMER) 527 m_client->scheduleAnimation(); 528#endif 529} 530#endif 531 532// -------- 533 534#if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION) 535void ChromeClient::annotatedRegionsChanged() 536{ 537} 538#endif 539 540void ChromeClient::populateVisitedLinks() 541{ 542} 543 544FloatRect ChromeClient::customHighlightRect(Node*, const AtomicString&, const FloatRect&) 545{ 546 return FloatRect(); 547} 548 549void ChromeClient::paintCustomHighlight(Node*, const AtomicString&, const FloatRect&, const FloatRect&, bool, bool) 550{ 551} 552 553bool ChromeClient::shouldReplaceWithGeneratedFileForUpload(const String&, String&) 554{ 555 return false; 556} 557 558String ChromeClient::generateReplacementFile(const String&) 559{ 560 ASSERT_NOT_REACHED(); 561 return String(); 562} 563 564bool ChromeClient::paintCustomOverhangArea(GraphicsContext*, const IntRect&, const IntRect&, const IntRect&) 565{ 566 return false; 567} 568 569bool Chrome::selectItemWritingDirectionIsNatural() 570{ 571 return m_client->selectItemWritingDirectionIsNatural(); 572} 573 574bool Chrome::selectItemAlignmentFollowsMenuWritingDirection() 575{ 576 return m_client->selectItemAlignmentFollowsMenuWritingDirection(); 577} 578 579bool Chrome::hasOpenedPopup() const 580{ 581 return m_client->hasOpenedPopup(); 582} 583 584PassRefPtr<PopupMenu> Chrome::createPopupMenu(PopupMenuClient* client) const 585{ 586 notifyPopupOpeningObservers(); 587 return m_client->createPopupMenu(client); 588} 589 590PassRefPtr<SearchPopupMenu> Chrome::createSearchPopupMenu(PopupMenuClient* client) const 591{ 592 notifyPopupOpeningObservers(); 593 return m_client->createSearchPopupMenu(client); 594} 595 596bool Chrome::requiresFullscreenForVideoPlayback() 597{ 598 return m_client->requiresFullscreenForVideoPlayback(); 599} 600 601void Chrome::registerPopupOpeningObserver(PopupOpeningObserver* observer) 602{ 603 ASSERT(observer); 604 m_popupOpeningObservers.append(observer); 605} 606 607void Chrome::unregisterPopupOpeningObserver(PopupOpeningObserver* observer) 608{ 609 size_t index = m_popupOpeningObservers.find(observer); 610 ASSERT(index != notFound); 611 m_popupOpeningObservers.remove(index); 612} 613 614void Chrome::notifyPopupOpeningObservers() const 615{ 616 const Vector<PopupOpeningObserver*> observers(m_popupOpeningObservers); 617 for (size_t i = 0; i < observers.size(); ++i) 618 observers[i]->willOpenPopup(); 619} 620 621} // namespace WebCore 622