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 "core/page/Chrome.h" 24 25#include "core/HTMLNames.h" 26#include "core/dom/Document.h" 27#include "core/frame/LocalFrame.h" 28#include "core/html/HTMLInputElement.h" 29#include "core/html/forms/ColorChooser.h" 30#include "core/html/forms/DateTimeChooser.h" 31#include "core/inspector/InspectorInstrumentation.h" 32#include "core/page/ChromeClient.h" 33#include "core/page/FrameTree.h" 34#include "core/page/Page.h" 35#include "core/page/PopupOpeningObserver.h" 36#include "core/page/ScopedPageLoadDeferrer.h" 37#include "core/page/WindowFeatures.h" 38#include "core/rendering/HitTestResult.h" 39#include "platform/FileChooser.h" 40#include "platform/Logging.h" 41#include "platform/geometry/FloatRect.h" 42#include "platform/network/DNS.h" 43#include "public/platform/WebScreenInfo.h" 44#include "wtf/PassRefPtr.h" 45#include "wtf/Vector.h" 46 47namespace blink { 48 49using namespace HTMLNames; 50 51Chrome::Chrome(Page* page, ChromeClient* client) 52 : m_page(page) 53 , m_client(client) 54{ 55 ASSERT(m_client); 56} 57 58Chrome::~Chrome() 59{ 60} 61 62PassOwnPtr<Chrome> Chrome::create(Page* page, ChromeClient* client) 63{ 64 return adoptPtr(new Chrome(page, client)); 65} 66 67void Chrome::invalidateContentsAndRootView(const IntRect& updateRect) 68{ 69 m_client->invalidateContentsAndRootView(updateRect); 70} 71 72void Chrome::invalidateContentsForSlowScroll(const IntRect& updateRect) 73{ 74 m_client->invalidateContentsForSlowScroll(updateRect); 75} 76 77IntRect Chrome::rootViewToScreen(const IntRect& rect) const 78{ 79 return m_client->rootViewToScreen(rect); 80} 81 82blink::WebScreenInfo Chrome::screenInfo() const 83{ 84 return m_client->screenInfo(); 85} 86 87void Chrome::contentsSizeChanged(LocalFrame* frame, const IntSize& size) const 88{ 89 m_client->contentsSizeChanged(frame, size); 90} 91 92void Chrome::setWindowRect(const FloatRect& rect) const 93{ 94 m_client->setWindowRect(rect); 95} 96 97FloatRect Chrome::windowRect() const 98{ 99 return m_client->windowRect(); 100} 101 102FloatRect Chrome::pageRect() const 103{ 104 return m_client->pageRect(); 105} 106 107void Chrome::focus() const 108{ 109 m_client->focus(); 110} 111 112bool Chrome::canTakeFocus(FocusType type) const 113{ 114 return m_client->canTakeFocus(type); 115} 116 117void Chrome::takeFocus(FocusType type) const 118{ 119 m_client->takeFocus(type); 120} 121 122void Chrome::focusedNodeChanged(Node* node) const 123{ 124 m_client->focusedNodeChanged(node); 125} 126 127void Chrome::show(NavigationPolicy policy) const 128{ 129 m_client->show(policy); 130} 131 132bool Chrome::canRunModal() const 133{ 134 return m_client->canRunModal(); 135} 136 137static bool canRunModalIfDuringPageDismissal(Page* page, ChromeClient::DialogType dialog, const String& message) 138{ 139 for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) { 140 if (!frame->isLocalFrame()) 141 continue; 142 Document::PageDismissalType dismissal = toLocalFrame(frame)->document()->pageDismissalEventBeingDispatched(); 143 if (dismissal != Document::NoDismissal) 144 return page->chrome().client().shouldRunModalDialogDuringPageDismissal(dialog, message, dismissal); 145 } 146 return true; 147} 148 149bool Chrome::canRunModalNow() const 150{ 151 return canRunModal() && canRunModalIfDuringPageDismissal(m_page, ChromeClient::HTMLDialog, String()); 152} 153 154void Chrome::runModal() const 155{ 156 // Defer callbacks in all the other pages, so we don't try to run JavaScript 157 // in a way that could interact with this view. 158 ScopedPageLoadDeferrer deferrer(m_page); 159 160 TimerBase::fireTimersInNestedEventLoop(); 161 m_client->runModal(); 162} 163 164void Chrome::setWindowFeatures(const WindowFeatures& features) const 165{ 166 m_client->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible); 167 m_client->setStatusbarVisible(features.statusBarVisible); 168 m_client->setScrollbarsVisible(features.scrollbarsVisible); 169 m_client->setMenubarVisible(features.menuBarVisible); 170 m_client->setResizable(features.resizable); 171} 172 173bool Chrome::toolbarsVisible() const 174{ 175 return m_client->toolbarsVisible(); 176} 177 178bool Chrome::statusbarVisible() const 179{ 180 return m_client->statusbarVisible(); 181} 182 183bool Chrome::scrollbarsVisible() const 184{ 185 return m_client->scrollbarsVisible(); 186} 187 188bool Chrome::menubarVisible() const 189{ 190 return m_client->menubarVisible(); 191} 192 193bool Chrome::canRunBeforeUnloadConfirmPanel() 194{ 195 return m_client->canRunBeforeUnloadConfirmPanel(); 196} 197 198bool Chrome::runBeforeUnloadConfirmPanel(const String& message, LocalFrame* frame) 199{ 200 // Defer loads in case the client method runs a new event loop that would 201 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 202 ScopedPageLoadDeferrer deferrer; 203 204 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, message); 205 bool ok = m_client->runBeforeUnloadConfirmPanel(message, frame); 206 InspectorInstrumentation::didRunJavaScriptDialog(cookie); 207 return ok; 208} 209 210void Chrome::closeWindowSoon() 211{ 212 m_client->closeWindowSoon(); 213} 214 215void Chrome::runJavaScriptAlert(LocalFrame* frame, const String& message) 216{ 217 if (!canRunModalIfDuringPageDismissal(m_page, ChromeClient::AlertDialog, message)) 218 return; 219 220 // Defer loads in case the client method runs a new event loop that would 221 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 222 ScopedPageLoadDeferrer deferrer; 223 224 ASSERT(frame); 225 notifyPopupOpeningObservers(); 226 227 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, message); 228 m_client->runJavaScriptAlert(frame, message); 229 InspectorInstrumentation::didRunJavaScriptDialog(cookie); 230} 231 232bool Chrome::runJavaScriptConfirm(LocalFrame* frame, const String& message) 233{ 234 if (!canRunModalIfDuringPageDismissal(m_page, ChromeClient::ConfirmDialog, message)) 235 return false; 236 237 // Defer loads in case the client method runs a new event loop that would 238 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 239 ScopedPageLoadDeferrer deferrer; 240 241 ASSERT(frame); 242 notifyPopupOpeningObservers(); 243 244 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, message); 245 bool ok = m_client->runJavaScriptConfirm(frame, message); 246 InspectorInstrumentation::didRunJavaScriptDialog(cookie); 247 return ok; 248} 249 250bool Chrome::runJavaScriptPrompt(LocalFrame* frame, const String& prompt, const String& defaultValue, String& result) 251{ 252 if (!canRunModalIfDuringPageDismissal(m_page, ChromeClient::PromptDialog, prompt)) 253 return false; 254 255 // Defer loads in case the client method runs a new event loop that would 256 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 257 ScopedPageLoadDeferrer deferrer; 258 259 ASSERT(frame); 260 notifyPopupOpeningObservers(); 261 262 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRunJavaScriptDialog(m_page, prompt); 263 bool ok = m_client->runJavaScriptPrompt(frame, prompt, defaultValue, result); 264 InspectorInstrumentation::didRunJavaScriptDialog(cookie); 265 266 return ok; 267} 268 269void Chrome::setStatusbarText(LocalFrame* frame, const String& status) 270{ 271 ASSERT(frame); 272 m_client->setStatusbarText(status); 273} 274 275IntRect Chrome::windowResizerRect() const 276{ 277 return m_client->windowResizerRect(); 278} 279 280void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) 281{ 282 if (result.innerNode()) { 283 if (result.innerNode()->document().isDNSPrefetchEnabled()) 284 prefetchDNS(result.absoluteLinkURL().host()); 285 } 286 m_client->mouseDidMoveOverElement(result, modifierFlags); 287} 288 289void Chrome::setToolTip(const HitTestResult& result) 290{ 291 // First priority is a potential toolTip representing a spelling or grammar error 292 TextDirection toolTipDirection; 293 String toolTip = result.spellingToolTip(toolTipDirection); 294 295 // Next we'll consider a tooltip for element with "title" attribute 296 if (toolTip.isEmpty()) 297 toolTip = result.title(toolTipDirection); 298 299 // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames 300 if (toolTip.isEmpty()) { 301 if (Node* node = result.innerNonSharedNode()) { 302 if (isHTMLInputElement(*node)) { 303 HTMLInputElement* input = toHTMLInputElement(node); 304 toolTip = input->defaultToolTip(); 305 306 // FIXME: We should obtain text direction of tooltip from 307 // ChromeClient or platform. As of October 2011, all client 308 // implementations don't use text direction information for 309 // ChromeClient::setToolTip. We'll work on tooltip text 310 // direction during bidi cleanup in form inputs. 311 toolTipDirection = LTR; 312 } 313 } 314 } 315 316 m_client->setToolTip(toolTip, toolTipDirection); 317} 318 319void Chrome::print(LocalFrame* frame) 320{ 321 // Defer loads in case the client method runs a new event loop that would 322 // otherwise cause the load to continue while we're in the middle of executing JavaScript. 323 ScopedPageLoadDeferrer deferrer; 324 325 m_client->print(frame); 326} 327 328void Chrome::enumerateChosenDirectory(FileChooser* fileChooser) 329{ 330 m_client->enumerateChosenDirectory(fileChooser); 331} 332 333PassOwnPtr<ColorChooser> Chrome::createColorChooser(LocalFrame* frame, ColorChooserClient* client, const Color& initialColor) 334{ 335 notifyPopupOpeningObservers(); 336 return m_client->createColorChooser(frame, client, initialColor); 337} 338 339PassRefPtr<DateTimeChooser> Chrome::openDateTimeChooser(DateTimeChooserClient* client, const DateTimeChooserParameters& parameters) 340{ 341 notifyPopupOpeningObservers(); 342 return m_client->openDateTimeChooser(client, parameters); 343} 344 345void Chrome::openTextDataListChooser(HTMLInputElement& input) 346{ 347 notifyPopupOpeningObservers(); 348 m_client->openTextDataListChooser(input); 349} 350 351void Chrome::runOpenPanel(LocalFrame* frame, PassRefPtr<FileChooser> fileChooser) 352{ 353 notifyPopupOpeningObservers(); 354 m_client->runOpenPanel(frame, fileChooser); 355} 356 357void Chrome::dispatchViewportPropertiesDidChange(const ViewportDescription& description) const 358{ 359 m_client->dispatchViewportPropertiesDidChange(description); 360} 361 362void Chrome::setCursor(const Cursor& cursor) 363{ 364 m_client->setCursor(cursor); 365} 366 367void Chrome::scheduleAnimation() 368{ 369 m_page->animator().setAnimationFramePending(); 370 m_client->scheduleAnimation(); 371} 372 373// -------- 374 375bool Chrome::hasOpenedPopup() const 376{ 377 return m_client->hasOpenedPopup(); 378} 379 380PassRefPtrWillBeRawPtr<PopupMenu> Chrome::createPopupMenu(LocalFrame& frame, PopupMenuClient* client) const 381{ 382 notifyPopupOpeningObservers(); 383 return m_client->createPopupMenu(frame, client); 384} 385 386void Chrome::registerPopupOpeningObserver(PopupOpeningObserver* observer) 387{ 388 ASSERT(observer); 389 m_popupOpeningObservers.append(observer); 390} 391 392void Chrome::unregisterPopupOpeningObserver(PopupOpeningObserver* observer) 393{ 394 size_t index = m_popupOpeningObservers.find(observer); 395 ASSERT(index != kNotFound); 396 m_popupOpeningObservers.remove(index); 397} 398 399void Chrome::notifyPopupOpeningObservers() const 400{ 401 const Vector<PopupOpeningObserver*> observers(m_popupOpeningObservers); 402 for (size_t i = 0; i < observers.size(); ++i) 403 observers[i]->willOpenPopup(); 404} 405 406void Chrome::willBeDestroyed() 407{ 408 m_client->chromeDestroyed(); 409} 410 411} // namespace blink 412