browsercore/core/wrtbrowsercontainer.cpp
author hgs
Fri, 15 Oct 2010 17:30:59 -0400
changeset 16 3c88a81ff781
parent 12 afcd8e6d025b
permissions -rw-r--r--
201041

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 2.1 of the License.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, 
* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
*
* Description:
*
*/

#include "browserpagefactory.h"
#include "wrtbrowsercontainer_p.h"
#include "wrtbrowsercontainer.h"
#include "webpagedata.h"
#include "SchemeHandlerBr.h"
#include "webnetworkaccessmanager.h"
#include "webcookiejar.h"
#include "secureuicontroller.h"
#include "LoadController.h"
#include "WebDialogProvider.h"
#include "bedrockprovisioning.h"
#include <QPainter>
#include <QAuthenticator>
#include <QFile>
#include <QMessageBox>
#include <QWebHistory>
#include <QWebFrame>
#include <QGraphicsWebView>

#ifdef QT_GEOLOCATION
#include "geolocationManager.h"

/* Declare the user defined meta type for use with QVariant in geolocation. */
Q_DECLARE_METATYPE(QWebPage::PermissionPolicy);
#endif // QT_GEOLOCATION

QDataStream &operator<<(QDataStream &out, const WebPageData &myObj)
{
    out << myObj.magic
        << myObj.minScale
        << myObj.maxScale
        << myObj.userScalable
        << myObj.initialScale
        << myObj.rect
        << myObj.webViewRect
        << myObj.scale
        << myObj.viewportSize
        << myObj.specifiedWidth
        << myObj.specifiedHeight
        << myObj.fitToScreen;
   return out;
}

QDataStream &operator>>(QDataStream &in, WebPageData &myObj)
{
    in >> myObj.magic
       >> myObj.minScale
       >> myObj.maxScale
       >> myObj.userScalable
       >> myObj.initialScale
       >> myObj.rect
       >> myObj.webViewRect
       >> myObj.scale
       >> myObj.viewportSize
       >> myObj.specifiedWidth
       >> myObj.specifiedHeight
       >> myObj.fitToScreen;
   return in;
}

namespace WRT
{
const int historyItemsCount = 10;

WrtBrowserContainerPrivate::WrtBrowserContainerPrivate(QObject* parent,
		WrtBrowserContainer* page/*never NULL*/) : m_schemeHandler(new SchemeHandler())
,   m_pageFactory(0)
,   m_widget(0)
,   m_fileChooser(0)
,   m_needUpdateThumbnail(false)
{
    m_page = page;

    m_secureController = new WRT::SecureUIController(parent);
    m_loadController = new  WRT::LoadController();
 
    // Turn off the scroll bars of main frame
    m_page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    m_page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
    
}

WrtBrowserContainerPrivate::~WrtBrowserContainerPrivate()
{
	m_page->setView(0);
	if (m_page)
		m_page->disconnect();
	delete m_schemeHandler;
  delete m_secureController;
  delete m_loadController;
  delete m_fileChooser;
}

/*!
 * Static function which creates Wrt page with parent Widget
 * @param parent   : parent widget for the new page
 * @return WrtBrowserContainer : Page handle to the newly created page
 */
WrtBrowserContainer* WrtBrowserContainer::createPageWithWidgetParent(
		QObject* parent, WrtBrowserContainer* page)
{
    if (page)
    {
        page->setParent(parent);
        return page;
    }
    else
        return new WrtBrowserContainer(parent);
}

/*!
 * WrtBrowserContainer Constructor
 * @param parent : Widget parent
 */
WrtBrowserContainer::WrtBrowserContainer(QObject* parent) :
	QWebPage(parent), d(new WrtBrowserContainerPrivate(this, this))
{
    
  settings()->setAttribute(QWebSettings::PluginsEnabled, true);
  BEDROCK_PROVISIONING::BedrockProvisioning * provisioning = BEDROCK_PROVISIONING::BedrockProvisioning::createBedrockProvisioning();
  settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, !provisioning->value("PopupBlocking").toInt());

