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 47 namespace blink { 48 49 using namespace HTMLNames; 50 51 Chrome::Chrome(Page* page, ChromeClient* client) 52 : m_page(page) 53 , m_client(client) 54 { 55 ASSERT(m_client); 56 } 57 58 Chrome::~Chrome() 59 { 60 } 61 62 PassOwnPtr<Chrome> Chrome::create(Page* page, ChromeClient* client) 63 { 64 return adoptPtr(new Chrome(page, client)); 65 } 66 67 void Chrome::invalidateContentsAndRootView(const IntRect& updateRect) 68 { 69 m_client->invalidateContentsAndRootView(updateRect); 70 } 71 72 void Chrome::invalidateContentsForSlowScroll(const IntRect& updateRect) 73 { 74 m_client->invalidateContentsForSlowScroll(updateRect); 75 } 76 77 IntRect Chrome::rootViewToScreen(const IntRect& rect) const 78 { 79 return m_client->rootViewToScreen(rect); 80 } 81 82 blink::WebScreenInfo Chrome::screenInfo() const 83 { 84 return m_client->screenInfo(); 85 } 86 87 void Chrome::contentsSizeChanged(LocalFrame* frame, const IntSize& size) const 88 { 89 m_client->contentsSizeChanged(frame, size); 90 } 91 92 void Chrome::setWindowRect(const FloatRect& rect) const 93 { 94 m_client->setWindowRect(rect); 95 } 96 97 FloatRect Chrome::windowRect() const 98 { 99 return m_client->windowRect(); 100 } 101 102 FloatRect Chrome::pageRect() const 103 { 104 return m_client->pageRect(); 105 } 106 107 void Chrome::focus() const 108 { 109 m_client->focus(); 110 } 111 112 bool Chrome::canTakeFocus(FocusType type) const 113 { 114 return m_client->canTakeFocus(type); 115 } 116 117 void Chrome::takeFocus(FocusType type) const 118 { 119 m_client->takeFocus(type); 120 } 121 122 void Chrome::focusedNodeChanged(Node* node) const 123 { 124 m_client->focusedNodeChanged(node); 125 } 126 127 void Chrome::show(NavigationPolicy policy) const 128 { 129 m_client->show(policy); 130 } 131 132 bool Chrome::canRunModal() const 133 { 134 return m_client->canRunModal(); 135 } 136 137 static 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 149 bool Chrome::canRunModalNow() const 150 { 151 return canRunModal() && canRunModalIfDuringPageDismissal(m_page, ChromeClient::HTMLDialog, String()); 152 } 153 154 void 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 164 void 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 173 bool Chrome::toolbarsVisible() const 174 { 175 return m_client->toolbarsVisible(); 176 } 177 178 bool Chrome::statusbarVisible() const 179 { 180 return m_client->statusbarVisible(); 181 } 182 183 bool Chrome::scrollbarsVisible() const 184 { 185 return m_client->scrollbarsVisible(); 186 } 187 188 bool Chrome::menubarVisible() const 189 { 190 return m_client->menubarVisible(); 191 } 192 193 bool Chrome::canRunBeforeUnloadConfirmPanel() 194 { 195 return m_client->canRunBeforeUnloadConfirmPanel(); 196 } 197 198 bool 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 210 void Chrome::closeWindowSoon() 211 { 212 m_client->closeWindowSoon(); 213 } 214 215 void 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 232 bool 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 250 bool 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 269 void Chrome::setStatusbarText(LocalFrame* frame, const String& status) 270 { 271 ASSERT(frame); 272 m_client->setStatusbarText(status); 273 } 274 275 IntRect Chrome::windowResizerRect() const 276 { 277 return m_client->windowResizerRect(); 278 } 279 280 void 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 289 void 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 319 void 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 328 void Chrome::enumerateChosenDirectory(FileChooser* fileChooser) 329 { 330 m_client->enumerateChosenDirectory(fileChooser); 331 } 332 333 PassOwnPtr<ColorChooser> Chrome::createColorChooser(LocalFrame* frame, ColorChooserClient* client, const Color& initialColor) 334 { 335 notifyPopupOpeningObservers(); 336 return m_client->createColorChooser(frame, client, initialColor); 337 } 338 339 PassRefPtr<DateTimeChooser> Chrome::openDateTimeChooser(DateTimeChooserClient* client, const DateTimeChooserParameters& parameters) 340 { 341 notifyPopupOpeningObservers(); 342 return m_client->openDateTimeChooser(client, parameters); 343 } 344 345 void Chrome::openTextDataListChooser(HTMLInputElement& input) 346 { 347 notifyPopupOpeningObservers(); 348 m_client->openTextDataListChooser(input); 349 } 350 351 void Chrome::runOpenPanel(LocalFrame* frame, PassRefPtr<FileChooser> fileChooser) 352 { 353 notifyPopupOpeningObservers(); 354 m_client->runOpenPanel(frame, fileChooser); 355 } 356 357 void Chrome::dispatchViewportPropertiesDidChange(const ViewportDescription& description) const 358 { 359 m_client->dispatchViewportPropertiesDidChange(description); 360 } 361 362 void Chrome::setCursor(const Cursor& cursor) 363 { 364 m_client->setCursor(cursor); 365 } 366 367 void Chrome::scheduleAnimation() 368 { 369 m_page->animator().setAnimationFramePending(); 370 m_client->scheduleAnimation(); 371 } 372 373 // -------- 374 375 bool Chrome::hasOpenedPopup() const 376 { 377 return m_client->hasOpenedPopup(); 378 } 379 380 PassRefPtrWillBeRawPtr<PopupMenu> Chrome::createPopupMenu(LocalFrame& frame, PopupMenuClient* client) const 381 { 382 notifyPopupOpeningObservers(); 383 return m_client->createPopupMenu(frame, client); 384 } 385 386 void Chrome::registerPopupOpeningObserver(PopupOpeningObserver* observer) 387 { 388 ASSERT(observer); 389 m_popupOpeningObservers.append(observer); 390 } 391 392 void Chrome::unregisterPopupOpeningObserver(PopupOpeningObserver* observer) 393 { 394 size_t index = m_popupOpeningObservers.find(observer); 395 ASSERT(index != kNotFound); 396 m_popupOpeningObservers.remove(index); 397 } 398 399 void 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 406 void Chrome::willBeDestroyed() 407 { 408 m_client->chromeDestroyed(); 409 } 410 411 } // namespace blink 412