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