  // Download related enable "forwardUnsupportedContent" to redirect unsupported content to download manager
	setForwardUnsupportedContent(true);
#ifdef BEDROCK_TILED_BACKING_STORE
#ifndef OWN_BACKING_STORE
	bool enableTiling = BEDROCK_PROVISIONING::BedrockProvisioning::createBedrockProvisioning()->value("EnableTiling").toBool(); 
    settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, enableTiling);
#endif // OWN_BACKING_STORE
    settings()->setAttribute(QWebSettings::ZoomTextOnly, false);
    settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, true);

    //Configure tiling properties
    //This would set tile size to (256, 256) and add 25ms delay between constructing
    //individual tiles. The settings would try to cache an area 1.5x width and 1.5x height
    //of the current viewport (centered to the viewport) with tiles and would drop tiles
    //after they are outside an area 2x the width and 2.5x the height of the viewport.
    //Refer https://bugs.webkit.org/show_bug.cgi?id=39874
    
    BEDROCK_PROVISIONING::BedrockProvisioning* brSettings = BEDROCK_PROVISIONING::BedrockProvisioning::createBedrockProvisioning();
    int tileW = brSettings->value("TilesWidth").toInt();
    int tileH = brSettings->value("TilesHeight").toInt();
    int tileCreationDelay = brSettings->value("TileCreationDelay").toInt();
    qreal coverAreaMultiplier = brSettings->value("TileCoverAreaMultiplier").toDouble();
    qreal keepAreaMultiplier = brSettings->value("TileKeepAreaMultiplier").toDouble();
    setProperty("_q_TiledBackingStoreTileSize", QSize(tileW, tileH));
    setProperty("_q_TiledBackingStoreTileCreationDelay", tileCreationDelay);
    setProperty("_q_TiledBackingStoreCoverAreaMultiplier", QSizeF(coverAreaMultiplier, coverAreaMultiplier));
    setProperty("_q_TiledBackingStoreKeepAreaMultiplier", QSizeF(keepAreaMultiplier, keepAreaMultiplier));
#endif

#ifndef NO_NETWORK_ACCESS_MANAGER	
	setNetworkAccessManager(new WebNetworkAccessManager(this,this));
#endif
	
	history()->setMaximumItemCount(historyItemsCount);

    /* Connect secure related signals and slots */
    connect(mainFrame(), SIGNAL(urlChanged(QUrl)), d->m_secureController, SLOT(setTopLevelScheme(const QUrl &)));
    connect(this, SIGNAL(loadFinished(bool)), d->m_secureController, SLOT( endSecureCheck(bool) ) );
    connect(d->m_secureController, SIGNAL(pageSecureState(int)), this, SLOT(pageSecureState(int)));
    connect(networkAccessManager(), SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)), d->m_secureController, SLOT(onSslErrors(QNetworkReply *, const QList<QSslError> &)));

    connect(this, SIGNAL(loadStarted()), d->m_loadController, SLOT(loadStarted()));
    connect(this, SIGNAL(loadProgress(int)), d->m_loadController, SLOT(loadProgress(int)));
    connect(this, SIGNAL(loadFinished(bool)), d->m_loadController, SLOT(loadFinished(bool)));
    connect(mainFrame(), SIGNAL(urlChanged(QUrl)), d->m_loadController, SLOT(urlChanged(QUrl)));
    connect(mainFrame(), SIGNAL(initialLayoutCompleted()), d->m_loadController, SLOT(initialLayoutCompleted()));
	  
#ifdef QT_GEOLOCATION 
    d->m_geolocationManager = GeolocationManager::getSingleton();
    
    /* Register user defined Meta Types used in geolocation API. */
    qRegisterMetaType<QWebPage::PermissionPolicy>("QWebPage::PermissionPolicy");
    /* Connect the geolocation permission signal to the geolocation handler. */
    connect(this, SIGNAL(requestPermissionFromUser(QWebFrame*, QWebPage::PermissionDomain)),
        this, SLOT(handleRequestPermissionFromUser(QWebFrame*, QWebPage::PermissionDomain)));
