diff -r 000000000000 -r 1450b09d0cfd browsercore/appfw/ThumbnailEngine/TnEngineHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browsercore/appfw/ThumbnailEngine/TnEngineHandler.cpp Tue May 04 12:39:35 2010 +0300 @@ -0,0 +1,607 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include +#include +#include "webcontentview.h" +#include "TnEngineHandler.h" +#include "TnEngineView.h" +#include "TnEngineGenerator.h" +#include "WrtPageManager.h" +#include "wrtbrowsercontainer.h" +#include "qwebframe.h" +#include + +namespace WRT { + +const int KDefaultZoomOutPercent = 250; // 2.5x TnEngine zoom out by default + +// defines a box relative to TnEngine edges. if view center goes outside this box +// the view is recentered (50%==always center) +const int KHScrollAreaPercent = 33; // horizontal distance in percent +const int KVScrollAreaPercent = 50; // verical distance in percent +const int KHScrollAreaPercentWithTouch1 = 20; // horizontal distance in percent when to scroll +const int KVScrollAreaPercentWithTouch1 = 20; // verical distance in percent when to scroll +const int KHScrollAreaPercentWithTouch2 = 25; // horizontal distance in percent amount to scroll (scroll to the right only) +const int KVScrollAreaPercentWithTouch2 = 25; // verical distance in percent amount to scroll (scroll up only) +const int KUpdateDelayComplete = 45000; // 45s +const int KUpdateDelayLoading = 7000; // 7s +const int KUpdateDelayFullScreen = 4000; // 4s +const int KUpdateCbDelayComplete = 100; // 0.1s +const int KUpdateCbDelayLoading = 1000; // 1s + +TnEngineHandler::TnEngineHandler(WrtPageManager * mgr, QWidget * parent) + : m_pageMgr(mgr), + m_zoomOutLevel(KDefaultZoomOutPercent), + m_needsUpdate(false), + m_documentComplete(false), + m_fullScreenMode(false), + m_pageScalerUpdating(false), + m_activePage(NULL), + m_parentWidget(parent) +{ + m_TnEngineView = NULL; + m_generator = NULL; + m_updateCbTimer = NULL; + m_updateTimer = NULL; + + activate(); +} + +TnEngineHandler::~TnEngineHandler() +{ + deactivate(); +} + +QRect TnEngineHandler::containerRect() const +{ + return m_containerRect; +} + +QRect TnEngineHandler::TnEngineRect() const +{ + QSize s(calcSize()); + //center + QPoint p((m_containerRect.width()-s.width())/2,(m_containerRect.height()-s.height())/2); + return QRect(p,s); +} + +QRect TnEngineHandler::indicatorRect() const +{ + QRect vp(documentViewport()); + QRect TnEngineVp(viewportOnDocument()); + vp.moveTo(vp.topLeft()-TnEngineVp.topLeft()); //make vp relative to TnEngineVp + QRect res = fromDocCoords(vp); //translate vp to mmap coords + // borders + res.moveTo(res.topLeft()+TnEngineRect().topLeft()); + // so that view area is within the indicator + res.adjust(1,1,-1,-1); + // ensure it is within the bounds + QRect mr = TnEngineRect(); + if (res.left() < mr.left()) { + res.setLeft(mr.left()); + } + if (res.top() < mr.top()) { + res.setTop(mr.top()); + } + if (res.right() > mr.right()) { + res.setRight(mr.right()); + } + if (res.bottom() > mr.bottom()) { + res.setBottom(mr.bottom()); + } + return res; +} + +void TnEngineHandler::documentStarted() +{ + scaledPageChanged(theRect(), true, false); + m_documentComplete = false; + m_viewportOnDocument = QRect(); + m_updateTimer->stop(); + m_updateCbTimer->stop(); + m_generator->clear(); + m_needsUpdate = false; + // keep bitmaps during loading to avoid constant realloc + m_generator->setKeepsBitmaps(true); +} + +void TnEngineHandler::documentChanged() +{ + long delay(m_documentComplete?KUpdateCbDelayComplete:KUpdateCbDelayLoading); + m_updateCbTimer->start( delay ); +} + +void TnEngineHandler::documentChangedCb() +{ + m_generator->invalidate(); + if (m_updateTimer->isActive()) { + // timer running, update when it completes + m_needsUpdate = true; + } + else { + if (documentSize().height()>5) { + m_viewportOnDocument = calcViewportOnDocument(); + m_generator->update(); + m_needsUpdate = false; + // don't do another update for.. + long delay(m_fullScreenMode?KUpdateDelayFullScreen:m_documentComplete?KUpdateDelayComplete:KUpdateDelayLoading); + m_updateTimer->start(delay); + } + } +} + +void TnEngineHandler::documentViewportMoved() +{ + m_viewportOnDocument = calcViewportOnDocument(); + m_generator->scroll(); + if (m_visible) { + m_generator->update(true); + } + else { + m_needsUpdate = true; + if (!m_updateTimer->isActive()) { + long delay(m_documentComplete?KUpdateDelayComplete:KUpdateDelayLoading); + m_updateTimer->start(delay); + } + } +} + +void TnEngineHandler::documentCompleted(bool) +{ + if( m_pageScalerUpdating ) return; + + // wait for a while so to make sure all images are decoded etc. + m_needsUpdate = true; + m_documentComplete = true; + m_updateTimer->start(0); + // we can delete the buffers now + m_generator->setKeepsBitmaps(false); + documentChanged(); +} + +QRect TnEngineHandler::viewportOnTnEngine() const +{ + return fromDocCoords(m_viewportOnDocument); +} + + +QRect TnEngineHandler::viewportOnDocument() const +{ + return m_viewportOnDocument; +} + +QSize TnEngineHandler::calcSize() const +{ + QSize res, max; + QSize mms = fromDocCoords(documentSize()); + max = m_containerRect.size(); + res.setWidth(qMin(mms.width(),max.width())); + res.setHeight(qMin(mms.height(),max.height())); + return res; +} + +QRect TnEngineHandler::calcViewportOnDocument() const +{ + QPoint mvp(m_viewportOnDocument.topLeft()); + + QRect docvp(documentViewport()); + QSize docs(documentSize()); + QSize ms(toDocCoords(TnEngineRect().size())); + QPoint docc(docvp.center()); + + if (!m_dragging) { + // scroll if not within 1/3 center area + // check x-direction + if (docc.x()mvp.x()+ms.width()*(100-KHScrollAreaPercent)/100) { + // far enough from the center, re-center the view + mvp.setX(docc.x()-ms.width()/2); + if (mvp.x()+ms.width()>docs.width()) { + mvp.setX(docs.width()-ms.width()); + } + if (mvp.x()<0) { + mvp.setX(0); + } + } + // y-direction + if (docc.y()mvp.y()+ms.height()*(100-KVScrollAreaPercent)/100) { + // far enough from the center, re-center the view + mvp.setY(docc.y()-ms.height()/2); + if (mvp.y()+ms.height()>docs.height()) { + mvp.setY(docs.height()-ms.height()); + } + if (mvp.y()<0) { + mvp.setY(0); + } + } + + } + else { + // check x-direction + bool moved = false; + if (docc.x()mvp.x()+ms.width()*(100-KHScrollAreaPercentWithTouch1)/100) { + mvp.setX(docc.x()-ms.width()*(100-KHScrollAreaPercentWithTouch1)/100); + moved = true; + } + if (moved) { + if (mvp.x()+ms.width()>docs.width()) { + mvp.setX(docs.width()-ms.width()); + } + if (mvp.x()<0) { + mvp.setX(0); + } + } + // y-direction + moved = false; + if (docc.y()mvp.y()+ms.height()*(100-KVScrollAreaPercentWithTouch1)/100) { + mvp.setY(docc.y()-ms.height()*(100-KVScrollAreaPercentWithTouch1)/100); + moved = true; + } + + if (moved) { + if (mvp.y()+ms.height()>docs.height()) { + mvp.setY(docs.height()-ms.height()); + } + if (mvp.y()<0) { + mvp.setY(0); + } + } + } + return QRect(mvp,ms); +} + +void TnEngineHandler::draw(QPainter& gc, const QRect& rect) const +{ + if (m_fullScreenMode) { + QPen pen(Qt::SolidLine); + pen.setColor(QColor(220,220,255)); + QBrush brush(Qt::SolidPattern); + brush.setColor(QColor(220,220,255)); + gc.setPen(pen); + gc.setBrush(brush); + gc.drawRect(m_containerRect); + m_generator->draw(gc, TnEngineRect()); + pen.setWidth(1); + pen.setColor(QColor(255, 0, 0)); + gc.setPen(pen); + gc.setBrush(Qt::NoBrush); + gc.drawRect(indicatorRect()); + } +} + +QRect TnEngineHandler::fromDocCoords(const QRect& from) const +{ + return QRect(fromDocCoords(from.topLeft()),fromDocCoords(from.size())); +} + +QPoint TnEngineHandler::fromDocCoords(const QPoint& from) const +{ + QPoint res; + res.setX(from.x()*100/m_zoomOutLevel); + res.setY(from.y()*100/m_zoomOutLevel); + return res; +} + +QSize TnEngineHandler::fromDocCoords(const QSize& from) const +{ + QSize res; + res.setWidth(from.width()*100/m_zoomOutLevel); + res.setHeight(from.height()*100/m_zoomOutLevel); + return res; +} + +QPoint TnEngineHandler::toDocCoords(const QPoint& from) const +{ + QPoint res; + res.setX(from.x()*m_zoomOutLevel/100); + res.setY(from.y()*m_zoomOutLevel/100); + return res; +} + +QSize TnEngineHandler::toDocCoords(const QSize& from) const +{ + QSize res; + res.setWidth(from.width()*m_zoomOutLevel/100); + res.setHeight(from.height()*m_zoomOutLevel/100); + return res; +} + +QRect TnEngineHandler::toDocCoords(const QRect& from) const +{ + return QRect(toDocCoords(from.topLeft()),toDocCoords(from.size())); +} + +bool TnEngineHandler::checkAndCreateBitmap(QSize sz, QPixmap*& image) +{ + if ( sz.width()<=0 || sz.height()<=0 ) { + // delete bitmap if there was one + delete image; + image = 0; + return false; + } + else { + if ( image && sz != image->size() ) { + // resize if different size + QPixmap* bm = new QPixmap(image->copy(0, 0, sz.width(), sz.height())); + delete image; + image = bm; + } + else if ( !image ) { + // create new + QPixmap* bm = new QPixmap(sz); + image = bm; + } + } + return true; +} + +void TnEngineHandler::updateCbTimerCb() +{ + m_updateCbTimer->stop(); + m_pageScalerUpdating = true; + documentChangedCb(); + m_pageScalerUpdating = false; +} + +void TnEngineHandler::updateTimerCb() +{ + m_updateTimer->stop(); + m_pageScalerUpdating = true; + if (m_needsUpdate) { + m_viewportOnDocument = calcViewportOnDocument(); + m_generator->update(); + } + m_needsUpdate = false; + m_pageScalerUpdating = false; + m_updateTimer->stop(); +} + +QRect TnEngineHandler::theRect() const +{ + return m_containerRect; +} + +void TnEngineHandler::setContainerRect(const QRect& rect) +{ + m_containerRect = rect; + m_viewportOnDocument = calcViewportOnDocument(); +} + +bool TnEngineHandler::isFullScreenMode() const +{ + return m_fullScreenMode; +} + +void TnEngineHandler::setFullScreenMode(bool fullScreenMode) +{ + m_fullScreenMode = fullScreenMode; + m_viewportOnDocument = calcViewportOnDocument(); +} + +void TnEngineHandler::setVisible(bool visible) +{ + if (visible && !m_visible) { + updateNow(); + } + m_visible = visible; +} + +void TnEngineHandler::updateNow() +{ + if (m_updateCbTimer->isActive()) { + m_updateCbTimer->stop(); + m_updateTimer->stop(); + documentChangedCb(); + } + else { + m_updateTimer->stop(); + updateTimerCb(); + } +} + +void TnEngineHandler::drawDocumentPart(QPainter& painter, const QRect& documentAreaToDraw) +{ + QWebFrame* frame = m_activePage->mainFrame(); + QRegion clip(documentAreaToDraw); + painter.save(); + painter.translate(-documentAreaToDraw.x(), -documentAreaToDraw.y()); + frame->render(&painter, clip); + painter.restore(); +} + +QRect TnEngineHandler::documentViewport() const +{ + QSize size = m_activePage->webWidget()->size().toSize(); + QSize offset = QSize(m_scrollX, m_scrollY); + return QRect(offset.width(), offset.height(), size.width(), size.height()); +} + +void TnEngineHandler::scaledPageChanged(const QRect& area, bool /*fullScreen*/, bool /*scroll*/) +{ + if (m_TnEngineView) + m_TnEngineView->update(area); +} + +QSize TnEngineHandler::documentSize() const +{ + return m_activePage->mainFrame()->contentsSize(); +} + +QWidget* TnEngineHandler::widget() +{ + return m_TnEngineView; +} + + +void TnEngineHandler::activate() +{ + if (!m_TnEngineView) { + createGenerator(); + createView(); + } +} + +void TnEngineHandler::deactivate() +{ + if (m_TnEngineView) { + destroyView(); + destroyGenerator(); + } +} + +void TnEngineHandler::createGenerator() +{ + Q_ASSERT(m_pageMgr); + m_activePage = m_pageMgr->currentPage(); + Q_ASSERT(m_activePage); + Q_ASSERT(!m_generator); + m_dragging = false; + QPoint pos(0,0); + pos = m_activePage->mainFrame()->scrollPosition(); + m_scrollX = pos.x(); + m_scrollY = pos.y(); + if (!m_generator) { + m_generator = TnEngineGenerator::initWithTnEngine(*this); + m_updateCbTimer = new QTimer(); + m_updateTimer = new QTimer(); + } +} + +void TnEngineHandler::destroyGenerator() +{ + Q_ASSERT(m_generator); + if (m_generator) { + delete m_generator; + m_generator = NULL; + } + if (m_updateCbTimer) { + m_updateCbTimer->stop(); + delete m_updateCbTimer; + m_updateCbTimer = NULL; + } + if (m_updateTimer) { + m_updateTimer->stop(); + delete m_updateTimer; + m_updateTimer = NULL; + } +} + +void TnEngineHandler::createView() +{ + Q_ASSERT(m_activePage); + connect(m_updateCbTimer, SIGNAL(timeout()), this, SLOT(updateCbTimerCb())); + connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(updateTimerCb())); + // connect(WebController::webController(), SIGNAL(activePageChanged()), this, SLOT(cancelTnEngineView())); + connect(m_activePage, SIGNAL(loadStarted()), this, SLOT(documentStarted())); + connect(m_activePage, SIGNAL(repaintRequested(const QRect&)), this, SLOT(documentChanged())); + connect(m_activePage, SIGNAL(loadFinished(bool)), this, SLOT(documentCompleted(bool))); + // connect(m_activePage, SIGNAL(scrollRequested(int, int, const QRect &)), this, SLOT(documentViewportMoved())); + Q_ASSERT(!m_TnEngineView); + + + + + //m_TnEngineView = TnEngineView::initiWithParentAndTnEngineHandler(m_activePage->webWidget(), this); + m_TnEngineView = TnEngineView::initiWithParentAndTnEngineHandler(m_parentWidget, this); + m_TnEngineView->show(); + m_savedPointPageView = documentViewport().topLeft(); + // connect(m_activePage, SIGNAL(scrollRequested(int, int, const QRect &)), m_TnEngineView, SLOT(update())); + connect(m_TnEngineView, SIGNAL(scrollBy(int, int)), this, SLOT(scrollBy(int, int))); + connect(m_TnEngineView, SIGNAL(scrollStarted()), this, SLOT(draggingStarted())); + connect(m_TnEngineView, SIGNAL(scrollEnded()), this, SLOT(draggingEnded())); + connect(m_TnEngineView, SIGNAL(ok()), this, SLOT(okInvoked())); + // get initial thumbnail + documentStarted(); + documentChanged(); + documentCompleted(true); +} + +void TnEngineHandler::destroyView() +{ + Q_ASSERT(m_activePage); + disconnect(m_updateCbTimer, SIGNAL(timeout()), this, SLOT(updateCbTimerCb())); + disconnect(m_updateTimer, SIGNAL(timeout()), this, SLOT(updateTimerCb())); + // disconnect(WebController::webController(), SIGNAL(activePageChanged()), this, SLOT(cancelTnEngineView())); + disconnect(m_activePage, SIGNAL(loadStarted()), this, SLOT(documentStarted())); + disconnect(m_activePage, SIGNAL(repaintRequested(const QRect&)), this, SLOT(documentChanged())); + disconnect(m_activePage, SIGNAL(loadFinished(bool)), this, SLOT(documentCompleted(bool))); + // disconnect(m_activePage, SIGNAL(scrollRequested(int, int, const QRect &)), this, SLOT(documentViewportMoved())); + Q_ASSERT(m_TnEngineView); + // disconnect(m_activePage, SIGNAL(scrollRequested(int, int, const QRect &)), m_TnEngineView, SLOT(update())); + disconnect(m_TnEngineView, SIGNAL(scrollBy(int, int)), this, SLOT(scrollBy(int, int))); + disconnect(m_TnEngineView, SIGNAL(scrollStarted()), this, SLOT(draggingStarted())); + disconnect(m_TnEngineView, SIGNAL(scrollEnded()), this, SLOT(draggingEnded())); + disconnect(m_TnEngineView, SIGNAL(ok()), this, SLOT(okInvoked())); + m_TnEngineView->hide(); + m_TnEngineView->deleteLater(); + m_TnEngineView = NULL; + m_visible = false; +} + +void TnEngineHandler::scrollBy(int x, int y) +{ + WebContentWidget* canvas = static_cast(m_activePage->webWidget()); + qreal w = documentSize().width() - canvas->size().width(); + qreal h = documentSize().height() - canvas->size().height(); + + qreal newX = m_scrollX + x; + qreal newY = m_scrollY + y; + newX = newX > 0 ? newX : 0; + newX = newX < w ? newX : w; + newY = newY > 0 ? newY : 0; + newY = newY < h ? newY : h; + m_scrollX = newX; + m_scrollY = newY; + if (m_generator) + documentViewportMoved(); + if (m_TnEngineView) + m_TnEngineView->update(); +} + +void TnEngineHandler::draggingStarted() +{ + m_dragging = true; +} + +void TnEngineHandler::draggingEnded() +{ + m_dragging = false; +} + +void TnEngineHandler::okInvoked() +{ + QPoint pos(0,0); + pos = m_activePage->mainFrame()->scrollPosition(); + + emit ok(m_scrollX - pos.x(), m_scrollY - pos.y()); +} + + +} +// End of File