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