#endif // QT_GEOLOCATION
}

/*!
 * WrtBrowserContainer destructor
 */
WrtBrowserContainer::~WrtBrowserContainer()
{
	// gracefully but warn, disconnect anything connected to this page
	if (!disconnect())
		qWarning("WrtPage destructor blanket disconnect failed");

    //setNetworkAccessManager(NULL);
   delete d;
   
   // 
   QList<QWebHistoryItem> items = history()->items();

   for (int i = 0; i < history()->count(); i++) {
       QWebHistoryItem item = items.at(i);
       WebPageData* data = (WebPageData*)(item.userData().value<void*>());
       if(data){
           QVariant variant;
           item.setUserData(variant);
           delete data;
       }
   }
}

QGraphicsWidget* WrtBrowserContainer::webWidget() const
{
    return d->m_widget;
}

void WrtBrowserContainer::setWebWidget(QGraphicsWidget* view)
{
    d->m_widget = view;

    if (view)
    {
        QGraphicsWebView* webView = static_cast<QGraphicsWebView*>(view);
        if(webView)
            webView->setPage(this);

    }
}
 
/*!
 * Handles pageSecureState state 
 */
void WrtBrowserContainer::pageSecureState(int state) {

    emit secureStateChange(state);

}

/*!
 * Returns schemeHandler
 */
SchemeHandler* WrtBrowserContainer::schemeHandler() const
{
   return d->m_schemeHandler;
}

/*!
 *  This function returns a thumbnail image for this page as specified by X & Y co-ordinate scale factors
 * @param  scaleX :  X Co-ordinate scale factor for the page thumbnail
 * @param  scaleY :  y Co-ordinate scale factor for the page thumbnail
 */
