1/* 2 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (c) 2012 Hewlett-Packard Development Company, L.P. 4 * Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). 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 program 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 program; 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 23#include "config.h" 24#include "qquickwebview_p.h" 25 26#include "CoordinatedLayerTreeHostProxy.h" 27#include "DownloadProxy.h" 28#include "DrawingAreaProxyImpl.h" 29#include "PageViewportControllerClientQt.h" 30#include "QtDialogRunner.h" 31#include "QtDownloadManager.h" 32#include "QtWebContext.h" 33#include "QtWebError.h" 34#include "QtWebIconDatabaseClient.h" 35#include "QtWebPageEventHandler.h" 36#include "QtWebPagePolicyClient.h" 37#include "WebBackForwardList.h" 38#include "WebContext.h" 39#include "WebFindOptions.h" 40#if ENABLE(INSPECTOR_SERVER) 41#include "WebInspectorProxy.h" 42#include "WebInspectorServer.h" 43#endif 44#if ENABLE(FULLSCREEN_API) 45#include "WebFullScreenManagerProxy.h" 46#endif 47#include "WebPageGroup.h" 48#include "WebPreferences.h" 49#include "qglobal.h" 50#include "qquicknetworkreply_p.h" 51#include "qquicknetworkrequest_p.h" 52#include "qquickwebpage_p_p.h" 53#include "qquickwebview_p_p.h" 54#include "qwebdownloaditem_p_p.h" 55#include "qwebiconimageprovider_p.h" 56#include "qwebkittest_p.h" 57#include "qwebloadrequest_p.h" 58#include "qwebnavigationhistory_p.h" 59#include "qwebnavigationhistory_p_p.h" 60#include "qwebpreferences_p.h" 61#include "qwebpreferences_p_p.h" 62#include <JavaScriptCore/InitializeThreading.h> 63#include <JavaScriptCore/JSBase.h> 64#include <JavaScriptCore/JSRetainPtr.h> 65#include <QDateTime> 66#include <QMap> 67#include <QtCore/QFile> 68#include <QtQml/QJSValue> 69#include <QtQuick/QQuickView> 70#include <WKNumber.h> 71#include <WKOpenPanelResultListener.h> 72#include <WKPageGroup.h> 73#include <WKPreferences.h> 74#include <WKSerializedScriptValue.h> 75#include <WKString.h> 76#include <WKStringQt.h> 77#include <WKURLQt.h> 78#include <WebCore/CoordinatedGraphicsScene.h> 79#include <WebCore/IntPoint.h> 80#include <WebCore/IntRect.h> 81#include <limits> 82#include <wtf/Assertions.h> 83#include <wtf/MainThread.h> 84#include <wtf/Vector.h> 85#include <wtf/text/WTFString.h> 86 87using namespace WebCore; 88using namespace WebKit; 89 90static bool s_flickableViewportEnabled = true; 91static const int kAxisLockSampleCount = 5; 92static const qreal kAxisLockVelocityThreshold = 300; 93static const qreal kAxisLockVelocityDirectionThreshold = 50; 94 95typedef QMap<WKPageRef, QQuickWebViewPrivate*> PageToViewMap; 96Q_GLOBAL_STATIC(PageToViewMap, pageToView) 97 98static inline QQuickWebViewPrivate* toQQuickWebViewPrivate(const void* clientInfo) 99{ 100 ASSERT(clientInfo); 101 return reinterpret_cast<QQuickWebViewPrivate*>(const_cast<void*>(clientInfo)); 102} 103 104struct JSCallbackClosure { 105 QPointer<QObject> receiver; 106 QByteArray method; 107 QJSValue value; 108}; 109 110static inline QString toQString(JSStringRef string) 111{ 112 return QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(string)), JSStringGetLength(string)); 113} 114 115static inline QJSValue toQJSValue(JSStringRef string) 116{ 117 return QJSValue(toQString(string)); 118} 119 120static QJSValue buildQJSValue(QJSEngine* engine, JSGlobalContextRef context, JSValueRef value, int depth) 121{ 122 QJSValue var; 123 JSValueRef exception = 0; 124 125 if (depth > 10) 126 return var; 127 128 switch (JSValueGetType(context, value)) { 129 case kJSTypeBoolean: 130 var = QJSValue(JSValueToBoolean(context, value)); 131 break; 132 case kJSTypeNumber: 133 { 134 double number = JSValueToNumber(context, value, &exception); 135 if (!exception) 136 var = QJSValue(number); 137 } 138 break; 139 case kJSTypeString: 140 { 141 JSRetainPtr<JSStringRef> string = JSValueToStringCopy(context, value, &exception); 142 if (!exception) 143 var = toQJSValue(string.get()); 144 } 145 break; 146 case kJSTypeObject: 147 { 148 JSObjectRef obj = JSValueToObject(context, value, &exception); 149 150 JSPropertyNameArrayRef names = JSObjectCopyPropertyNames(context, obj); 151 size_t length = JSPropertyNameArrayGetCount(names); 152 153 var = engine->newObject(); 154 155 for (size_t i = 0; i < length; ++i) { 156 JSRetainPtr<JSStringRef> name = JSPropertyNameArrayGetNameAtIndex(names, i); 157 JSValueRef property = JSObjectGetProperty(context, obj, name.get(), &exception); 158 159 if (!exception) { 160 QJSValue value = buildQJSValue(engine, context, property, depth + 1); 161 var.setProperty(toQString(name.get()), value); 162 } 163 } 164 } 165 break; 166 } 167 return var; 168} 169 170static void javaScriptCallback(WKSerializedScriptValueRef valueRef, WKErrorRef, void* data) 171{ 172 JSCallbackClosure* closure = reinterpret_cast<JSCallbackClosure*>(data); 173 174 if (closure->method.size()) 175 QMetaObject::invokeMethod(closure->receiver, closure->method); 176 else { 177 QJSValue function = closure->value; 178 179 // If a callable function is supplied, we build a JavaScript value accessible 180 // in the QML engine, and calls the function with that. 181 if (function.isCallable()) { 182 QJSValue var; 183 if (valueRef) { 184 // FIXME: Slow but OK for now. 185 JSGlobalContextRef context = JSGlobalContextCreate(0); 186 187 JSValueRef exception = 0; 188 JSValueRef value = WKSerializedScriptValueDeserialize(valueRef, context, &exception); 189 var = buildQJSValue(function.engine(), context, value, /* depth */ 0); 190 191 JSGlobalContextRelease(context); 192 } 193 194 QList<QJSValue> args; 195 args.append(var); 196 function.call(args); 197 } 198 } 199 200 delete closure; 201} 202 203static QQuickWebViewPrivate* createPrivateObject(QQuickWebView* publicObject) 204{ 205 if (s_flickableViewportEnabled) 206 return new QQuickWebViewFlickablePrivate(publicObject); 207 return new QQuickWebViewLegacyPrivate(publicObject); 208} 209 210QQuickWebViewPrivate* QQuickWebViewPrivate::get(WKPageRef page) 211{ 212 return pageToView()->value(page); 213} 214 215QQuickWebViewPrivate::FlickableAxisLocker::FlickableAxisLocker() 216 : m_allowedDirection(QQuickFlickable::AutoFlickDirection) 217 , m_time(0), m_sampleCount(0) 218{ 219} 220 221QVector2D QQuickWebViewPrivate::FlickableAxisLocker::touchVelocity(const QTouchEvent* event) 222{ 223 static bool touchVelocityAvailable = event->device()->capabilities().testFlag(QTouchDevice::Velocity); 224 const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first(); 225 226 if (touchVelocityAvailable) 227 return touchPoint.velocity(); 228 229 const QLineF movementLine(touchPoint.pos(), m_initialPosition); 230 const ulong elapsed = event->timestamp() - m_time; 231 232 if (!elapsed) 233 return QVector2D(0, 0); 234 235 // Calculate an approximate velocity vector in the unit of pixel / second. 236 return QVector2D(1000 * movementLine.dx() / elapsed, 1000 * movementLine.dy() / elapsed); 237} 238 239void QQuickWebViewPrivate::FlickableAxisLocker::update(const QTouchEvent* event) 240{ 241 ASSERT(event->touchPoints().size() == 1); 242 const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first(); 243 244 ++m_sampleCount; 245 246 if (m_sampleCount == 1) { 247 m_initialPosition = touchPoint.pos(); 248 m_time = event->timestamp(); 249 return; 250 } 251 252 if (m_sampleCount > kAxisLockSampleCount 253 || m_allowedDirection == QQuickFlickable::HorizontalFlick 254 || m_allowedDirection == QQuickFlickable::VerticalFlick) 255 return; 256 257 QVector2D velocity = touchVelocity(event); 258 259 qreal directionIndicator = qAbs(velocity.x()) - qAbs(velocity.y()); 260 261 if (velocity.length() > kAxisLockVelocityThreshold && qAbs(directionIndicator) > kAxisLockVelocityDirectionThreshold) 262 m_allowedDirection = (directionIndicator > 0) ? QQuickFlickable::HorizontalFlick : QQuickFlickable::VerticalFlick; 263} 264 265void QQuickWebViewPrivate::FlickableAxisLocker::setReferencePosition(const QPointF& position) 266{ 267 m_lockReferencePosition = position; 268} 269 270void QQuickWebViewPrivate::FlickableAxisLocker::reset() 271{ 272 m_allowedDirection = QQuickFlickable::AutoFlickDirection; 273 m_sampleCount = 0; 274} 275 276QPointF QQuickWebViewPrivate::FlickableAxisLocker::adjust(const QPointF& position) 277{ 278 if (m_allowedDirection == QQuickFlickable::HorizontalFlick) 279 return QPointF(position.x(), m_lockReferencePosition.y()); 280 281 if (m_allowedDirection == QQuickFlickable::VerticalFlick) 282 return QPointF(m_lockReferencePosition.x(), position.y()); 283 284 return position; 285} 286 287QQuickWebViewPrivate::QQuickWebViewPrivate(QQuickWebView* viewport) 288 : q_ptr(viewport) 289 , experimental(new QQuickWebViewExperimental(viewport, this)) 290 , context(0) 291 , alertDialog(0) 292 , confirmDialog(0) 293 , promptDialog(0) 294 , authenticationDialog(0) 295 , certificateVerificationDialog(0) 296 , itemSelector(0) 297 , proxyAuthenticationDialog(0) 298 , filePicker(0) 299 , databaseQuotaDialog(0) 300 , colorChooser(0) 301 , m_betweenLoadCommitAndFirstFrame(false) 302 , m_useDefaultContentItemSize(true) 303 , m_navigatorQtObjectEnabled(false) 304 , m_renderToOffscreenBuffer(false) 305 , m_allowAnyHTTPSCertificateForLocalHost(false) 306 , m_loadProgress(0) 307{ 308 viewport->setClip(true); 309 viewport->setPixelAligned(true); 310 QObject::connect(viewport, SIGNAL(visibleChanged()), viewport, SLOT(_q_onVisibleChanged())); 311 QObject::connect(viewport, SIGNAL(urlChanged()), viewport, SLOT(_q_onUrlChanged())); 312 pageView.reset(new QQuickWebPage(viewport)); 313} 314 315QQuickWebViewPrivate::~QQuickWebViewPrivate() 316{ 317 webPageProxy->close(); 318 pageToView()->remove(webPage.get()); 319} 320 321// Note: we delay this initialization to make sure that QQuickWebView has its d-ptr in-place. 322void QQuickWebViewPrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef) 323{ 324 pageGroup = pageGroupRef; 325 if (!pageGroup) 326 pageGroup = adoptWK(WKPageGroupCreateWithIdentifier(0)); 327 328 context = contextRef ? QtWebContext::create(contextRef) : QtWebContext::defaultContext(); 329 webPageProxy = toImpl(context->context())->createWebPage(&pageClient, toImpl(pageGroup.get())); 330 webPage = toAPI(webPageProxy.get()); 331 pageToView()->insert(webPage.get(), this); 332 333 webPageProxy->setUseFixedLayout(s_flickableViewportEnabled); 334#if ENABLE(FULLSCREEN_API) 335 webPageProxy->fullScreenManager()->setWebView(q_ptr); 336#endif 337 338 pageEventHandler.reset(new QtWebPageEventHandler(webPage.get(), pageView.data(), q_ptr)); 339 340 { 341 WKPageFindClient findClient; 342 memset(&findClient, 0, sizeof(WKPageFindClient)); 343 findClient.version = kWKPageFindClientCurrentVersion; 344 findClient.clientInfo = this; 345 findClient.didFindString = didFindString; 346 findClient.didFailToFindString = didFailToFindString; 347 WKPageSetPageFindClient(webPage.get(), &findClient); 348 } 349 350 { 351 WKPageLoaderClient loadClient; 352 memset(&loadClient, 0, sizeof(WKPageLoaderClient)); 353 loadClient.version = kWKPageLoaderClientCurrentVersion; 354 loadClient.clientInfo = this; 355 loadClient.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame; 356 loadClient.didReceiveServerRedirectForProvisionalLoadForFrame = didReceiveServerRedirectForProvisionalLoadForFrame; 357 loadClient.didFailProvisionalLoadWithErrorForFrame = didFailLoad; 358 loadClient.didCommitLoadForFrame = didCommitLoadForFrame; 359 loadClient.didFinishLoadForFrame = didFinishLoadForFrame; 360 loadClient.didFailLoadWithErrorForFrame = didFailLoad; 361 loadClient.didSameDocumentNavigationForFrame = didSameDocumentNavigationForFrame; 362 loadClient.didReceiveTitleForFrame = didReceiveTitleForFrame; 363 loadClient.didStartProgress = didStartProgress; 364 loadClient.didChangeProgress = didChangeProgress; 365 loadClient.didFinishProgress = didFinishProgress; 366 loadClient.didChangeBackForwardList = didChangeBackForwardList; 367 WKPageSetPageLoaderClient(webPage.get(), &loadClient); 368 } 369 370 pagePolicyClient.reset(new QtWebPagePolicyClient(webPage.get(), q_ptr)); 371 pageUIClient.reset(new QtWebPageUIClient(webPage.get(), q_ptr)); 372 navigationHistory = adoptPtr(QWebNavigationHistoryPrivate::createHistory(webPage.get())); 373 374 QtWebIconDatabaseClient* iconDatabase = context->iconDatabase(); 375 QObject::connect(iconDatabase, SIGNAL(iconChangedForPageURL(QString)), q_ptr, SLOT(_q_onIconChangedForPageURL(QString))); 376 377 // Any page setting should preferrable be set before creating the page. 378 WKPreferencesRef preferencesRef = WKPageGroupGetPreferences(pageGroup.get()); 379 WKPreferencesSetAcceleratedCompositingEnabled(preferencesRef, true); 380 bool showDebugVisuals = qgetenv("WEBKIT_SHOW_COMPOSITING_DEBUG_VISUALS") == "1"; 381 WKPreferencesSetCompositingBordersVisible(preferencesRef, showDebugVisuals); 382 WKPreferencesSetCompositingRepaintCountersVisible(preferencesRef, showDebugVisuals); 383 WKPreferencesSetFrameFlatteningEnabled(preferencesRef, true); 384 WKPreferencesSetWebGLEnabled(preferencesRef, true); 385 webPageProxy->pageGroup()->preferences()->setForceCompositingMode(true); 386 387 pageClient.initialize(q_ptr, pageEventHandler.data(), &undoController); 388 webPageProxy->initializeWebPage(); 389 webPageProxy->registerApplicationScheme(ASCIILiteral("qrc")); 390 391 q_ptr->setAcceptedMouseButtons(Qt::MouseButtonMask); 392 q_ptr->setAcceptHoverEvents(true); 393 q_ptr->setFlag(QQuickItem::ItemAcceptsDrops, true); 394} 395 396void QQuickWebViewPrivate::didStartProvisionalLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo) 397{ 398 if (!WKFrameIsMainFrame(frame)) 399 return; 400 401 WKRetainPtr<WKURLRef> url = adoptWK(WKFrameCopyProvisionalURL(frame)); 402 403 QQuickWebView* const q = toQQuickWebViewPrivate(clientInfo)->q_func(); 404 405 q->emitUrlChangeIfNeeded(); 406 QWebLoadRequest loadRequest(WKURLCopyQUrl(url.get()), QQuickWebView::LoadStartedStatus); 407 emit q->loadingChanged(&loadRequest); 408} 409 410void QQuickWebViewPrivate::didReceiveServerRedirectForProvisionalLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo) 411{ 412 if (!WKFrameIsMainFrame(frame)) 413 return; 414 415 toQQuickWebViewPrivate(clientInfo)->q_func()->emitUrlChangeIfNeeded(); 416} 417 418void QQuickWebViewPrivate::didFailLoad(WKPageRef, WKFrameRef frame, WKErrorRef errorRef, WKTypeRef, const void* clientInfo) 419{ 420 if (!WKFrameIsMainFrame(frame)) 421 return; 422 423 QQuickWebView* const q = toQQuickWebViewPrivate(clientInfo)->q_func(); 424 ASSERT(!q->loading()); 425 426 QtWebError error(errorRef); 427 if (error.isCancellation()) { 428 QWebLoadRequest loadRequest(q->url(), QQuickWebView::LoadStoppedStatus); 429 emit q->loadingChanged(&loadRequest); 430 return; 431 } 432 433 int errorCode = error.errorCode(); 434 if (errorCode == kWKErrorCodeFrameLoadInterruptedByPolicyChange && errorCode == kWKErrorCodePlugInWillHandleLoad) { 435 QWebLoadRequest loadRequest(q->url(), QQuickWebView::LoadSucceededStatus); 436 q->emitUrlChangeIfNeeded(); 437 emit q->loadingChanged(&loadRequest); 438 return; 439 } 440 441 // We set the unreachable url unconditionally so that the current 442 // active url of the webview when the loadingChanged signal is 443 // emitted reflects the failed url, not the previously committed 444 // url. This also ensures that if the user does not do a loadHtml 445 // with an error page and and unreachable url as a reponse to the 446 // failed load, we can still detect the failed url for reloads. 447 // We need to find a way to do this via the C API or find another 448 // way to do this. 449 toImpl(frame)->setUnreachableURL(error.url()); 450 q->emitUrlChangeIfNeeded(); 451 QWebLoadRequest loadRequest(error.url(), QQuickWebView::LoadFailedStatus, error.description(), static_cast<QQuickWebView::ErrorDomain>(error.type()), errorCode); 452 emit q->loadingChanged(&loadRequest); 453} 454 455void QQuickWebViewPrivate::didCommitLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo) 456{ 457 if (!WKFrameIsMainFrame(frame)) 458 return; 459 QQuickWebViewPrivate* d = toQQuickWebViewPrivate(clientInfo); 460 461 PageViewportController* pageViewportController = d->viewportController(); 462 if (pageViewportController) 463 pageViewportController->didCommitLoad(); 464 465 QQuickWebView* const q = d->q_func(); 466 ASSERT(q->loading()); 467 d->m_betweenLoadCommitAndFirstFrame = true; 468 emit q->navigationHistoryChanged(); 469 emit q->titleChanged(); 470} 471 472void QQuickWebViewPrivate::didFinishLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo) 473{ 474 if (!WKFrameIsMainFrame(frame)) 475 return; 476 477 QQuickWebView* const q = toQQuickWebViewPrivate(clientInfo)->q_func(); 478 ASSERT(!q->loading()); 479 480 QWebLoadRequest loadRequest(q->url(), QQuickWebView::LoadSucceededStatus); 481 emit q->loadingChanged(&loadRequest); 482} 483 484void QQuickWebViewPrivate::didSameDocumentNavigationForFrame(WKPageRef, WKFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef userData, const void* clientInfo) 485{ 486 if (!WKFrameIsMainFrame(frame)) 487 return; 488 QQuickWebView* const q = toQQuickWebViewPrivate(clientInfo)->q_func(); 489 q->emitUrlChangeIfNeeded(); 490 emit q->navigationHistoryChanged(); 491} 492 493void QQuickWebViewPrivate::didReceiveTitleForFrame(WKPageRef, WKStringRef title, WKFrameRef frame, WKTypeRef, const void* clientInfo) 494{ 495 if (!WKFrameIsMainFrame(frame)) 496 return; 497 emit toQQuickWebViewPrivate(clientInfo)->q_func()->titleChanged(); 498} 499 500void QQuickWebViewPrivate::didStartProgress(WKPageRef, const void* clientInfo) 501{ 502 toQQuickWebViewPrivate(clientInfo)->loadProgressDidChange(0); 503} 504 505void QQuickWebViewPrivate::didChangeProgress(WKPageRef page, const void* clientInfo) 506{ 507 toQQuickWebViewPrivate(clientInfo)->loadProgressDidChange(WKPageGetEstimatedProgress(page) * 100); 508} 509 510void QQuickWebViewPrivate::didFinishProgress(WKPageRef, const void* clientInfo) 511{ 512 toQQuickWebViewPrivate(clientInfo)->loadProgressDidChange(100); 513} 514 515void QQuickWebViewPrivate::didChangeBackForwardList(WKPageRef, WKBackForwardListItemRef, WKArrayRef, const void *clientInfo) 516{ 517 toQQuickWebViewPrivate(clientInfo)->navigationHistory->d->reset(); 518} 519 520void QQuickWebViewPrivate::setTransparentBackground(bool enable) 521{ 522 webPageProxy->setDrawsTransparentBackground(enable); 523} 524 525bool QQuickWebViewPrivate::transparentBackground() const 526{ 527 return webPageProxy->drawsTransparentBackground(); 528} 529 530void QQuickWebViewPrivate::loadProgressDidChange(int loadProgress) 531{ 532 Q_Q(QQuickWebView); 533 534 m_loadProgress = loadProgress; 535 536 emit q->loadProgressChanged(); 537} 538 539void QQuickWebViewPrivate::handleMouseEvent(QMouseEvent* event) 540{ 541 switch (event->type()) { 542 case QEvent::MouseButtonPress: 543 pageEventHandler->handleMousePressEvent(event); 544 break; 545 case QEvent::MouseMove: 546 pageEventHandler->handleMouseMoveEvent(event); 547 break; 548 case QEvent::MouseButtonRelease: 549 pageEventHandler->handleMouseReleaseEvent(event); 550 break; 551 case QEvent::MouseButtonDblClick: 552 // If a MouseButtonDblClick was received then we got a MouseButtonPress before. 553 // WebCore will build double-clicks out of press events. 554 event->accept(); 555 break; 556 default: 557 ASSERT_NOT_REACHED(); 558 break; 559 } 560} 561 562void QQuickWebViewPrivate::setNeedsDisplay() 563{ 564 Q_Q(QQuickWebView); 565 if (renderToOffscreenBuffer()) { 566 // This is used only to mantain the rendering synchronisation between the UI and 567 // the web process when running tests even if the render loop is not active. 568 QImage dummyImage(1, 1, QImage::Format_ARGB32); 569 QPainter painter(&dummyImage); 570 q->page()->d->paint(&painter); 571 return; 572 } 573 q->page()->update(); 574} 575 576void QQuickWebViewPrivate::didRenderFrame() 577{ 578 Q_Q(QQuickWebView); 579 if (m_betweenLoadCommitAndFirstFrame) { 580 emit q->experimental()->loadVisuallyCommitted(); 581 m_betweenLoadCommitAndFirstFrame = false; 582 } 583} 584 585void QQuickWebViewPrivate::processDidCrash() 586{ 587 Q_Q(QQuickWebView); 588 589 QUrl url(KURL(WebCore::ParsedURLString, webPageProxy->urlAtProcessExit())); 590 qWarning("WARNING: The web process experienced a crash on '%s'.", qPrintable(url.toString(QUrl::RemoveUserInfo))); 591 592 pageEventHandler->resetGestureRecognizers(); 593 594 // Check if loading was ongoing, when process crashed. 595 if (m_loadProgress > 0 && m_loadProgress < 100) { 596 QWebLoadRequest loadRequest(url, QQuickWebView::LoadFailedStatus, QLatin1String("The web process crashed."), QQuickWebView::InternalErrorDomain, 0); 597 598 loadProgressDidChange(100); 599 emit q->loadingChanged(&loadRequest); 600 } 601} 602 603void QQuickWebViewPrivate::didRelaunchProcess() 604{ 605 qWarning("WARNING: The web process has been successfully restarted."); 606 607 if (DrawingAreaProxy *drawingArea = webPageProxy->drawingArea()) { 608 drawingArea->setSize(viewSize(), IntSize(), IntSize()); 609 610 updateViewportSize(); 611 updateUserScripts(); 612 updateSchemeDelegates(); 613 } 614} 615 616PassOwnPtr<DrawingAreaProxy> QQuickWebViewPrivate::createDrawingAreaProxy() 617{ 618 return DrawingAreaProxyImpl::create(webPageProxy.get()); 619} 620 621void QQuickWebViewPrivate::handleDownloadRequest(DownloadProxy* download) 622{ 623 Q_Q(QQuickWebView); 624 // This function is responsible for hooking up a DownloadProxy to our API layer 625 // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be 626 // ready (filled with the ResourceResponse information) so we can pass it through to 627 // our WebViews. 628 QWebDownloadItem* downloadItem = new QWebDownloadItem(); 629 downloadItem->d->downloadProxy = download; 630 631 q->connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), q, SLOT(_q_onReceivedResponseFromDownload(QWebDownloadItem*))); 632 QtWebContext::defaultContext()->downloadManager()->addDownload(toAPI(download), downloadItem); 633} 634 635void QQuickWebViewPrivate::_q_onVisibleChanged() 636{ 637 webPageProxy->viewStateDidChange(WebPageProxy::ViewIsVisible); 638} 639 640void QQuickWebViewPrivate::_q_onUrlChanged() 641{ 642 updateIcon(); 643} 644 645void QQuickWebViewPrivate::_q_onIconChangedForPageURL(const QString& pageUrl) 646{ 647 if (pageUrl != m_currentUrl) 648 return; 649 650 updateIcon(); 651} 652 653/* Called either when the url changes, or when the icon for the current page changes */ 654void QQuickWebViewPrivate::updateIcon() 655{ 656 Q_Q(QQuickWebView); 657 658 QQuickView* view = qobject_cast<QQuickView*>(q->window()); 659 if (!view) 660 return; 661 662 QWebIconImageProvider* provider = static_cast<QWebIconImageProvider*>( 663 view->engine()->imageProvider(QWebIconImageProvider::identifier())); 664 if (!provider) 665 return; 666 667 QUrl iconUrl = provider->iconURLForPageURLInContext(m_currentUrl, context); 668 669 if (iconUrl == m_iconUrl) 670 return; 671 672 m_iconUrl = iconUrl; 673 emit q->iconChanged(); 674} 675 676void QQuickWebViewPrivate::_q_onReceivedResponseFromDownload(QWebDownloadItem* downloadItem) 677{ 678 // Now that our downloadItem has everything we need we can emit downloadRequested. 679 if (!downloadItem) 680 return; 681 682 Q_Q(QQuickWebView); 683 QQmlEngine::setObjectOwnership(downloadItem, QQmlEngine::JavaScriptOwnership); 684 emit q->experimental()->downloadRequested(downloadItem); 685} 686 687void QQuickWebViewPrivate::runJavaScriptAlert(const QString& alertText) 688{ 689 Q_Q(QQuickWebView); 690 QtDialogRunner dialogRunner(q); 691 if (!dialogRunner.initForAlert(alertText)) 692 return; 693 694 dialogRunner.run(); 695} 696 697bool QQuickWebViewPrivate::runJavaScriptConfirm(const QString& message) 698{ 699 Q_Q(QQuickWebView); 700 QtDialogRunner dialogRunner(q); 701 if (!dialogRunner.initForConfirm(message)) 702 return true; 703 704 dialogRunner.run(); 705 706 return dialogRunner.wasAccepted(); 707} 708 709QString QQuickWebViewPrivate::runJavaScriptPrompt(const QString& message, const QString& defaultValue, bool& ok) 710{ 711 Q_Q(QQuickWebView); 712 QtDialogRunner dialogRunner(q); 713 if (!dialogRunner.initForPrompt(message, defaultValue)) { 714 ok = true; 715 return defaultValue; 716 } 717 718 dialogRunner.run(); 719 720 ok = dialogRunner.wasAccepted(); 721 return dialogRunner.result(); 722} 723 724void QQuickWebViewPrivate::handleAuthenticationRequiredRequest(const QString& hostname, const QString& realm, const QString& prefilledUsername, QString& username, QString& password) 725{ 726 Q_Q(QQuickWebView); 727 QtDialogRunner dialogRunner(q); 728 if (!dialogRunner.initForAuthentication(hostname, realm, prefilledUsername)) 729 return; 730 731 dialogRunner.run(); 732 733 username = dialogRunner.username(); 734 password = dialogRunner.password(); 735} 736 737void QQuickWebViewPrivate::handleProxyAuthenticationRequiredRequest(const QString& hostname, uint16_t port, const QString& prefilledUsername, QString& username, QString& password) 738{ 739 Q_Q(QQuickWebView); 740 QtDialogRunner dialogRunner(q); 741 if (!dialogRunner.initForProxyAuthentication(hostname, port, prefilledUsername)) 742 return; 743 744 dialogRunner.run(); 745 746 username = dialogRunner.username(); 747 password = dialogRunner.password(); 748} 749 750bool QQuickWebViewPrivate::handleCertificateVerificationRequest(const QString& hostname) 751{ 752 Q_Q(QQuickWebView); 753 754 if (m_allowAnyHTTPSCertificateForLocalHost 755 && (hostname == QStringLiteral("127.0.0.1") || hostname == QStringLiteral("localhost"))) 756 return true; 757 758 QtDialogRunner dialogRunner(q); 759 if (!dialogRunner.initForCertificateVerification(hostname)) 760 return false; 761 762 dialogRunner.run(); 763 764 return dialogRunner.wasAccepted(); 765} 766 767void QQuickWebViewPrivate::chooseFiles(WKOpenPanelResultListenerRef listenerRef, const QStringList& selectedFileNames, QtWebPageUIClient::FileChooserType type) 768{ 769 Q_Q(QQuickWebView); 770 771 QtDialogRunner dialogRunner(q); 772 if (!dialogRunner.initForFilePicker(selectedFileNames, (type == QtWebPageUIClient::MultipleFilesSelection))) 773 return; 774 775 dialogRunner.run(); 776 777 if (dialogRunner.wasAccepted()) { 778 QStringList selectedPaths = dialogRunner.filePaths(); 779 780 Vector<RefPtr<APIObject> > wkFiles(selectedPaths.size()); 781 for (unsigned i = 0; i < selectedPaths.size(); ++i) 782 wkFiles[i] = WebURL::create(QUrl::fromLocalFile(selectedPaths.at(i)).toString()); 783 784 WKOpenPanelResultListenerChooseFiles(listenerRef, toAPI(ImmutableArray::adopt(wkFiles).leakRef())); 785 } else 786 WKOpenPanelResultListenerCancel(listenerRef); 787 788} 789 790quint64 QQuickWebViewPrivate::exceededDatabaseQuota(const QString& databaseName, const QString& displayName, WKSecurityOriginRef securityOrigin, quint64 currentQuota, quint64 currentOriginUsage, quint64 currentDatabaseUsage, quint64 expectedUsage) 791{ 792 Q_Q(QQuickWebView); 793 QtDialogRunner dialogRunner(q); 794 if (!dialogRunner.initForDatabaseQuotaDialog(databaseName, displayName, securityOrigin, currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage)) 795 return 0; 796 797 dialogRunner.run(); 798 799 return dialogRunner.wasAccepted() ? dialogRunner.databaseQuota() : 0; 800} 801 802/* The 'WebView' attached property allows items spawned by the webView to 803 refer back to the originating webView through 'WebView.view', similar 804 to how ListView.view and GridView.view is exposed to items. */ 805QQuickWebViewAttached::QQuickWebViewAttached(QObject* object) 806 : QObject(object) 807 , m_view(0) 808{ 809} 810 811void QQuickWebViewAttached::setView(QQuickWebView* view) 812{ 813 if (m_view == view) 814 return; 815 m_view = view; 816 emit viewChanged(); 817} 818 819QQuickWebViewAttached* QQuickWebView::qmlAttachedProperties(QObject* object) 820{ 821 return new QQuickWebViewAttached(object); 822} 823 824 825 826void QQuickWebViewPrivate::addAttachedPropertyTo(QObject* object) 827{ 828 Q_Q(QQuickWebView); 829 QQuickWebViewAttached* attached = static_cast<QQuickWebViewAttached*>(qmlAttachedPropertiesObject<QQuickWebView>(object)); 830 attached->setView(q); 831} 832 833bool QQuickWebViewPrivate::navigatorQtObjectEnabled() const 834{ 835 return m_navigatorQtObjectEnabled; 836} 837 838void QQuickWebViewPrivate::setNavigatorQtObjectEnabled(bool enabled) 839{ 840 ASSERT(enabled != m_navigatorQtObjectEnabled); 841 // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous. 842 m_navigatorQtObjectEnabled = enabled; 843 844 static WKStringRef messageName = WKStringCreateWithUTF8CString("SetNavigatorQtObjectEnabled"); 845 WKRetainPtr<WKBooleanRef> wkEnabled = adoptWK(WKBooleanCreate(enabled)); 846 WKPagePostMessageToInjectedBundle(webPage.get(), messageName, wkEnabled.get()); 847} 848 849static WKRetainPtr<WKStringRef> readUserScript(const QUrl& url) 850{ 851 QString path; 852 if (url.isLocalFile()) 853 path = url.toLocalFile(); 854 else if (url.scheme() == QLatin1String("qrc")) 855 path = QStringLiteral(":") + url.path(); 856 else { 857 qWarning("QQuickWebView: Couldn't open '%s' as user script because only file:/// and qrc:/// URLs are supported.", qPrintable(url.toString())); 858 return 0; 859 } 860 861 QFile file(path); 862 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 863 qWarning("QQuickWebView: Couldn't open '%s' as user script due to error '%s'.", qPrintable(url.toString()), qPrintable(file.errorString())); 864 return 0; 865 } 866 867 QByteArray contents = file.readAll(); 868 if (contents.isEmpty()) 869 qWarning("QQuickWebView: Ignoring '%s' as user script because file is empty.", qPrintable(url.toString())); 870 871 return adoptWK(WKStringCreateWithUTF8CString(contents.constData())); 872} 873 874void QQuickWebViewPrivate::updateUserScripts() 875{ 876 // This feature works per-WebView because we keep an unique page group for 877 // each Page/WebView pair we create. 878 WKPageGroupRemoveAllUserScripts(pageGroup.get()); 879 880 for (unsigned i = 0; i < userScripts.size(); ++i) { 881 const QUrl& url = userScripts.at(i); 882 if (!url.isValid()) { 883 qWarning("QQuickWebView: Couldn't open '%s' as user script because URL is invalid.", qPrintable(url.toString())); 884 continue; 885 } 886 887 WKRetainPtr<WKStringRef> contents = readUserScript(url); 888 if (!contents || WKStringIsEmpty(contents.get())) 889 continue; 890 WKPageGroupAddUserScript(pageGroup.get(), contents.get(), /*baseURL*/ 0, /*whitelistedURLPatterns*/ 0, /*blacklistedURLPatterns*/ 0, kWKInjectInTopFrameOnly, kWKInjectAtDocumentEnd); 891 } 892} 893 894void QQuickWebViewPrivate::updateSchemeDelegates() 895{ 896 webPageProxy->registerApplicationScheme(ASCIILiteral("qrc")); 897 898 QQmlListProperty<QQuickUrlSchemeDelegate> schemes = experimental->schemeDelegates(); 899 for (int i = 0, numSchemes = experimental->schemeDelegates_Count(&schemes); i < numSchemes; ++i) { 900 QQuickUrlSchemeDelegate* scheme = experimental->schemeDelegates_At(&schemes, i); 901 webPageProxy->registerApplicationScheme(scheme->scheme()); 902 } 903} 904 905QPointF QQuickWebViewPrivate::contentPos() const 906{ 907 Q_Q(const QQuickWebView); 908 return QPointF(q->contentX(), q->contentY()); 909} 910 911void QQuickWebViewPrivate::setContentPos(const QPointF& pos) 912{ 913 Q_Q(QQuickWebView); 914 q->setContentX(pos.x()); 915 q->setContentY(pos.y()); 916} 917 918WebCore::IntSize QQuickWebViewPrivate::viewSize() const 919{ 920 return WebCore::IntSize(pageView->width(), pageView->height()); 921} 922 923/*! 924 \internal 925 926 \qmlsignal WebViewExperimental::onMessageReceived(var message) 927 928 \brief Emitted when JavaScript code executing on the web page calls navigator.qt.postMessage(). 929 930 \sa postMessage 931*/ 932void QQuickWebViewPrivate::didReceiveMessageFromNavigatorQtObject(WKStringRef message) 933{ 934 QVariantMap variantMap; 935 variantMap.insert(QLatin1String("data"), WKStringCopyQString(message)); 936 variantMap.insert(QLatin1String("origin"), q_ptr->url()); 937 emit q_ptr->experimental()->messageReceived(variantMap); 938} 939 940CoordinatedGraphicsScene* QQuickWebViewPrivate::coordinatedGraphicsScene() 941{ 942 if (webPageProxy && webPageProxy->drawingArea() && webPageProxy->drawingArea()->coordinatedLayerTreeHostProxy()) 943 return webPageProxy->drawingArea()->coordinatedLayerTreeHostProxy()->coordinatedGraphicsScene(); 944 945 return 0; 946} 947 948float QQuickWebViewPrivate::deviceScaleFactor() 949{ 950 return webPageProxy->deviceScaleFactor(); 951} 952 953void QQuickWebViewPrivate::setIntrinsicDeviceScaleFactor(float scaleFactor) 954{ 955 webPageProxy->setIntrinsicDeviceScaleFactor(scaleFactor); 956} 957 958QQuickWebViewLegacyPrivate::QQuickWebViewLegacyPrivate(QQuickWebView* viewport) 959 : QQuickWebViewPrivate(viewport) 960{ 961} 962 963void QQuickWebViewLegacyPrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef) 964{ 965 QQuickWebViewPrivate::initialize(contextRef, pageGroupRef); 966 967 // Trigger setting of correct visibility flags after everything was allocated and initialized. 968 _q_onVisibleChanged(); 969} 970 971void QQuickWebViewLegacyPrivate::updateViewportSize() 972{ 973 Q_Q(QQuickWebView); 974 QSizeF viewportSize = q->boundingRect().size(); 975 if (viewportSize.isEmpty()) 976 return; 977 978 pageView->setContentsSize(viewportSize); 979 980 if (DrawingAreaProxy *drawingArea = webPageProxy->drawingArea()) { 981 // The fixed layout is handled by the FrameView and the drawing area doesn't behave differently 982 // whether its fixed or not. We still need to tell the drawing area which part of it 983 // has to be rendered on tiles, and in desktop mode it's all of it. 984 drawingArea->setSize(viewportSize.toSize(), IntSize(), IntSize()); 985 // The backing store scale factor should already be set to the device pixel ratio 986 // of the underlying window, thus we set the effective scale to 1 here. 987 drawingArea->setVisibleContentsRect(FloatRect(FloatPoint(), FloatSize(viewportSize)), FloatPoint()); 988 } 989} 990 991qreal QQuickWebViewLegacyPrivate::zoomFactor() const 992{ 993 return WKPageGetPageZoomFactor(webPage.get()); 994} 995 996void QQuickWebViewLegacyPrivate::setZoomFactor(qreal factor) 997{ 998 WKPageSetPageZoomFactor(webPage.get(), factor); 999} 1000 1001QQuickWebViewFlickablePrivate::QQuickWebViewFlickablePrivate(QQuickWebView* viewport) 1002 : QQuickWebViewPrivate(viewport) 1003{ 1004} 1005 1006void QQuickWebViewFlickablePrivate::initialize(WKContextRef contextRef, WKPageGroupRef pageGroupRef) 1007{ 1008 QQuickWebViewPrivate::initialize(contextRef, pageGroupRef); 1009} 1010 1011void QQuickWebViewFlickablePrivate::onComponentComplete() 1012{ 1013 QQuickWebViewPrivate::onComponentComplete(); 1014 1015 Q_Q(QQuickWebView); 1016 m_pageViewportControllerClient.reset(new PageViewportControllerClientQt(q, pageView.data())); 1017 m_pageViewportController.reset(new PageViewportController(webPageProxy.get(), m_pageViewportControllerClient.data())); 1018 pageEventHandler->setViewportController(m_pageViewportControllerClient.data()); 1019 1020 // Trigger setting of correct visibility flags after everything was allocated and initialized. 1021 _q_onVisibleChanged(); 1022} 1023 1024void QQuickWebViewFlickablePrivate::didChangeViewportProperties(const WebCore::ViewportAttributes& newAttributes) 1025{ 1026 if (m_pageViewportController) 1027 m_pageViewportController->didChangeViewportAttributes(newAttributes); 1028} 1029 1030void QQuickWebViewFlickablePrivate::updateViewportSize() 1031{ 1032 Q_Q(QQuickWebView); 1033 1034 if (m_pageViewportController) 1035 m_pageViewportController->didChangeViewportSize(FloatSize(q->width(), q->height())); 1036} 1037 1038void QQuickWebViewFlickablePrivate::pageDidRequestScroll(const QPoint& pos) 1039{ 1040 if (m_pageViewportController) 1041 m_pageViewportController->pageDidRequestScroll(pos); 1042} 1043 1044QQuickWebViewExperimental::QQuickWebViewExperimental(QQuickWebView *webView, QQuickWebViewPrivate* webViewPrivate) 1045 : QObject(webView) 1046 , q_ptr(webView) 1047 , d_ptr(webViewPrivate) 1048 , schemeParent(new QObject(this)) 1049 , m_test(new QWebKitTest(webViewPrivate, this)) 1050{ 1051} 1052 1053QQuickWebViewExperimental::~QQuickWebViewExperimental() 1054{ 1055} 1056 1057void QQuickWebViewExperimental::setRenderToOffscreenBuffer(bool enable) 1058{ 1059 Q_D(QQuickWebView); 1060 d->setRenderToOffscreenBuffer(enable); 1061} 1062 1063bool QQuickWebViewExperimental::renderToOffscreenBuffer() const 1064{ 1065 Q_D(const QQuickWebView); 1066 return d->renderToOffscreenBuffer(); 1067} 1068 1069bool QQuickWebViewExperimental::transparentBackground() const 1070{ 1071 Q_D(const QQuickWebView); 1072 return d->transparentBackground(); 1073} 1074void QQuickWebViewExperimental::setTransparentBackground(bool enable) 1075{ 1076 Q_D(QQuickWebView); 1077 d->setTransparentBackground(enable); 1078} 1079 1080bool QQuickWebViewExperimental::useDefaultContentItemSize() const 1081{ 1082 Q_D(const QQuickWebView); 1083 return d->m_useDefaultContentItemSize; 1084} 1085 1086void QQuickWebViewExperimental::setUseDefaultContentItemSize(bool enable) 1087{ 1088 Q_D(QQuickWebView); 1089 d->m_useDefaultContentItemSize = enable; 1090} 1091 1092/*! 1093 \internal 1094 1095 \qmlproperty int WebViewExperimental::preferredMinimumContentsWidth 1096 \brief Minimum contents width when not overriden by the page itself. 1097 1098 Unless the page defines how contents should be laid out, using e.g. 1099 the viewport meta tag, it is laid out given the width of the viewport 1100 (in CSS units). 1101 1102 This setting can be used to enforce a minimum width when the page 1103 does not define a width itself. This is useful for laying out pages 1104 designed for big screens, commonly knows as desktop pages, on small 1105 devices. 1106 1107 The default value is 0, but the value of 980 is recommented for small 1108 screens as it provides a good trade off between legitable pages and 1109 non-broken content. 1110 */ 1111int QQuickWebViewExperimental::preferredMinimumContentsWidth() const 1112{ 1113 Q_D(const QQuickWebView); 1114 return d->webPageProxy->pageGroup()->preferences()->layoutFallbackWidth(); 1115} 1116 1117void QQuickWebViewExperimental::setPreferredMinimumContentsWidth(int width) 1118{ 1119 Q_D(QQuickWebView); 1120 WebPreferences* webPreferences = d->webPageProxy->pageGroup()->preferences(); 1121 1122 if (width == webPreferences->layoutFallbackWidth()) 1123 return; 1124 1125 webPreferences->setLayoutFallbackWidth(width); 1126 emit preferredMinimumContentsWidthChanged(); 1127} 1128 1129void QQuickWebViewExperimental::setFlickableViewportEnabled(bool enable) 1130{ 1131 s_flickableViewportEnabled = enable; 1132} 1133 1134bool QQuickWebViewExperimental::flickableViewportEnabled() 1135{ 1136 return s_flickableViewportEnabled; 1137} 1138 1139/*! 1140 \internal 1141 1142 \qmlmethod void WebViewExperimental::postMessage(string message) 1143 1144 \brief Post a message to an onmessage function registered with the navigator.qt object 1145 by JavaScript code executing on the page. 1146 1147 \sa onMessageReceived 1148*/ 1149 1150void QQuickWebViewExperimental::postMessage(const QString& message) 1151{ 1152 Q_D(QQuickWebView); 1153 static WKStringRef messageName = WKStringCreateWithUTF8CString("MessageToNavigatorQtObject"); 1154 WKRetainPtr<WKStringRef> contents = adoptWK(WKStringCreateWithQString(message)); 1155 WKPagePostMessageToInjectedBundle(d->webPage.get(), messageName, contents.get()); 1156} 1157 1158QQmlComponent* QQuickWebViewExperimental::alertDialog() const 1159{ 1160 Q_D(const QQuickWebView); 1161 return d->alertDialog; 1162} 1163 1164void QQuickWebViewExperimental::setAlertDialog(QQmlComponent* alertDialog) 1165{ 1166 Q_D(QQuickWebView); 1167 if (d->alertDialog == alertDialog) 1168 return; 1169 d->alertDialog = alertDialog; 1170 emit alertDialogChanged(); 1171} 1172 1173QQmlComponent* QQuickWebViewExperimental::confirmDialog() const 1174{ 1175 Q_D(const QQuickWebView); 1176 return d->confirmDialog; 1177} 1178 1179void QQuickWebViewExperimental::setConfirmDialog(QQmlComponent* confirmDialog) 1180{ 1181 Q_D(QQuickWebView); 1182 if (d->confirmDialog == confirmDialog) 1183 return; 1184 d->confirmDialog = confirmDialog; 1185 emit confirmDialogChanged(); 1186} 1187 1188QWebNavigationHistory* QQuickWebViewExperimental::navigationHistory() const 1189{ 1190 return d_ptr->navigationHistory.get(); 1191} 1192 1193QQmlComponent* QQuickWebViewExperimental::promptDialog() const 1194{ 1195 Q_D(const QQuickWebView); 1196 return d->promptDialog; 1197} 1198 1199QWebPreferences* QQuickWebViewExperimental::preferences() const 1200{ 1201 QQuickWebViewPrivate* const d = d_ptr; 1202 if (!d->preferences) 1203 d->preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(d)); 1204 return d->preferences.get(); 1205} 1206 1207void QQuickWebViewExperimental::setPromptDialog(QQmlComponent* promptDialog) 1208{ 1209 Q_D(QQuickWebView); 1210 if (d->promptDialog == promptDialog) 1211 return; 1212 d->promptDialog = promptDialog; 1213 emit promptDialogChanged(); 1214} 1215 1216QQmlComponent* QQuickWebViewExperimental::authenticationDialog() const 1217{ 1218 Q_D(const QQuickWebView); 1219 return d->authenticationDialog; 1220} 1221 1222void QQuickWebViewExperimental::setAuthenticationDialog(QQmlComponent* authenticationDialog) 1223{ 1224 Q_D(QQuickWebView); 1225 if (d->authenticationDialog == authenticationDialog) 1226 return; 1227 d->authenticationDialog = authenticationDialog; 1228 emit authenticationDialogChanged(); 1229} 1230 1231QQmlComponent* QQuickWebViewExperimental::proxyAuthenticationDialog() const 1232{ 1233 Q_D(const QQuickWebView); 1234 return d->proxyAuthenticationDialog; 1235} 1236 1237void QQuickWebViewExperimental::setProxyAuthenticationDialog(QQmlComponent* proxyAuthenticationDialog) 1238{ 1239 Q_D(QQuickWebView); 1240 if (d->proxyAuthenticationDialog == proxyAuthenticationDialog) 1241 return; 1242 d->proxyAuthenticationDialog = proxyAuthenticationDialog; 1243 emit proxyAuthenticationDialogChanged(); 1244} 1245QQmlComponent* QQuickWebViewExperimental::certificateVerificationDialog() const 1246{ 1247 Q_D(const QQuickWebView); 1248 return d->certificateVerificationDialog; 1249} 1250 1251void QQuickWebViewExperimental::setCertificateVerificationDialog(QQmlComponent* certificateVerificationDialog) 1252{ 1253 Q_D(QQuickWebView); 1254 if (d->certificateVerificationDialog == certificateVerificationDialog) 1255 return; 1256 d->certificateVerificationDialog = certificateVerificationDialog; 1257 emit certificateVerificationDialogChanged(); 1258} 1259 1260QQmlComponent* QQuickWebViewExperimental::itemSelector() const 1261{ 1262 Q_D(const QQuickWebView); 1263 return d->itemSelector; 1264} 1265 1266void QQuickWebViewExperimental::setItemSelector(QQmlComponent* itemSelector) 1267{ 1268 Q_D(QQuickWebView); 1269 if (d->itemSelector == itemSelector) 1270 return; 1271 d->itemSelector = itemSelector; 1272 emit itemSelectorChanged(); 1273} 1274 1275QQmlComponent* QQuickWebViewExperimental::filePicker() const 1276{ 1277 Q_D(const QQuickWebView); 1278 return d->filePicker; 1279} 1280 1281void QQuickWebViewExperimental::setFilePicker(QQmlComponent* filePicker) 1282{ 1283 Q_D(QQuickWebView); 1284 if (d->filePicker == filePicker) 1285 return; 1286 d->filePicker = filePicker; 1287 emit filePickerChanged(); 1288} 1289 1290QQmlComponent* QQuickWebViewExperimental::databaseQuotaDialog() const 1291{ 1292 Q_D(const QQuickWebView); 1293 return d->databaseQuotaDialog; 1294} 1295 1296void QQuickWebViewExperimental::setDatabaseQuotaDialog(QQmlComponent* databaseQuotaDialog) 1297{ 1298 Q_D(QQuickWebView); 1299 if (d->databaseQuotaDialog == databaseQuotaDialog) 1300 return; 1301 d->databaseQuotaDialog = databaseQuotaDialog; 1302 emit databaseQuotaDialogChanged(); 1303} 1304 1305QQmlComponent* QQuickWebViewExperimental::colorChooser() const 1306{ 1307 Q_D(const QQuickWebView); 1308 return d->colorChooser; 1309} 1310 1311void QQuickWebViewExperimental::setColorChooser(QQmlComponent* colorChooser) 1312{ 1313 Q_D(QQuickWebView); 1314 if (d->colorChooser == colorChooser) 1315 return; 1316 1317 d->colorChooser = colorChooser; 1318 emit colorChooserChanged(); 1319} 1320 1321QString QQuickWebViewExperimental::userAgent() const 1322{ 1323 Q_D(const QQuickWebView); 1324 WKRetainPtr<WKStringRef> ua = adoptWK(WKPageCopyCustomUserAgent(d->webPage.get())); 1325 return WKStringCopyQString(ua.get()); 1326} 1327 1328void QQuickWebViewExperimental::setUserAgent(const QString& userAgent) 1329{ 1330 Q_D(QQuickWebView); 1331 WKRetainPtr<WKStringRef> newUserAgent = adoptWK(WKStringCreateWithQString(userAgent)); 1332 WKRetainPtr<WKStringRef> currentUserAgent = adoptWK(WKPageCopyCustomUserAgent(d->webPage.get())); 1333 if (WKStringIsEqual(newUserAgent.get(), currentUserAgent.get())) 1334 return; 1335 1336 WKPageSetCustomUserAgent(d->webPage.get(), newUserAgent.get()); 1337 emit userAgentChanged(); 1338} 1339 1340/*! 1341 \internal 1342 1343 \qmlproperty int WebViewExperimental::deviceWidth 1344 \brief The device width used by the viewport calculations. 1345 1346 The value used when calculation the viewport, eg. what is used for 'device-width' when 1347 used in the viewport meta tag. If unset (zero or negative width), the width of the 1348 actual viewport is used instead. 1349*/ 1350 1351int QQuickWebViewExperimental::deviceWidth() const 1352{ 1353 Q_D(const QQuickWebView); 1354 return d->webPageProxy->pageGroup()->preferences()->deviceWidth(); 1355} 1356 1357void QQuickWebViewExperimental::setDeviceWidth(int value) 1358{ 1359 Q_D(QQuickWebView); 1360 d->webPageProxy->pageGroup()->preferences()->setDeviceWidth(qMax(0, value)); 1361 emit deviceWidthChanged(); 1362} 1363 1364/*! 1365 \internal 1366 1367 \qmlproperty int WebViewExperimental::deviceHeight 1368 \brief The device width used by the viewport calculations. 1369 1370 The value used when calculation the viewport, eg. what is used for 'device-height' when 1371 used in the viewport meta tag. If unset (zero or negative height), the height of the 1372 actual viewport is used instead. 1373*/ 1374 1375int QQuickWebViewExperimental::deviceHeight() const 1376{ 1377 Q_D(const QQuickWebView); 1378 return d->webPageProxy->pageGroup()->preferences()->deviceHeight(); 1379} 1380 1381void QQuickWebViewExperimental::setDeviceHeight(int value) 1382{ 1383 Q_D(QQuickWebView); 1384 d->webPageProxy->pageGroup()->preferences()->setDeviceHeight(qMax(0, value)); 1385 emit deviceHeightChanged(); 1386} 1387 1388/*! 1389 \internal 1390 1391 \qmlmethod void WebViewExperimental::evaluateJavaScript(string script [, function(result)]) 1392 1393 \brief Evaluates the specified JavaScript and, if supplied, calls a function with the result. 1394*/ 1395 1396void QQuickWebViewExperimental::evaluateJavaScript(const QString& script, const QJSValue& value) 1397{ 1398 JSCallbackClosure* closure = new JSCallbackClosure; 1399 1400 closure->receiver = this; 1401 closure->value = value; 1402 1403 WKRetainPtr<WKStringRef> scriptString = adoptWK(WKStringCreateWithQString(script)); 1404 WKPageRunJavaScriptInMainFrame(d_ptr->webPage.get(), scriptString.get(), closure, javaScriptCallback); 1405} 1406 1407void QQuickWebViewExperimental::findText(const QString& string, FindFlags options) 1408{ 1409 Q_D(QQuickWebView); 1410 if (string.isEmpty()) { 1411 WKPageHideFindUI(d->webPage.get()); 1412 return; 1413 } 1414 1415 WKFindOptions wkOptions = kWKFindOptionsCaseInsensitive; 1416 if (options & FindCaseSensitively) 1417 wkOptions = wkOptions & ~kWKFindOptionsCaseInsensitive; 1418 if (options & FindBackward) 1419 wkOptions |= kWKFindOptionsBackwards; 1420 if (options & FindWrapsAroundDocument) 1421 wkOptions |= kWKFindOptionsWrapAround; 1422 if (options & FindHighlightAllOccurrences) 1423 wkOptions |= kWKFindOptionsShowHighlight; 1424 1425 WKRetainPtr<WKStringRef> str = adoptWK(WKStringCreateWithQString(string)); 1426 1427 WKPageFindString(d->webPage.get(), str.get(), wkOptions, std::numeric_limits<unsigned>::max() - 1); 1428} 1429 1430QList<QUrl> QQuickWebViewExperimental::userScripts() const 1431{ 1432 Q_D(const QQuickWebView); 1433 return d->userScripts; 1434} 1435 1436void QQuickWebViewExperimental::setUserScripts(const QList<QUrl>& userScripts) 1437{ 1438 Q_D(QQuickWebView); 1439 if (d->userScripts == userScripts) 1440 return; 1441 d->userScripts = userScripts; 1442 d->updateUserScripts(); 1443 emit userScriptsChanged(); 1444} 1445 1446QUrl QQuickWebViewExperimental::remoteInspectorUrl() const 1447{ 1448#if ENABLE(INSPECTOR_SERVER) 1449 return QUrl(WebInspectorServer::shared().inspectorUrlForPageID(d_ptr->webPageProxy->inspector()->remoteInspectionPageID())); 1450#else 1451 return QUrl(); 1452#endif 1453} 1454 1455QQuickUrlSchemeDelegate* QQuickWebViewExperimental::schemeDelegates_At(QQmlListProperty<QQuickUrlSchemeDelegate>* property, int index) 1456{ 1457 const QObjectList children = property->object->children(); 1458 if (index < children.count()) 1459 return static_cast<QQuickUrlSchemeDelegate*>(children.at(index)); 1460 return 0; 1461} 1462 1463void QQuickWebViewExperimental::schemeDelegates_Append(QQmlListProperty<QQuickUrlSchemeDelegate>* property, QQuickUrlSchemeDelegate *scheme) 1464{ 1465 if (!scheme->scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive)) { 1466 qWarning("WARNING: The qrc scheme is reserved to be handled internally. The handler will be ignored."); 1467 delete scheme; 1468 return; 1469 } 1470 1471 QObject* schemeParent = property->object; 1472 scheme->setParent(schemeParent); 1473 QQuickWebViewExperimental* webViewExperimental = qobject_cast<QQuickWebViewExperimental*>(property->object->parent()); 1474 if (!webViewExperimental) 1475 return; 1476 scheme->reply()->setWebViewExperimental(webViewExperimental); 1477 QQuickWebViewPrivate* d = webViewExperimental->d_func(); 1478 d->webPageProxy->registerApplicationScheme(scheme->scheme()); 1479} 1480 1481int QQuickWebViewExperimental::schemeDelegates_Count(QQmlListProperty<QQuickUrlSchemeDelegate>* property) 1482{ 1483 return property->object->children().count(); 1484} 1485 1486void QQuickWebViewExperimental::schemeDelegates_Clear(QQmlListProperty<QQuickUrlSchemeDelegate>* property) 1487{ 1488 const QObjectList children = property->object->children(); 1489 for (int index = 0; index < children.count(); index++) { 1490 QObject* child = children.at(index); 1491 child->setParent(0); 1492 delete child; 1493 } 1494} 1495 1496QQmlListProperty<QQuickUrlSchemeDelegate> QQuickWebViewExperimental::schemeDelegates() 1497{ 1498 return QQmlListProperty<QQuickUrlSchemeDelegate>(schemeParent, 0, 1499 QQuickWebViewExperimental::schemeDelegates_Append, 1500 QQuickWebViewExperimental::schemeDelegates_Count, 1501 QQuickWebViewExperimental::schemeDelegates_At, 1502 QQuickWebViewExperimental::schemeDelegates_Clear); 1503} 1504 1505void QQuickWebViewExperimental::invokeApplicationSchemeHandler(PassRefPtr<QtRefCountedNetworkRequestData> request) 1506{ 1507 RefPtr<QtRefCountedNetworkRequestData> req = request; 1508 if (req->data().m_scheme.startsWith("qrc", false)) { 1509 QQuickQrcSchemeDelegate qrcDelegate(QUrl(QString(req->data().m_urlString))); 1510 qrcDelegate.request()->setNetworkRequestData(req); 1511 qrcDelegate.reply()->setNetworkRequestData(req); 1512 qrcDelegate.reply()->setWebViewExperimental(this); 1513 qrcDelegate.readResourceAndSend(); 1514 return; 1515 } 1516 1517 const QObjectList children = schemeParent->children(); 1518 for (int index = 0; index < children.count(); index++) { 1519 QQuickUrlSchemeDelegate* delegate = qobject_cast<QQuickUrlSchemeDelegate*>(children.at(index)); 1520 if (!delegate) 1521 continue; 1522 if (!delegate->scheme().compare(QString(req->data().m_scheme), Qt::CaseInsensitive)) { 1523 delegate->request()->setNetworkRequestData(req); 1524 delegate->reply()->setNetworkRequestData(req); 1525 emit delegate->receivedRequest(); 1526 return; 1527 } 1528 } 1529} 1530 1531void QQuickWebViewExperimental::sendApplicationSchemeReply(QQuickNetworkReply* reply) 1532{ 1533 d_ptr->webPageProxy->sendApplicationSchemeReply(reply); 1534} 1535 1536void QQuickWebViewExperimental::goForwardTo(int index) 1537{ 1538 d_ptr->navigationHistory->d->goForwardTo(index); 1539} 1540 1541void QQuickWebViewExperimental::goBackTo(int index) 1542{ 1543 d_ptr->navigationHistory->d->goBackTo(index); 1544} 1545 1546QWebKitTest* QQuickWebViewExperimental::test() 1547{ 1548 return m_test; 1549} 1550 1551QQuickWebPage* QQuickWebViewExperimental::page() 1552{ 1553 return q_ptr->page(); 1554} 1555 1556/*! 1557 \page index.html 1558 \title QtWebKit: QML WebView version 3.0 1559 1560 The WebView API allows QML applications to render regions of dynamic 1561 web content. A \e{WebView} component may share the screen with other 1562 QML components or encompass the full screen as specified within the 1563 QML application. 1564 1565 QML WebView version 3.0 is incompatible with previous QML \l 1566 {QtWebKit1::WebView} {WebView} API versions. It allows an 1567 application to load pages into the WebView, either by URL or with 1568 an HTML string, and navigate within session history. By default, 1569 links to different pages load within the same WebView, but applications 1570 may intercept requests to delegate links to other functions. 1571 1572 This sample QML application loads a web page, responds to session 1573 history context, and intercepts requests for external links: 1574 1575 \code 1576 import QtQuick 2.0 1577 import QtWebKit 3.0 1578 1579 Page { 1580 WebView { 1581 id: webview 1582 url: "http://qt-project.org" 1583 width: parent.width 1584 height: parent.height 1585 onNavigationRequested: { 1586 // detect URL scheme prefix, most likely an external link 1587 var schemaRE = /^\w+:/; 1588 if (schemaRE.test(request.url)) { 1589 request.action = WebView.AcceptRequest; 1590 } else { 1591 request.action = WebView.IgnoreRequest; 1592 // delegate request.url here 1593 } 1594 } 1595 } 1596 } 1597 \endcode 1598 1599 \section1 Examples 1600 1601 There are several Qt WebKit examples located in the 1602 \l{Qt WebKit Examples} page. 1603 1604*/ 1605 1606 1607/*! 1608 \qmltype WebView 1609 \instantiates QQuickWebView 1610 \inqmlmodule QtWebKit 3.0 1611 \brief A WebView renders web content within a QML application 1612*/ 1613 1614QQuickWebView::QQuickWebView(QQuickItem* parent) 1615 : QQuickFlickable(parent) 1616 , d_ptr(createPrivateObject(this)) 1617{ 1618 Q_D(QQuickWebView); 1619 d->initialize(); 1620} 1621 1622QQuickWebView::QQuickWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef, QQuickItem* parent) 1623 : QQuickFlickable(parent) 1624 , d_ptr(createPrivateObject(this)) 1625{ 1626 Q_D(QQuickWebView); 1627 d->initialize(contextRef, pageGroupRef); 1628} 1629 1630QQuickWebView::~QQuickWebView() 1631{ 1632} 1633 1634QQuickWebPage* QQuickWebView::page() 1635{ 1636 Q_D(QQuickWebView); 1637 return d->pageView.data(); 1638} 1639 1640/*! 1641 \qmlmethod void WebView::goBack() 1642 1643 Go backward within the browser's session history, if possible. 1644 (Equivalent to the \c{window.history.back()} DOM method.) 1645 1646 \sa WebView::canGoBack 1647*/ 1648void QQuickWebView::goBack() 1649{ 1650 Q_D(QQuickWebView); 1651 WKPageGoBack(d->webPage.get()); 1652} 1653 1654/*! 1655 \qmlmethod void WebView::goForward() 1656 1657 Go forward within the browser's session history, if possible. 1658 (Equivalent to the \c{window.history.forward()} DOM method.) 1659*/ 1660void QQuickWebView::goForward() 1661{ 1662 Q_D(QQuickWebView); 1663 WKPageGoForward(d->webPage.get()); 1664} 1665 1666/*! 1667 \qmlmethod void WebView::stop() 1668 1669 Stop loading the current page. 1670*/ 1671void QQuickWebView::stop() 1672{ 1673 Q_D(QQuickWebView); 1674 WKPageStopLoading(d->webPage.get()); 1675} 1676 1677/*! 1678 \qmlmethod void WebView::reload() 1679 1680 Reload the current page. (Equivalent to the 1681 \c{window.location.reload()} DOM method.) 1682*/ 1683void QQuickWebView::reload() 1684{ 1685 Q_D(QQuickWebView); 1686 1687 WebFrameProxy* mainFrame = d->webPageProxy->mainFrame(); 1688 if (mainFrame && !mainFrame->unreachableURL().isEmpty() && mainFrame->url() != blankURL()) { 1689 // We are aware of the unreachable url on the UI process side, but since we haven't 1690 // loaded alternative/subsitute data for it (an error page eg.) WebCore doesn't know 1691 // about the unreachable url yet. If we just do a reload at this point WebCore will try to 1692 // reload the currently committed url instead of the unrachable url. To work around this 1693 // we override the reload here by doing a manual load. 1694 d->webPageProxy->loadURL(mainFrame->unreachableURL()); 1695 // FIXME: We should make WebCore aware of the unreachable url regardless of substitute-loads 1696 return; 1697 } 1698 1699 WKPageReloadFromOrigin(d->webPage.get()); 1700} 1701 1702/*! 1703 \qmlproperty url WebView::url 1704 1705 The location of the currently displaying HTML page. This writable 1706 property offers the main interface to load a page into a web view. 1707 It functions the same as the \c{window.location} DOM property. 1708 1709 \sa WebView::loadHtml() 1710*/ 1711QUrl QQuickWebView::url() const 1712{ 1713 Q_D(const QQuickWebView); 1714 1715 // FIXME: Enable once we are sure this should not trigger 1716 // Q_ASSERT(d->m_currentUrl == d->webPageProxy->activeURL()); 1717 1718 return QUrl(d->m_currentUrl); 1719} 1720 1721void QQuickWebView::setUrl(const QUrl& url) 1722{ 1723 Q_D(QQuickWebView); 1724 1725 if (url.isEmpty()) 1726 return; 1727 1728 WKRetainPtr<WKURLRef> u = adoptWK(WKURLCreateWithQUrl(url)); 1729 WKPageLoadURL(d->webPage.get(), u.get()); 1730 emitUrlChangeIfNeeded(); 1731} 1732 1733// Make sure we don't emit urlChanged unless it actually changed 1734void QQuickWebView::emitUrlChangeIfNeeded() 1735{ 1736 Q_D(QQuickWebView); 1737 1738 QString activeUrl = d->webPageProxy->activeURL(); 1739 if (activeUrl != d->m_currentUrl) { 1740 d->m_currentUrl = activeUrl; 1741 emit urlChanged(); 1742 } 1743} 1744 1745/*! 1746 \qmlproperty url WebView::icon 1747 1748 The location of the currently displaying Web site icon, also known as favicon 1749 or shortcut icon. This read-only URL corresponds to the image used within a 1750 mobile browser application to represent a bookmarked page on the device's home 1751 screen. 1752 1753 This example uses the \c{icon} property to build an \c{Image} element: 1754 1755 \code 1756 Image { 1757 id: appIcon 1758 source: webView.icon != "" ? webView.icon : "fallbackFavIcon.png"; 1759 ... 1760 } 1761 \endcode 1762*/ 1763QUrl QQuickWebView::icon() const 1764{ 1765 Q_D(const QQuickWebView); 1766 return d->m_iconUrl; 1767} 1768 1769/*! 1770 \qmlproperty int WebView::loadProgress 1771 1772 The amount of the page that has been loaded, expressed as an integer 1773 percentage in the range from \c{0} to \c{100}. 1774*/ 1775int QQuickWebView::loadProgress() const 1776{ 1777 Q_D(const QQuickWebView); 1778 return d->loadProgress(); 1779} 1780 1781/*! 1782 \qmlproperty bool WebView::canGoBack 1783 1784 Returns \c{true} if there are prior session history entries, \c{false} 1785 otherwise. 1786*/ 1787bool QQuickWebView::canGoBack() const 1788{ 1789 Q_D(const QQuickWebView); 1790 return WKPageCanGoBack(d->webPage.get()); 1791} 1792 1793/*! 1794 \qmlproperty bool WebView::canGoForward 1795 1796 Returns \c{true} if there are subsequent session history entries, 1797 \c{false} otherwise. 1798*/ 1799bool QQuickWebView::canGoForward() const 1800{ 1801 Q_D(const QQuickWebView); 1802 return WKPageCanGoForward(d->webPage.get()); 1803} 1804 1805/*! 1806 \qmlproperty bool WebView::loading 1807 1808 Returns \c{true} if the HTML page is currently loading, \c{false} otherwise. 1809*/ 1810bool QQuickWebView::loading() const 1811{ 1812 Q_D(const QQuickWebView); 1813 WKFrameRef mainFrame = WKPageGetMainFrame(d->webPage.get()); 1814 return mainFrame && !(kWKFrameLoadStateFinished == WKFrameGetFrameLoadState(mainFrame)); 1815} 1816 1817/*! 1818 \internal 1819 */ 1820 1821QPointF QQuickWebView::mapToWebContent(const QPointF& pointInViewCoordinates) const 1822{ 1823 Q_D(const QQuickWebView); 1824 return d->pageView->transformFromItem().map(pointInViewCoordinates); 1825} 1826 1827/*! 1828 \internal 1829 */ 1830 1831QRectF QQuickWebView::mapRectToWebContent(const QRectF& rectInViewCoordinates) const 1832{ 1833 Q_D(const QQuickWebView); 1834 return d->pageView->transformFromItem().mapRect(rectInViewCoordinates); 1835} 1836 1837/*! 1838 \internal 1839 */ 1840 1841QPointF QQuickWebView::mapFromWebContent(const QPointF& pointInCSSCoordinates) const 1842{ 1843 Q_D(const QQuickWebView); 1844 return d->pageView->transformToItem().map(pointInCSSCoordinates); 1845} 1846 1847/*! 1848 \internal 1849 */ 1850QRectF QQuickWebView::mapRectFromWebContent(const QRectF& rectInCSSCoordinates) const 1851{ 1852 Q_D(const QQuickWebView); 1853 return d->pageView->transformToItem().mapRect(rectInCSSCoordinates); 1854} 1855 1856/*! 1857 \qmlproperty string WebView::title 1858 1859 The title of the currently displaying HTML page, a read-only value 1860 that reflects the contents of the \c{<title>} tag. 1861*/ 1862QString QQuickWebView::title() const 1863{ 1864 Q_D(const QQuickWebView); 1865 WKRetainPtr<WKStringRef> t = adoptWK(WKPageCopyTitle(d->webPage.get())); 1866 return WKStringCopyQString(t.get()); 1867} 1868 1869QVariant QQuickWebView::inputMethodQuery(Qt::InputMethodQuery property) const 1870{ 1871 Q_D(const QQuickWebView); 1872 const EditorState& state = d->webPageProxy->editorState(); 1873 1874 switch(property) { 1875 case Qt::ImCursorRectangle: 1876 return QRectF(state.cursorRect); 1877 case Qt::ImFont: 1878 return QVariant(); 1879 case Qt::ImCursorPosition: 1880 return QVariant(static_cast<int>(state.cursorPosition)); 1881 case Qt::ImAnchorPosition: 1882 return QVariant(static_cast<int>(state.anchorPosition)); 1883 case Qt::ImSurroundingText: 1884 return QString(state.surroundingText); 1885 case Qt::ImCurrentSelection: 1886 return QString(state.selectedText); 1887 case Qt::ImMaximumTextLength: 1888 return QVariant(); // No limit. 1889 case Qt::ImHints: 1890 return int(Qt::InputMethodHints(state.inputMethodHints)); 1891 default: 1892 // Rely on the base implementation for ImEnabled, ImHints and ImPreferredLanguage. 1893 return QQuickFlickable::inputMethodQuery(property); 1894 } 1895} 1896 1897/*! 1898 internal 1899 1900 The experimental module consisting on experimental API which will break 1901 from version to version. 1902*/ 1903QQuickWebViewExperimental* QQuickWebView::experimental() const 1904{ 1905 Q_D(const QQuickWebView); 1906 return d->experimental; 1907} 1908 1909/*! 1910 \internal 1911*/ 1912void QQuickWebView::platformInitialize() 1913{ 1914 JSC::initializeThreading(); 1915 WTF::initializeMainThread(); 1916} 1917 1918bool QQuickWebView::childMouseEventFilter(QQuickItem* item, QEvent* event) 1919{ 1920 if (!isVisible() || !isEnabled()) 1921 return false; 1922 1923 // This function is used by MultiPointTouchArea and PinchArea to filter 1924 // touch events, thus to hinder the canvas from sending synthesized 1925 // mouse events to the Flickable implementation we need to reimplement 1926 // childMouseEventFilter to ignore touch and mouse events. 1927 1928 switch (event->type()) { 1929 case QEvent::MouseButtonPress: 1930 case QEvent::MouseMove: 1931 case QEvent::MouseButtonRelease: 1932 case QEvent::TouchBegin: 1933 case QEvent::TouchUpdate: 1934 case QEvent::TouchEnd: 1935 // Force all mouse and touch events through the default propagation path. 1936 return false; 1937 default: 1938 ASSERT(event->type() == QEvent::UngrabMouse); 1939 break; 1940 } 1941 1942 return QQuickFlickable::childMouseEventFilter(item, event); 1943} 1944 1945void QQuickWebView::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) 1946{ 1947 Q_D(QQuickWebView); 1948 QQuickFlickable::geometryChanged(newGeometry, oldGeometry); 1949 if (newGeometry.size() != oldGeometry.size()) 1950 d->updateViewportSize(); 1951} 1952 1953void QQuickWebView::componentComplete() 1954{ 1955 Q_D(QQuickWebView); 1956 QQuickFlickable::componentComplete(); 1957 1958 d->onComponentComplete(); 1959 d->updateViewportSize(); 1960} 1961 1962void QQuickWebView::keyPressEvent(QKeyEvent* event) 1963{ 1964 Q_D(QQuickWebView); 1965 d->pageEventHandler->handleKeyPressEvent(event); 1966} 1967 1968void QQuickWebView::keyReleaseEvent(QKeyEvent* event) 1969{ 1970 Q_D(QQuickWebView); 1971 d->pageEventHandler->handleKeyReleaseEvent(event); 1972} 1973 1974void QQuickWebView::inputMethodEvent(QInputMethodEvent* event) 1975{ 1976 Q_D(QQuickWebView); 1977 d->pageEventHandler->handleInputMethodEvent(event); 1978} 1979 1980void QQuickWebView::focusInEvent(QFocusEvent* event) 1981{ 1982 Q_D(QQuickWebView); 1983 d->pageEventHandler->handleFocusInEvent(event); 1984} 1985 1986void QQuickWebView::itemChange(ItemChange change, const ItemChangeData &value) 1987{ 1988 Q_D(QQuickWebView); 1989 if (change == ItemActiveFocusHasChanged) { 1990 bool focus = value.boolValue; 1991 if (!focus) 1992 d->pageEventHandler->handleFocusLost(); 1993 } 1994 QQuickFlickable::itemChange(change, value); 1995} 1996 1997void QQuickWebView::touchEvent(QTouchEvent* event) 1998{ 1999 Q_D(QQuickWebView); 2000 2001 bool lockingDisabled = flickableDirection() != AutoFlickDirection 2002 || event->touchPoints().size() != 1 2003 || width() >= contentWidth() 2004 || height() >= contentHeight(); 2005 2006 if (!lockingDisabled) 2007 d->axisLocker.update(event); 2008 else 2009 d->axisLocker.reset(); 2010 2011 forceActiveFocus(); 2012 d->pageEventHandler->handleTouchEvent(event); 2013} 2014 2015void QQuickWebView::mousePressEvent(QMouseEvent* event) 2016{ 2017 Q_D(QQuickWebView); 2018 forceActiveFocus(); 2019 d->handleMouseEvent(event); 2020} 2021 2022void QQuickWebView::mouseMoveEvent(QMouseEvent* event) 2023{ 2024 Q_D(QQuickWebView); 2025 d->handleMouseEvent(event); 2026} 2027 2028void QQuickWebView::mouseReleaseEvent(QMouseEvent* event) 2029{ 2030 Q_D(QQuickWebView); 2031 d->handleMouseEvent(event); 2032} 2033 2034void QQuickWebView::mouseDoubleClickEvent(QMouseEvent* event) 2035{ 2036 Q_D(QQuickWebView); 2037 forceActiveFocus(); 2038 d->handleMouseEvent(event); 2039} 2040 2041void QQuickWebView::wheelEvent(QWheelEvent* event) 2042{ 2043 Q_D(QQuickWebView); 2044 d->pageEventHandler->handleWheelEvent(event); 2045} 2046 2047void QQuickWebView::hoverEnterEvent(QHoverEvent* event) 2048{ 2049 Q_D(QQuickWebView); 2050 // Map HoverEnter to Move, for WebKit the distinction doesn't matter. 2051 d->pageEventHandler->handleHoverMoveEvent(event); 2052} 2053 2054void QQuickWebView::hoverMoveEvent(QHoverEvent* event) 2055{ 2056 Q_D(QQuickWebView); 2057 d->pageEventHandler->handleHoverMoveEvent(event); 2058} 2059 2060void QQuickWebView::hoverLeaveEvent(QHoverEvent* event) 2061{ 2062 Q_D(QQuickWebView); 2063 d->pageEventHandler->handleHoverLeaveEvent(event); 2064} 2065 2066void QQuickWebView::dragMoveEvent(QDragMoveEvent* event) 2067{ 2068 Q_D(QQuickWebView); 2069 d->pageEventHandler->handleDragMoveEvent(event); 2070} 2071 2072void QQuickWebView::dragEnterEvent(QDragEnterEvent* event) 2073{ 2074 Q_D(QQuickWebView); 2075 d->pageEventHandler->handleDragEnterEvent(event); 2076} 2077 2078void QQuickWebView::dragLeaveEvent(QDragLeaveEvent* event) 2079{ 2080 Q_D(QQuickWebView); 2081 d->pageEventHandler->handleDragLeaveEvent(event); 2082} 2083 2084void QQuickWebView::dropEvent(QDropEvent* event) 2085{ 2086 Q_D(QQuickWebView); 2087 d->pageEventHandler->handleDropEvent(event); 2088} 2089 2090bool QQuickWebView::event(QEvent* ev) 2091{ 2092 // Re-implemented for possible future use without breaking binary compatibility. 2093 return QQuickFlickable::event(ev); 2094} 2095 2096WKPageRef QQuickWebView::pageRef() const 2097{ 2098 Q_D(const QQuickWebView); 2099 return d->webPage.get(); 2100} 2101 2102QPointF QQuickWebView::contentPos() const 2103{ 2104 Q_D(const QQuickWebView); 2105 return d->contentPos(); 2106} 2107 2108void QQuickWebView::setContentPos(const QPointF& pos) 2109{ 2110 Q_D(QQuickWebView); 2111 2112 if (pos == contentPos()) 2113 return; 2114 2115 d->setContentPos(pos); 2116} 2117 2118void QQuickWebView::handleFlickableMousePress(const QPointF& position, qint64 eventTimestampMillis) 2119{ 2120 Q_D(QQuickWebView); 2121 d->axisLocker.setReferencePosition(position); 2122 QMouseEvent mouseEvent(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); 2123 mouseEvent.setTimestamp(eventTimestampMillis); 2124 QQuickFlickable::mousePressEvent(&mouseEvent); 2125} 2126 2127void QQuickWebView::handleFlickableMouseMove(const QPointF& position, qint64 eventTimestampMillis) 2128{ 2129 Q_D(QQuickWebView); 2130 QMouseEvent mouseEvent(QEvent::MouseMove, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); 2131 mouseEvent.setTimestamp(eventTimestampMillis); 2132 QQuickFlickable::mouseMoveEvent(&mouseEvent); 2133} 2134 2135void QQuickWebView::handleFlickableMouseRelease(const QPointF& position, qint64 eventTimestampMillis) 2136{ 2137 Q_D(QQuickWebView); 2138 QMouseEvent mouseEvent(QEvent::MouseButtonRelease, d->axisLocker.adjust(position), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); 2139 d->axisLocker.reset(); 2140 mouseEvent.setTimestamp(eventTimestampMillis); 2141 QQuickFlickable::mouseReleaseEvent(&mouseEvent); 2142} 2143 2144/*! 2145 \qmlmethod void WebView::loadHtml(string html, url baseUrl, url unreachableUrl) 2146 \brief Loads the specified \a html as the content of the web view. 2147 2148 (This method offers a lower-level alternative to the \c{url} property, 2149 which references HTML pages via URL.) 2150 2151 External objects such as stylesheets or images referenced in the HTML 2152 document are located relative to \a baseUrl. For example if provided \a html 2153 was originally retrieved from \c http://www.example.com/documents/overview.html 2154 and that was the base url, then an image referenced with the relative url \c diagram.png 2155 would be looked for at \c{http://www.example.com/documents/diagram.png}. 2156 2157 If an \a unreachableUrl is passed it is used as the url for the loaded 2158 content. This is typically used to display error pages for a failed 2159 load. 2160 2161 \sa WebView::url 2162*/ 2163void QQuickWebView::loadHtml(const QString& html, const QUrl& baseUrl, const QUrl& unreachableUrl) 2164{ 2165 Q_D(QQuickWebView); 2166 WKRetainPtr<WKStringRef> htmlRef = adoptWK(WKStringCreateWithQString(html)); 2167 WKRetainPtr<WKURLRef> baseUrlRef = adoptWK(WKURLCreateWithQUrl(baseUrl)); 2168 WKRetainPtr<WKURLRef> unreachableUrlRef = adoptWK(WKURLCreateWithQUrl(unreachableUrl)); 2169 2170 if (unreachableUrl.isValid()) 2171 WKPageLoadAlternateHTMLString(d->webPage.get(), htmlRef.get(), baseUrlRef.get(), unreachableUrlRef.get()); 2172 else 2173 WKPageLoadHTMLString(d->webPage.get(), htmlRef.get(), baseUrlRef.get()); 2174} 2175 2176qreal QQuickWebView::zoomFactor() const 2177{ 2178 Q_D(const QQuickWebView); 2179 return d->zoomFactor(); 2180} 2181 2182void QQuickWebView::setZoomFactor(qreal factor) 2183{ 2184 2185 Q_D(QQuickWebView); 2186 d->setZoomFactor(factor); 2187} 2188 2189void QQuickWebView::runJavaScriptInMainFrame(const QString &script, QObject *receiver, const char *method) 2190{ 2191 Q_D(QQuickWebView); 2192 2193 JSCallbackClosure* closure = new JSCallbackClosure; 2194 closure->receiver = receiver; 2195 closure->method = method; 2196 2197 WKRetainPtr<WKStringRef> scriptString = adoptWK(WKStringCreateWithQString(script)); 2198 WKPageRunJavaScriptInMainFrame(d->webPage.get(), scriptString.get(), closure, javaScriptCallback); 2199} 2200 2201bool QQuickWebView::allowAnyHTTPSCertificateForLocalHost() const 2202{ 2203 Q_D(const QQuickWebView); 2204 return d->m_allowAnyHTTPSCertificateForLocalHost; 2205} 2206 2207void QQuickWebView::setAllowAnyHTTPSCertificateForLocalHost(bool allow) 2208{ 2209 Q_D(QQuickWebView); 2210 d->m_allowAnyHTTPSCertificateForLocalHost = allow; 2211} 2212 2213void QQuickWebViewPrivate::didFindString(WKPageRef, WKStringRef, unsigned matchCount, const void* clientInfo) 2214{ 2215 QQuickWebView* q = toQQuickWebViewPrivate(clientInfo)->q_ptr; 2216 emit q->experimental()->textFound(matchCount); 2217} 2218 2219void QQuickWebViewPrivate::didFailToFindString(WKPageRef page, WKStringRef string, const void* clientInfo) 2220{ 2221 QQuickWebViewPrivate::didFindString(page, string, 0, clientInfo); 2222} 2223 2224/*! 2225 \qmlsignal WebView::onLoadingChanged(loadRequest) 2226 2227 Occurs when any page load begins, ends, or fails. Various read-only 2228 parameters are available on the \a loadRequest: 2229 2230 \list 2231 2232 \li \c{url}: the location of the resource that is loading. 2233 2234 \li \c{status}: Reflects one of three load states: 2235 \c{LoadStartedStatus}, \c{LoadSucceededStatus}, or 2236 \c{LoadFailedStatus}. See \c{WebView::LoadStatus}. 2237 2238 \li \c{errorString}: description of load error. 2239 2240 \li \c{errorCode}: HTTP error code. 2241 2242 \li \c{errorDomain}: high-level error types, one of 2243 \c{NetworkErrorDomain}, \c{HttpErrorDomain}, \c{InternalErrorDomain}, 2244 \c{DownloadErrorDomain}, or \c{NoErrorDomain}. See 2245 \l{WebView::ErrorDomain}. 2246 2247 \endlist 2248 2249 \sa WebView::loading 2250*/ 2251 2252/*! 2253 \qmlsignal WebView::onLinkHovered(hoveredUrl, hoveredTitle) 2254 2255 Within a mouse-driven interface, this signal is emitted when a mouse 2256 pointer passes over a link, corresponding to the \c{mouseover} DOM 2257 event. (May also occur in touch interfaces for \c{mouseover} events 2258 that are not cancelled with \c{preventDefault()}.) The \a{hoveredUrl} 2259 provides the link's location, and the \a{hoveredTitle} is any avalable 2260 link text. 2261*/ 2262 2263/*! 2264 \qmlsignal WebView::onNavigationRequested(request) 2265 2266 Occurs for various kinds of navigation. If the application listens 2267 for this signal, it must set the \c{request.action} to either of the 2268 following \l{WebView::NavigationRequestAction} enum values: 2269 2270 \list 2271 2272 \li \c{AcceptRequest}: Allow navigation to external pages within the 2273 web view. This represents the default behavior when no listener is 2274 active. 2275 2276 \li \c{IgnoreRequest}: Suppress navigation to new pages within the web 2277 view. (The listener may then delegate navigation externally to 2278 the browser application.) 2279 2280 \endlist 2281 2282 The \a{request} also provides the following read-only values: 2283 2284 \list 2285 2286 \li \c{url}: The location of the requested page. 2287 2288 \li \c{navigationType}: contextual information, one of 2289 \c{LinkClickedNavigation}, \c{BackForwardNavigation}, 2290 \c{ReloadNavigation}, \c{FormSubmittedNavigation}, 2291 \c{FormResubmittedNavigation}, or \c{OtherNavigation} enum values. 2292 See \l{WebView::NavigationType}. 2293 2294 \li \c{keyboardModifiers}: potential states for \l{Qt::KeyboardModifier}. 2295 2296 \li \c{mouseButton}: potential states for \l{Qt::MouseButton}. 2297 2298 \endlist 2299*/ 2300 2301/*! 2302 \qmlproperty enumeration WebView::ErrorDomain 2303 2304 Details various high-level error types. 2305 2306 \table 2307 2308 \header 2309 \li Constant 2310 \li Description 2311 2312 \row 2313 \li InternalErrorDomain 2314 \li Content fails to be interpreted by Qt WebKit. 2315 2316 \row 2317 \li NetworkErrorDomain 2318 \li Error results from faulty network connection. 2319 2320 \row 2321 \li HttpErrorDomain 2322 \li Error is produced by server. 2323 2324 \row 2325 \li DownloadErrorDomain 2326 \li Error in saving file. 2327 2328 \row 2329 \li NoErrorDomain 2330 \li Unspecified fallback error. 2331 2332 \endtable 2333*/ 2334 2335/*! 2336 \qmlproperty enumeration WebView::NavigationType 2337 2338 Distinguishes context for various navigation actions. 2339 2340 \table 2341 2342 \header 2343 \li Constant 2344 \li Description 2345 2346 \row 2347 \li LinkClickedNavigation 2348 \li Navigation via link. 2349 2350 \row 2351 \li FormSubmittedNavigation 2352 \li Form data is posted. 2353 2354 \row 2355 \li BackForwardNavigation 2356 \li Navigation back and forth within session history. 2357 2358 \row 2359 \li ReloadNavigation 2360 \li The current page is reloaded. 2361 2362 \row 2363 \li FormResubmittedNavigation 2364 \li Form data is re-posted. 2365 2366 \row 2367 \li OtherNavigation 2368 \li Unspecified fallback method of navigation. 2369 2370 \endtable 2371*/ 2372 2373/*! 2374 \qmlproperty enumeration WebView::LoadStatus 2375 2376 Reflects a page's load status. 2377 2378 \table 2379 2380 \header 2381 \li Constant 2382 \li Description 2383 2384 \row 2385 \li LoadStartedStatus 2386 \li Page is currently loading. 2387 2388 \row 2389 \li LoadSucceededStatus 2390 \li Page has successfully loaded, and is not currently loading. 2391 2392 \row 2393 \li LoadFailedStatus 2394 \li Page has failed to load, and is not currently loading. 2395 2396 \endtable 2397*/ 2398 2399/*! 2400 \qmlproperty enumeration WebView::NavigationRequestAction 2401 2402 Specifies a policy when navigating a link to an external page. 2403 2404 \table 2405 2406 \header 2407 \li Constant 2408 \li Description 2409 2410 \row 2411 \li AcceptRequest 2412 \li Allow navigation to external pages within the web view. 2413 2414 \row 2415 \li IgnoreRequest 2416 \li Suppress navigation to new pages within the web view. 2417 2418 \endtable 2419*/ 2420 2421#include "moc_qquickwebview_p.cpp" 2422