1 /* 2 * Copyright (C) 2006 Zack Rusin <zack (at) kde.org> 3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 4 * 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "ChromeClientQt.h" 31 32 #include "FileChooser.h" 33 #include "Frame.h" 34 #include "FrameLoadRequest.h" 35 #include "FrameLoader.h" 36 #include "FrameLoaderClientQt.h" 37 #include "FrameView.h" 38 #include "HitTestResult.h" 39 #include "NotImplemented.h" 40 #include "WindowFeatures.h" 41 #include "DatabaseTracker.h" 42 #include "QtFallbackWebPopup.h" 43 #include "QWebPageClient.h" 44 #include "SecurityOrigin.h" 45 46 #include <qdebug.h> 47 #include <qeventloop.h> 48 #include <qtextdocument.h> 49 #include <qtooltip.h> 50 51 #include "qwebpage.h" 52 #include "qwebpage_p.h" 53 #include "qwebframe_p.h" 54 #include "qwebsecurityorigin.h" 55 #include "qwebsecurityorigin_p.h" 56 #include "qwebview.h" 57 58 #if USE(ACCELERATED_COMPOSITING) 59 #include "GraphicsLayerQt.h" 60 #endif 61 62 namespace WebCore { 63 64 ChromeClientQt::ChromeClientQt(QWebPage* webPage) 65 : m_webPage(webPage) 66 , m_eventLoop(0) 67 { 68 toolBarsVisible = statusBarVisible = menuBarVisible = true; 69 } 70 71 ChromeClientQt::~ChromeClientQt() 72 { 73 if (m_eventLoop) 74 m_eventLoop->exit(); 75 } 76 77 void ChromeClientQt::setWindowRect(const FloatRect& rect) 78 { 79 if (!m_webPage) 80 return; 81 emit m_webPage->geometryChangeRequested(QRect(qRound(rect.x()), qRound(rect.y()), 82 qRound(rect.width()), qRound(rect.height()))); 83 } 84 85 86 FloatRect ChromeClientQt::windowRect() 87 { 88 if (!m_webPage) 89 return FloatRect(); 90 91 QWidget* view = m_webPage->view(); 92 if (!view) 93 return FloatRect(); 94 return IntRect(view->topLevelWidget()->geometry()); 95 } 96 97 98 FloatRect ChromeClientQt::pageRect() 99 { 100 if (!m_webPage) 101 return FloatRect(); 102 return FloatRect(QRectF(QPointF(0,0), m_webPage->viewportSize())); 103 } 104 105 106 float ChromeClientQt::scaleFactor() 107 { 108 notImplemented(); 109 return 1; 110 } 111 112 113 void ChromeClientQt::focus() 114 { 115 if (!m_webPage) 116 return; 117 QWidget* view = m_webPage->view(); 118 if (!view) 119 return; 120 121 view->setFocus(); 122 } 123 124 125 void ChromeClientQt::unfocus() 126 { 127 if (!m_webPage) 128 return; 129 QWidget* view = m_webPage->view(); 130 if (!view) 131 return; 132 view->clearFocus(); 133 } 134 135 bool ChromeClientQt::canTakeFocus(FocusDirection) 136 { 137 // This is called when cycling through links/focusable objects and we 138 // reach the last focusable object. Then we want to claim that we can 139 // take the focus to avoid wrapping. 140 return true; 141 } 142 143 void ChromeClientQt::takeFocus(FocusDirection) 144 { 145 // don't do anything. This is only called when cycling to links/focusable objects, 146 // which in turn is called from focusNextPrevChild. We let focusNextPrevChild 147 // call QWidget::focusNextPrevChild accordingly, so there is no need to do anything 148 // here. 149 } 150 151 152 void ChromeClientQt::focusedNodeChanged(WebCore::Node*) 153 { 154 } 155 156 157 Page* ChromeClientQt::createWindow(Frame*, const FrameLoadRequest& request, const WindowFeatures& features) 158 { 159 QWebPage *newPage = m_webPage->createWindow(features.dialog ? QWebPage::WebModalDialog : QWebPage::WebBrowserWindow); 160 if (!newPage) 161 return 0; 162 newPage->mainFrame()->load(request.resourceRequest().url()); 163 return newPage->d->page; 164 } 165 166 void ChromeClientQt::show() 167 { 168 if (!m_webPage) 169 return; 170 QWidget* view = m_webPage->view(); 171 if (!view) 172 return; 173 view->topLevelWidget()->show(); 174 } 175 176 177 bool ChromeClientQt::canRunModal() 178 { 179 return true; 180 } 181 182 183 void ChromeClientQt::runModal() 184 { 185 m_eventLoop = new QEventLoop(); 186 QEventLoop* eventLoop = m_eventLoop; 187 m_eventLoop->exec(); 188 delete eventLoop; 189 } 190 191 192 void ChromeClientQt::setToolbarsVisible(bool visible) 193 { 194 toolBarsVisible = visible; 195 emit m_webPage->toolBarVisibilityChangeRequested(visible); 196 } 197 198 199 bool ChromeClientQt::toolbarsVisible() 200 { 201 return toolBarsVisible; 202 } 203 204 205 void ChromeClientQt::setStatusbarVisible(bool visible) 206 { 207 emit m_webPage->statusBarVisibilityChangeRequested(visible); 208 statusBarVisible = visible; 209 } 210 211 212 bool ChromeClientQt::statusbarVisible() 213 { 214 return statusBarVisible; 215 return false; 216 } 217 218 219 void ChromeClientQt::setScrollbarsVisible(bool) 220 { 221 notImplemented(); 222 } 223 224 225 bool ChromeClientQt::scrollbarsVisible() 226 { 227 notImplemented(); 228 return true; 229 } 230 231 232 void ChromeClientQt::setMenubarVisible(bool visible) 233 { 234 menuBarVisible = visible; 235 emit m_webPage->menuBarVisibilityChangeRequested(visible); 236 } 237 238 bool ChromeClientQt::menubarVisible() 239 { 240 return menuBarVisible; 241 } 242 243 void ChromeClientQt::setResizable(bool) 244 { 245 notImplemented(); 246 } 247 248 void ChromeClientQt::addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, 249 unsigned int lineNumber, const String& sourceID) 250 { 251 QString x = message; 252 QString y = sourceID; 253 m_webPage->javaScriptConsoleMessage(x, lineNumber, y); 254 } 255 256 void ChromeClientQt::chromeDestroyed() 257 { 258 delete this; 259 } 260 261 bool ChromeClientQt::canRunBeforeUnloadConfirmPanel() 262 { 263 return true; 264 } 265 266 bool ChromeClientQt::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 267 { 268 return runJavaScriptConfirm(frame, message); 269 } 270 271 void ChromeClientQt::closeWindowSoon() 272 { 273 m_webPage->mainFrame()->d->frame->loader()->stopAllLoaders(); 274 emit m_webPage->windowCloseRequested(); 275 } 276 277 void ChromeClientQt::runJavaScriptAlert(Frame* f, const String& msg) 278 { 279 QString x = msg; 280 FrameLoaderClientQt *fl = static_cast<FrameLoaderClientQt*>(f->loader()->client()); 281 m_webPage->javaScriptAlert(fl->webFrame(), x); 282 } 283 284 bool ChromeClientQt::runJavaScriptConfirm(Frame* f, const String& msg) 285 { 286 QString x = msg; 287 FrameLoaderClientQt *fl = static_cast<FrameLoaderClientQt*>(f->loader()->client()); 288 return m_webPage->javaScriptConfirm(fl->webFrame(), x); 289 } 290 291 bool ChromeClientQt::runJavaScriptPrompt(Frame* f, const String& message, const String& defaultValue, String& result) 292 { 293 QString x = result; 294 FrameLoaderClientQt *fl = static_cast<FrameLoaderClientQt*>(f->loader()->client()); 295 bool rc = m_webPage->javaScriptPrompt(fl->webFrame(), (QString)message, (QString)defaultValue, &x); 296 297 // Fix up a quirk in the QInputDialog class. If no input happened the string should be empty 298 // but it is null. See https://bugs.webkit.org/show_bug.cgi?id=30914. 299 if (rc && x.isNull()) 300 result = String(""); 301 else 302 result = x; 303 304 return rc; 305 } 306 307 void ChromeClientQt::setStatusbarText(const String& msg) 308 { 309 QString x = msg; 310 emit m_webPage->statusBarMessage(x); 311 } 312 313 bool ChromeClientQt::shouldInterruptJavaScript() 314 { 315 bool shouldInterrupt = false; 316 QMetaObject::invokeMethod(m_webPage, "shouldInterruptJavaScript", Qt::DirectConnection, Q_RETURN_ARG(bool, shouldInterrupt)); 317 return shouldInterrupt; 318 } 319 320 bool ChromeClientQt::tabsToLinks() const 321 { 322 return m_webPage->settings()->testAttribute(QWebSettings::LinksIncludedInFocusChain); 323 } 324 325 IntRect ChromeClientQt::windowResizerRect() const 326 { 327 return IntRect(); 328 } 329 330 void ChromeClientQt::repaint(const IntRect& windowRect, bool contentChanged, bool, bool) 331 { 332 // No double buffer, so only update the QWidget if content changed. 333 if (contentChanged) { 334 if (platformPageClient()) { 335 QRect rect(windowRect); 336 rect = rect.intersected(QRect(QPoint(0, 0), m_webPage->viewportSize())); 337 if (!rect.isEmpty()) 338 platformPageClient()->update(rect); 339 } 340 emit m_webPage->repaintRequested(windowRect); 341 } 342 343 // FIXME: There is no "immediate" support for window painting. This should be done always whenever the flag 344 // is set. 345 } 346 347 void ChromeClientQt::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect&) 348 { 349 if (platformPageClient()) 350 platformPageClient()->scroll(delta.width(), delta.height(), scrollViewRect); 351 emit m_webPage->scrollRequested(delta.width(), delta.height(), scrollViewRect); 352 } 353 354 IntRect ChromeClientQt::windowToScreen(const IntRect& rect) const 355 { 356 notImplemented(); 357 return rect; 358 } 359 360 IntPoint ChromeClientQt::screenToWindow(const IntPoint& point) const 361 { 362 notImplemented(); 363 return point; 364 } 365 366 PlatformPageClient ChromeClientQt::platformPageClient() const 367 { 368 return m_webPage->d->client; 369 } 370 371 void ChromeClientQt::contentsSizeChanged(Frame* frame, const IntSize& size) const 372 { 373 emit QWebFramePrivate::kit(frame)->contentsSizeChanged(size); 374 } 375 376 void ChromeClientQt::mouseDidMoveOverElement(const HitTestResult& result, unsigned) 377 { 378 TextDirection dir; 379 if (result.absoluteLinkURL() != lastHoverURL 380 || result.title(dir) != lastHoverTitle 381 || result.textContent() != lastHoverContent) { 382 lastHoverURL = result.absoluteLinkURL(); 383 lastHoverTitle = result.title(dir); 384 lastHoverContent = result.textContent(); 385 emit m_webPage->linkHovered(lastHoverURL.prettyURL(), 386 lastHoverTitle, lastHoverContent); 387 } 388 } 389 390 void ChromeClientQt::setToolTip(const String &tip, TextDirection) 391 { 392 #ifndef QT_NO_TOOLTIP 393 QWidget* view = m_webPage->view(); 394 if (!view) 395 return; 396 397 if (tip.isEmpty()) { 398 view->setToolTip(QString()); 399 QToolTip::hideText(); 400 } else { 401 QString dtip = QLatin1String("<p>") + Qt::escape(tip) + QLatin1String("</p>"); 402 view->setToolTip(dtip); 403 } 404 #else 405 Q_UNUSED(tip); 406 #endif 407 } 408 409 void ChromeClientQt::print(Frame *frame) 410 { 411 emit m_webPage->printRequested(QWebFramePrivate::kit(frame)); 412 } 413 414 #if ENABLE(DATABASE) 415 void ChromeClientQt::exceededDatabaseQuota(Frame* frame, const String& databaseName) 416 { 417 quint64 quota = QWebSettings::offlineStorageDefaultQuota(); 418 419 if (!DatabaseTracker::tracker().hasEntryForOrigin(frame->document()->securityOrigin())) 420 DatabaseTracker::tracker().setQuota(frame->document()->securityOrigin(), quota); 421 422 emit m_webPage->databaseQuotaExceeded(QWebFramePrivate::kit(frame), databaseName); 423 } 424 #endif 425 426 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 427 void ChromeClientQt::reachedMaxAppCacheSize(int64_t) 428 { 429 // FIXME: Free some space. 430 notImplemented(); 431 } 432 #endif 433 434 void ChromeClientQt::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> prpFileChooser) 435 { 436 RefPtr<FileChooser> fileChooser = prpFileChooser; 437 bool supportMulti = m_webPage->supportsExtension(QWebPage::ChooseMultipleFilesExtension); 438 439 if (fileChooser->allowsMultipleFiles() && supportMulti) { 440 QWebPage::ChooseMultipleFilesExtensionOption option; 441 option.parentFrame = QWebFramePrivate::kit(frame); 442 443 if (!fileChooser->filenames().isEmpty()) 444 for (unsigned i = 0; i < fileChooser->filenames().size(); ++i) 445 option.suggestedFileNames += fileChooser->filenames()[i]; 446 447 QWebPage::ChooseMultipleFilesExtensionReturn output; 448 m_webPage->extension(QWebPage::ChooseMultipleFilesExtension, &option, &output); 449 450 if (!output.fileNames.isEmpty()) { 451 Vector<String> names; 452 for (int i = 0; i < output.fileNames.count(); ++i) 453 names.append(output.fileNames.at(i)); 454 fileChooser->chooseFiles(names); 455 } 456 } else { 457 QString suggestedFile; 458 if (!fileChooser->filenames().isEmpty()) 459 suggestedFile = fileChooser->filenames()[0]; 460 QString file = m_webPage->chooseFile(QWebFramePrivate::kit(frame), suggestedFile); 461 if (!file.isEmpty()) 462 fileChooser->chooseFile(file); 463 } 464 } 465 466 bool ChromeClientQt::setCursor(PlatformCursorHandle) 467 { 468 notImplemented(); 469 return false; 470 } 471 472 void ChromeClientQt::requestGeolocationPermissionForFrame(Frame*, Geolocation*) 473 { 474 // See the comment in WebCore/page/ChromeClient.h 475 notImplemented(); 476 } 477 478 #if USE(ACCELERATED_COMPOSITING) 479 void ChromeClientQt::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer) 480 { 481 if (platformPageClient()) 482 platformPageClient()->setRootGraphicsLayer(graphicsLayer ? graphicsLayer->nativeLayer() : 0); 483 } 484 485 void ChromeClientQt::setNeedsOneShotDrawingSynchronization() 486 { 487 // we want the layers to synchronize next time we update the screen anyway 488 if (platformPageClient()) 489 platformPageClient()->markForSync(false); 490 } 491 492 void ChromeClientQt::scheduleCompositingLayerSync() 493 { 494 // we want the layers to synchronize ASAP 495 if (platformPageClient()) 496 platformPageClient()->markForSync(true); 497 } 498 #endif 499 500 QtAbstractWebPopup* ChromeClientQt::createSelectPopup() 501 { 502 return new QtFallbackWebPopup; 503 } 504 505 } 506