QImage WrtBrowserContainer::thumbnail(QSize s)
{
    QImage image(s, QImage::Format_RGB32);
    qreal fitWidth = s.width();
    QPoint renderPos(0, 0);
    WebPageData* d = pageZoomMetaData();
    qreal scale = 1.0;
    if(d->isValid())
    {
        fitWidth = d->rect.width();
        if(fitWidth > d->webViewRect.width() * d->scale)
            fitWidth = d->webViewRect.width() * d->scale;
        renderPos = d->webViewRect.topLeft().toPoint();
        scale = s.width() / (fitWidth / d->scale);
    }

    if (image.isNull()) {
        return QImage();
    }
    QPainter painter(&image);
    QRect r(QPoint(0,0),s);
    QRegion clip(r);
    painter.setBrush(Qt::white);
    painter.fillRect(r,Qt::white);

    QTransform transform;
    transform.scale(scale,scale);
    renderPos /= scale;
    transform.translate(renderPos.x(),renderPos.y());
    painter.setTransform(transform);

    mainFrame()->render(&painter);
    return image;
}
QImage WrtBrowserContainer::pageThumbnail(qreal scaleX, qreal scaleY)
{
    #ifdef Q_WS_MAEMO_5
    QSize size(800,424);
    #else
    QSize size(640,360);
    #endif
    QImage image(size, QImage::Format_RGB32);

    QPainter painter(&image);
    QRect r(0, 0, size.width(), size.height());
    QRegion clip(r);
    painter.save();
    painter.setBrush(Qt::white);
    painter.drawRect(r);
    painter.restore();
    qreal saveZoomFactor = mainFrame()->zoomFactor();
    mainFrame()->setZoomFactor(1.0);
    mainFrame()->render(&painter, clip);
    mainFrame()->setZoomFactor(saveZoomFactor);
    QImage thumbnail = image.scaled(scaleX * size.width(), scaleY * size.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
    return thumbnail;
}

/*!
 Pulic Slots:
 void savePageDataToHistoryItem(QWebFrame*, QWebHistoryItem* item);
 void slotAuthenticationRequired(QNetworkReply *, QAuthenticator *);
 void slotProxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *);
 */

/*!
 * Public slot, saves the page data (like thumbail, current position, zoom factor etc ) to WebHistoryItem
 * @frame  main frame for which the data has to be stored
 * @item   handle to QWebHistoryItem into which the page data has to be saved.
 */

void WrtBrowserContainer::savePageDataToHistoryItem(QWebFrame* frame,
      QWebHistoryItem* item)
{
    if (frame != mainFrame() || !item->isValid() || !webWidget())
    {
        return;
    }
    if (restoreSession()) return;

//    item->setUserData(QVariant::fromValue(d->m_zoomData));
/*    WebPageData data(this);
    //   WebPageData data = item->userData().value<WebPageData>();
    data.m_zoomFactor = 1.0; // Need to find a way to get this.  Not used right now anyway
    data.m_thumbnail = pageThumbnail(0.5, 0.5);//data.m_zoomFactor, data.m_zoomFactor);

    QPoint pos(0, 0);
    //    pos = static_cast<WebCanvasWidget*>(webWidget())->canvas()->canvasToDocument(pos);
    pos = mainFrame()->scrollPosition();
    data.m_contentsPos = pos;
    QVariant variant;
    variant.setValue(data);
    item->setUserData(variant); */
    //ii++;
}

/*!
 * Public slot  AuthenticationRequired
 * Launches dialog for user name and password if Authentication is required for page load.
 * @param reply     : network reply
 * @param  athenticator : athenticator
 */
void WrtBrowserContainer::slotAuthenticationRequired(QNetworkReply* reply,
      QAuthenticator* authenticator)
{
	QString username, password;
	if (WebDialogProvider::getUsernamePassword(0/*webWidget()*/, username, password))
	{
		authenticator->setUser(username);
		authenticator->setPassword(password);
    }
}

/*!
 * public slot for setting proxy when Authentication is Required
 * @param networkProxy : network Proxy
 * @param authenticator : authenticator
 */
void WrtBrowserContainer::slotProxyAuthenticationRequired(
      const QNetworkProxy& networkProxy, QAuthenticator* authenticator)
{
	QString username, password;
	if (WebDialogProvider::getUsernamePassword(0/*webWidget()*/, username, password))
	{
		authenticator->setUser(username);
		authenticator->setPassword(password);
    }
}

#ifdef QT_GEOLOCATION
void WrtBrowserContainer::handleRequestPermissionFromUser(QWebFrame* frame, QWebPage::PermissionDomain permissionDomain)
{
    QList<QVariant> attributes;
    QUrl baseUrl = frame->baseUrl();
    QString domain = baseUrl.host();
    
    qDebug() << "handleRequestPermissionFromUser";
    
    // Check if the domian from the frame already exisit in the database
    attributes = d->m_geolocationManager->findGeodomain(domain);
    
    if (!attributes.isEmpty())
    {
        QWebPage::PermissionPolicy permission
            = attributes.at(0).value<QWebPage::PermissionPolicy>();
       
        setUserPermission(frame, permissionDomain, permission);
    }
    else
    {
        // If the domain is empty string, provide whole base url
        if (domain == "")
            domain = baseUrl.toString();
	          
        emit requestGeolocationPermission(frame, permissionDomain, domain);
    }
}

void WrtBrowserContainer::setGeolocationPermission(QWebFrame* frame, QWebPage::PermissionDomain permissionDomain, 
	       bool permissionGranted, bool saveSetting)
{
    QWebPage::PermissionPolicy permission = QWebPage::PermissionUnknown;
    	
    if (permissionGranted == true)
        permission = QWebPage::PermissionGranted;
    else
        permission = QWebPage::PermissionDenied;
	  	  	
    setUserPermission(frame, permissionDomain, permission);
    
    // save the geolocation permission setting (granted/denied) in the data base
    if (saveSetting)
    {
        QUrl baseUrl = frame->baseUrl();
        QString domain = baseUrl.host();
	      
        // If the domain is empty string, provide whole base url
        if (domain == "")
            domain = baseUrl.toString();
	          
        d->m_geolocationManager->addGeodomain(domain, permission);
    }
}
#endif // QT_GEOLOCATION 

void WrtBrowserContainer::setPageFactory(BrowserPageFactory* f)
{
    d->m_pageFactory = f;
}

QString WrtBrowserContainer::pageTitle(){

    QString title = mainFrame()->title();
    
    // If mainFrame title is empty we may be restoring session
    // Check history title
    if (title.isEmpty()){ 
    	title = history()->currentItem().title();
    }
    
    /* If there is no title, provide the partial url */
    if (title.isEmpty()) {
        QUrl url  = mainFrame()->url(); 
        // If mainframe url is empty, we may be restoring session
        // check history url
        if (url.isEmpty()) {
        	url = history()->currentItem().url();
        }
        title = url.toString();
        QString scheme=url.scheme();
        title.remove(0, scheme.length() + 3); // remove "scheme://"
        if (title.startsWith("www.", Qt::CaseInsensitive)) {
            title.remove(0, 4);
        }

    }
    return title;
}

int WrtBrowserContainer::secureState() {

    return d->m_secureController->secureState();
}
bool WrtBrowserContainer::restoreSession() {
	if (d->m_pageFactory)
    return d->m_pageFactory->m_bRestoreSession;
  else
    return true;
}

bool WrtBrowserContainer::emptyWindow() {

    bool result= false;
    if (mainFrame()->title()  == "" && mainFrame()->url().toString() == "" )
        result = true;

    return result;
}

WebPageData* WrtBrowserContainer::pageZoomMetaData()
{
    QVariant userData = history()->currentItem().userData();
    QVariant::Type t = userData.type();
    int ut = userData.userType();

    if(userData.isValid() && t == QVariant::UserType &&
       ut == QMetaTypeId<WebPageData>::qt_metatype_id())
       return (WebPageData*)(history()->currentItem().userData().constData());
    else {
        static WebPageData dummyData;
        return &dummyData;
    }
}

void WrtBrowserContainer::setPageZoomMetaData(const WebPageData &zoomData ){
    history()->currentItem().setUserData(qVariantFromValue(zoomData));
}


WrtBrowserFileChooser::~WrtBrowserFileChooser()
{}

void WrtBrowserContainer::setFileChooser(WrtBrowserFileChooser * chooser)
{
    if (d->m_fileChooser) {
        delete d->m_fileChooser;
    }

    d->m_fileChooser = chooser;
}

QString WrtBrowserContainer::chooseFile(QWebFrame * parentFrame, const QString & suggestedFile)
{
    if (d->m_fileChooser != 0) {
        return d->m_fileChooser->chooseFile(parentFrame, suggestedFile);
    }

    return QWebPage::chooseFile(parentFrame, suggestedFile);
}

QString WrtBrowserContainer::userAgentForUrl(const QUrl& url) const
{
    QString uaString = BEDROCK_PROVISIONING::BedrockProvisioning::createBedrockProvisioning()->valueAsString("UserAgentString");
   
    if (uaString.isEmpty())
   	{
   	    QUrl url;
        return QWebPage::userAgentForUrl(url); 
   	}
   	else
        return uaString;
}
	
WRT::WrtBrowserContainer* WrtBrowserContainer::createWindow(
    QWebPage::WebWindowType webWindowType)
{

    /* When WrtPage is created, QWebSettings::JavascriptCanOpenWindows is initialized
     * to popup setting value. Need not do any check here 
     */
    if (d->m_pageFactory)
    {
        // no need to signal in this case
        return d->m_pageFactory->openPage();
    }

    WrtBrowserContainer* wrtPage = new WrtBrowserContainer();
    emit createNewWindow(wrtPage);
    return wrtPage;
}

void WrtBrowserContainer::requestPageDataUpdate()
{
    QWebHistoryItem i = history()->currentItem();
    emit saveFrameStateRequested(mainFrame(),&i);
}

} // namespace WRT