ginebra/chromewidget.cpp
branchGCC_SURGE
changeset 8 2e16851ffecd
parent 2 bf4420e9fa4d
parent 6 1c3b8676e58c
--- a/ginebra/chromewidget.cpp	Fri Jun 11 16:23:26 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,767 +0,0 @@
-/*
-* Copyright (c) 2010 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 <QtGui>
-#include <QNetworkReply>
-#include <QGraphicsScene>
-#include <QImage>
-#include <QTimeLine>
-#include <QPainterPath>
-#include "qwebpage.h"
-#include "qwebframe.h"
-#include "qwebview.h"
-#include "qwebelement.h"
-#include "chromewidget.h"
-#include "chromerenderer.h"
-#include "chromesnippet.h"
-#include "chromewidgetjsobject.h"
-#include "chromeview.h"
-#include "attentionanimator.h"
-#include "visibilityanimator.h"
-//NB: remove these
-#include "animations/fadeanimator.h"
-#include "animations/bounceanimator.h"
-#include "animations/flyoutanimator.h"
-
-#include "utilities.h"
-#include <assert.h>
-
-//Temporary include
-#include <QDebug>
-
-#ifdef G_TIMING
-#include "gtimer.h"
-#endif
-
-class UpdateBufferEvent : public QEvent {
-  public:
-    UpdateBufferEvent()
-      : QEvent(customType()) {
-    }
-    static QEvent::Type customType() {
-        static int type = QEvent::registerEventType();
-        return (QEvent::Type) type;
-    }
-};
-
-ChromeWidget::ChromeWidget(ChromeView *parentChromeView, QGraphicsItem *parent, const QString &jsName)
-  :QObject(),
-   m_chromePage(0),
-   m_parentItem(parent),
-   m_parentChromeView(parentChromeView),
-   m_state(maximized),
-   m_buffer(0),
-   m_painter(0),
-   m_dirtyTimer(0),
-   m_jsObject(new ChromeWidgetJSObject(this, this, jsName))
-{
-  // Connect signals generated by this object to signals on the javascript object.
-  safe_connect(this, SIGNAL(loadStarted()), m_jsObject, SIGNAL(loadStarted()));
-  safe_connect(this, SIGNAL(loadComplete()), m_jsObject, SIGNAL(loadComplete()));
-  safe_connect(this, SIGNAL(dragStarted()), m_jsObject, SIGNAL(dragStarted()));
-  safe_connect(this, SIGNAL(dragFinished()), m_jsObject, SIGNAL(dragFinished()));
-  safe_connect(this, SIGNAL(viewPortResize(QRect)), m_jsObject, SIGNAL(viewPortResize(QRect)));
-
-  //Allocate an instance of webkit to render the chrome
-  ChromeRenderer *pageView = new ChromeRenderer(parentChromeView->parentWidget());
-  safe_connect(pageView, SIGNAL(symbianCarriageReturn()), m_jsObject, SIGNAL(symbianCarriageReturn()));
-  //QWebView *pageView = new QWebView(parentChromeView->parentWidget());
-
-  pageView->show();
-  m_chromePage = pageView->page();
-
-  //Render to a transparent background (see WebKit bug 29414)
-  QPalette palette = m_chromePage->palette();
-  palette.setColor(QPalette::Base, Qt::transparent);
-  m_chromePage->setPalette(palette);
-
-  // No scrolling of the chrome
-  m_chromePage->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
-  m_chromePage->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
-
-  // Display the page view offscreen to ensure that it doesn't grab focus from chrome widget
-  pageView->setGeometry(-1600, 0, 5, 5);
-
-  // Connect QtWebPage signals
-  safe_connect(chromePage(), SIGNAL(frameCreated(QWebFrame*)), this, SLOT(frameCreated(QWebFrame*)));
-  safe_connect(chromePage(), SIGNAL(loadStarted()), this, SLOT(onLoadStarted()));
-  safe_connect(chromePage(), SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
-  safe_connect(chromePage(), SIGNAL(repaintRequested(QRect)), this, SLOT(repaintRequested(QRect)));
-
-  //External links in chrome are delegated to a content view so we
-  //propagate the QWebPage::linkClicked signal. The idea is that
-  //chrome does not normally load external content into the chrome
-  //itself (though chrome can still load content via XHR). Typically,
-  //the active  web view handles this signal. This allows chrome to contain
-  //links to external content that get loaded into the web view. An
-  //example would be a news feed that renders feed item titles in a chrome
-  //pop-up, but which loads the feed content into the main web view.
-
-  chromePage()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
-  QObject::connect(chromePage(), SIGNAL(linkClicked(const QUrl&)), this, SIGNAL(delegateLink(const QUrl&)));
-
-  installEventFilter(this);
-}
-
-ChromeWidget::~ChromeWidget(){
-  delete m_painter;
-  delete m_jsObject; 
-  delete m_buffer;
-}
-
-
-QObject *ChromeWidget::jsObject() { 
-  return static_cast<QObject *>(m_jsObject); 
-}
-
-#ifdef Q_OS_SYMBIAN
-QPixmap * ChromeWidget::buffer()
-#else
-QImage * ChromeWidget::buffer()
-#endif
-{
-  return m_buffer;
-}
-
-QPainter * ChromeWidget::painter(){
-  return m_painter;
-}
-
-void ChromeWidget::resizeBuffer(){
-  //qDebug() << "ChromeWidget::resizeBuffer: " << chromePage()->mainFrame()->contentsSize();
-  if(m_painter) {
-      m_painter->end();
-      delete m_painter;
-      m_painter = 0;
-  }
-  if(m_buffer) 
-      delete m_buffer;
-#ifdef Q_OS_SYMBIAN
-  m_buffer = new QPixmap(chromePage()->mainFrame()->contentsSize());
-#else
-  m_buffer = new QImage(chromePage()->mainFrame()->contentsSize(), QImage::Format_ARGB32_Premultiplied);
-#endif
-  m_buffer->fill(Qt::transparent);  
-  m_painter = new QPainter(m_buffer);
-}
-
-void ChromeWidget::setChromeUrl(QString url)
-{
-  //qDebug() << "ChromeWidget::setChromeUrl: " << url;
-  if(chromePage() && chromePage()->mainFrame()){
-#ifdef G_TIMING
-    GTimer * t = new GTimer();
-    t->start("ChromeWidget::setChromeUrl()");
-#endif
-    chromePage()->mainFrame()->load(QUrl(url));
-#ifdef G_TIMING
-   t->stop();
-   t->save();
-   delete t;
-#endif
-  }
-}
-
-void ChromeWidget::setGeometry(const QRect &rect)
-{
-  m_chromePage->setViewportSize(QSize(rect.size().width(), 1000));
-  resizeBuffer();
-  updateChildGeometries();
-}
-
-
-void ChromeWidget::toggleVisibility(const QString & elementId)
-{
-  ChromeSnippet * snippet = getSnippet(elementId);
-  if(snippet)
-    snippet->toggleVisibility();
-}
-
-void ChromeWidget::setLocation(const QString& id, int x, int y)
-{
-  ChromeSnippet * snippet = getSnippet(id);
-  if(snippet)
-    snippet->setPos(x,y);
-}
-
-void ChromeWidget::setAnchor(const QString& id, const QString& anchor){
-  ChromeSnippet * snippet = getSnippet(id);
-  if(snippet)
-    snippet->setAnchor(anchor);
-}
-
-void ChromeWidget::show(const QString & elementId, int x, int y)
-{
-  ChromeSnippet * snippet = getSnippet(elementId);
-
-  if(snippet){
-    snippet->setPos(x,y);
-    snippet->show(true);
-  }
-}
-
-void ChromeWidget::show(const QString & elementId)
-{
-  ChromeSnippet * snippet = getSnippet(elementId);
-
-  if(snippet){
-    //snippet->show(true);
-     snippet->show(false);
-  }
-}
-
-
-void ChromeWidget::hide(const QString & elementId)
-{
-  ChromeSnippet * snippet = getSnippet(elementId);
-  if(snippet)
-    snippet->hide(true);
-}
-
-void ChromeWidget::toggleAttention(const QString & elementId){
-  ChromeSnippet * snippet = getSnippet(elementId);
-  if(snippet) {
-    //qDebug() << "ChromeWidget::toggleAttention " << elementId; 
-    snippet->toggleAttention();
-  }
-}
-
-void ChromeWidget::setVisibilityAnimator(const QString& elementId, const QString & animatorName){
- ChromeSnippet * snippet = getSnippet(elementId);
-  if(snippet) {
-    VisibilityAnimator * animator = VisibilityAnimator::create(animatorName, snippet);
-    snippet->setVisibilityAnimator(animator); // NB: Move this to visibility animator implementation
-  }
-}
-
-void ChromeWidget::setAttentionAnimator(const QString& elementId, const QString & animatorName){
-ChromeSnippet * snippet = getSnippet(elementId);
-  if(snippet) {
-     AttentionAnimator * animator = AttentionAnimator::create(animatorName, snippet);
-    snippet->setAttentionAnimator(animator); // NB: Move this to visibility animator implementation
-  }
-}
-
-//NB: Factor out snippet cleanup and use in destructor too
-
-void ChromeWidget::onLoadStarted()  // slot
-{
-  qDebug() << "ChromeWidget::onLoadStarted";
-#ifdef G_TIMING
-  GTimer * t = new GTimer();
-  t->start("ChromeWidget::loadStarted");
-#endif
-  //First zero out all of the non-root snippets. These
-  //will be deleted when the root snippets are deleted.
-  QMapIterator<QString, ChromeSnippet*> i(m_snippetMap);
-  while(i.hasNext()){
-    i.next();
-    if(i.value()->parentItem() != m_parentItem){
-      m_snippetMap[i.key()] = 0;
-    }
-  }
-  //Now delete the root snippets.
-  foreach(ChromeSnippet *snippet, m_snippetMap){
-    if(snippet){
-      //Remove about-to-be-deleted snippet from parent scene
-      m_parentChromeView->getScene()->removeItem(snippet);
-      delete snippet;
-    }
-  }
-  m_snippetMap.clear();
-//  m_topSnippet = 0;
-//  m_bottomSnippet = 0;
-  //m_popSnippet = 0;
-  //Does anybody care about this signal?
-  emit loadStarted();
-#ifdef G_TIMING
-  t->stop();
-  t->save();
-  delete t;
-#endif
-}
-
-
-QString ChromeWidget::getDisplayMode() 
-{
-	return m_parentChromeView->getDisplayMode(); 
-	
-}
-	
-	
-void ChromeWidget::frameCreated(QWebFrame* frame){
-  Q_UNUSED(frame)
-  //qDebug() << "===>ChromeWidget::frameCreated";
-}
-
-void ChromeWidget::loadFinished(bool ok)  // slot
-{
-#ifdef G_TIMING
-  GTimer * t = new GTimer();
-  t->start("ChromeWidget::loadFinished");
-#endif
-  qDebug() << "ChromeWidget::loadFinished";
-  if(!ok)
-  {
-    qDebug() << "ChromeWidget::loadFinished: error";
-    return;
-  }
-  getInitialChrome();
-  resizeBuffer();
-  updateChildGeometries();
-  emit loadComplete();
-#ifdef G_TIMING
-  t->stop();
-  t->save();
-  delete t;
-#endif
-}
-
-void ChromeWidget::getInitialChrome(){
-  
-  QWebElement doc = chromePage()->mainFrame()->documentElement();
-#if QT_VERSION < 0x040600
-  QList <QWebElement> initialSnippets = doc.findAll(".GinebraSnippet");
-#else
-  QList <QWebElement> initialSnippets = doc.findAll(".GinebraSnippet").toList();
-#endif
-  foreach(QWebElement element, initialSnippets) {
-    ChromeSnippet* s = getSnippet(element.attribute("id"));
-    if((element.attribute("data-GinebraVisible","false"))=="true"){
-      s->show(false);
-    }
-    else {
-      s->hide();
-    }
-  }
-}
-
-ChromeSnippet *ChromeWidget::getSnippet(const QString &docElementId, QGraphicsItem *parent) {
- 
-  ChromeSnippet *result = m_snippetMap.value(docElementId);
-  if(!result){
-    QWebElement doc = chromePage()->mainFrame()->documentElement();
-    QWebElement element = doc.findFirst("#" + docElementId);
-    QRect rect = getDocElementRect(docElementId);
-    if(!rect.isNull()){
-      QGraphicsItem * p = (parent)?parent:m_parentItem;
-      
-      // Create the snippet, pass the ChromeWidget's javascript object in so that it can
-      // be used as the parent of the snippet's javascript object.
-      result = new ChromeSnippet(p, this, jsObject(), docElementId);
-      
-      // Make sure snippets are shown above the content view.
-      result->setZValue(3);
-      
-      //result->setAnchor("AnchorCenter");
-      //qDebug() << "Creating snippet: " << docElementId << ":" << (int) result;  
-      // Set up connections to freeze the main content page while snippets are being dragged
-      // to improve performance on complex pages.
-      safe_connect(result->getJSObject(), SIGNAL(dragStarted()), this, SIGNAL(dragStarted()));
-      safe_connect(result->getJSObject(), SIGNAL(dragFinished()), this, SIGNAL(dragFinished()));
-      //Note that the following can be inefficient if several snippets are
-      //made visible/invisible at once, which will result is successive
-      //updates to the viewport. Optimize this to coalesce updates.
-      safe_connect(result->getJSObject(), SIGNAL(onHide()), this, SLOT(updateViewPort()));
-      safe_connect(result->getJSObject(), SIGNAL(onShow()), this, SLOT(updateViewPort()));
-      //qDebug() << "Snippet child count: " << p->childItems().size() << " parent=" << ((QGraphicsWidget *)p)->objectName();
-      //qDebug() << "ChromeWidget::getSnippet: " << docElementId << " " << rect;
-
-      result->setOwnerArea(rect);
-      //Snippet size is determined by owner area.
-      result->resize(rect.size());
-      //Set auto-layout attributes
-      result->setAnchor(element.attribute("data-GinebraAnchor", "AnchorNone"));
-      result->setHidesContent( element.attribute("data-GinebraHidesContent", "false") == "true" );
-      result->setAnchorOffset( element.attribute("data-GinebraAnchorOffset", "0").toInt() ); //toInt() returns 0 for malformed string
-      m_snippetMap[docElementId] = result;
-      //NB: not very efficient
-      QList <QVariant> chromeButtons = getChildIdsByClassName(docElementId, "GinebraButtonSnippet").toList();
-      //qDebug() << "Chrome row size: " << chromeButtons.size();
-      for(int i = 0; i < chromeButtons.size();i++) {
-        qDebug() << "Chrome row button: " << chromeButtons[i].toString();
-        getSnippet(chromeButtons[i].toString(),result);
-      }
-  
-    }
-    else{
-      //qDebug() << "ChromeWidget::getSnippet: snippet not found, id=" << docElementId;
-      return 0;
-    }
-  }else{
-    //qDebug() << "Found existing snippet: " << docElementId;
-  }
-
-  return result;
-}
-
-/* Do a re-layout of the chrome. This gets snippet geometries, sets positions
- * and calculates the viewport size. This gets called when:
- * - New chrome is loaded
- * - The chrome is resized
- * This doesn't get called when chrome snippet visibility changes
- * or snippets get moved so that animations don't invoke multiple
- * relayouts. This means that visiblity changes need to explicitly
- * invoke a viewport size calculation if they want to resize the
- * viewport.
- */
-
-void ChromeWidget::updateChildGeometries()
-{
-  QRect viewRect(QPoint(0,0), m_parentChromeView->geometry().size());
-  //qDebug() << "ChromeWidget::updateChildGeometries: viewRect=" << viewRect;
-  //m_chromePage->setViewportSize(viewRect.size());
-
-  updateOwnerAreas();
-  
-  //NB: It would be more efficient to calculate the viewport as snippet geometry is set
-  //though this ought to be done without duplicating code between here and updateViewport()
-  
-  foreach(ChromeSnippet *snippet, m_snippetMap) {
-    qreal sHeight = snippet->ownerArea().height();
-    if(snippet->anchor()=="AnchorTop"){
-      snippet->setPos(0, snippet->anchorOffset());
-      snippet->resize(viewRect.width(), sHeight);
-    }
-    else if(snippet->anchor()=="AnchorBottom"){
-      //NB: Why do we need to subtract 2 from y coord here???
-      //snippet->setPos(0, viewRect.height() - sHeight - snippet->anchorOffset() -2);
-      snippet->setPos(0, viewRect.height() - sHeight - snippet->anchorOffset());
-      snippet->resize(viewRect.width(), sHeight);
-    }
-    else if(snippet->anchor()=="AnchorCenter"){
-      qreal sWidth = snippet->ownerArea().width();
-      snippet->setPos((viewRect.width()-sWidth)/2,(viewRect.height()-sHeight)/2);
-      snippet->resize(sWidth, sHeight);
-    }
-    else if(snippet->anchor()=="AnchorFullScreen"){
-      snippet->setRect(0,0,viewRect.width(), viewRect.height());
-    }
-    snippet->updateChildGeometries();
-    
-  }
-  
-  updateViewPort();
-
-  repaintRequested(viewRect); //Do intial repaint of the whole chrome after snippets are inited
-}
-
-//Updates the current viewport size to the area not covered by visible top and bottom chrome.
-
-void ChromeWidget::updateViewPort() {
-  QRect viewPort(QPoint(0,0), m_parentChromeView->geometry().size());
-  
-  //NB: Note that this algorithm assumes that anchor offsets do NOT
-  //shrink the viewport. I.e., if you have an offset snippet it is
-  //assumed either that it hides content (HidesContent attribute is set)
-  //or that it is being stacked on another anchored snippet. An offset snippet 
-  //that is not being stacked on another snippet and that does not have content hiding
-  //set (HidesContent attribute) will typically show on top of the content window
-  //with the content window reduced by the size of the snippet.
-  int viewPortY = 0;
-  foreach(ChromeSnippet *snippet, m_snippetMap) {
-    if(!snippet->hidesContent()){
-      if((snippet->anchor()=="AnchorTop") && snippet->isVisible() && !snippet->isHiding()){
-        int snippetY = snippet->pos().y() + snippet->ownerArea().height();
-        if  (snippetY > viewPortY) {
-            viewPortY = snippetY;
-        }
-      }
-      else if((snippet->anchor()=="AnchorBottom") && snippet->isVisible() && !snippet->isHiding()){
-        viewPort.adjust(0, 0, 0, (int)-snippet->ownerArea().height());
-      }
-    }
-  }
-  viewPort.adjust(0, viewPortY, 0, 0);
-  emit viewPortResize(viewPort);
-}
-
-//Explicitly reset the viewport to a specified rectangle
-
-void ChromeWidget::setViewPort(QRect viewPort){
-  emit viewPortResize(viewPort);
-}
-
-void ChromeWidget::networkRequestFinished(QNetworkReply *reply){  // slot
-  if(reply->error() != QNetworkReply::NoError) {
-    //qDebug() << "ChromeWidget::networkRequestFinished: " << reply->errorString();
-  }
-}
-
-// Called when some part of the chrome page needs repainting.  Uses a custom event to delay calling mainFrame->render()
-// since in some cases render() can crash -- apparently when it tries to paint an element that has
-// been deleted (by javascript etc.).  Coalesces multiple calls to repaintRequested() into one call to
-// paintDirtyRegion().
-void ChromeWidget::repaintRequested(QRect dirtyRect){  // slot
-  //qDebug() << "ChromeWidget::repaintRequested: " << dirtyRect;
-
-#ifdef G_TIMING
- GTimer * t = new GTimer();
- t->start("ChromeWidget::repaintRequested");
-#endif
-
-#ifdef Q_OS_SYMBIANXX // turn off the hack for now, remove eventually
-  // Hack to get around painting issue in text fields.  Backspacing doesn't appear to generate
-  // repaint requests though the blinking caret does.  Since the caret is very narrow this leaves 
-  // behind artifacts of the character that was deleted.
-  dirtyRect.setRight(dirtyRect.right() + 20);
-  
-  //NB:Delayed repaints don't get invoked on NSP, at least on emulator
-  //so paint immediately. Note that delayed repaints are a work-around
-  //for JS/DOM issues in WebKit, so this needs to be revisited.
-  m_dirtyRegion = dirtyRect;
-  paintDirtyRegion();
-#else
-  if(m_dirtyRegion.isEmpty()) {
-      m_dirtyRegion += dirtyRect;
-      QCoreApplication::postEvent(this, new UpdateBufferEvent);
-  }
-  else
-      m_dirtyRegion += dirtyRect;
-#endif
-#ifdef G_TIMING
-  t->stop();
-  t->save();
-  delete t;
-#endif
-}
-
-void ChromeWidget::paintDirtyRegion() {
-  //qDebug() << "ChromeWidget::paintDirtyRegion" << m_dirtyRegion;
-  
-  if(m_dirtyRegion.isEmpty())
-      return;
-  if(m_buffer){
-    m_painter->save(); //NB: would it be more efficient just to create a new painter on the stack?
-    //Must set clip rect because frame may render background(?) outside dirty rect
-    m_painter->setClipRegion(m_dirtyRegion);
-    if(chromePage() && chromePage()->mainFrame())
-        chromePage()->mainFrame()->render(m_painter, m_dirtyRegion);
-    m_painter->restore();
-  }
-
-  foreach(ChromeSnippet *snippet, m_snippetMap) {
-    if((snippet->parentItem() == m_parentItem) && snippet->isVisible() && m_dirtyRegion.intersects(snippet->ownerArea().toRect())) {
-      //  qDebug() << "Dirty rect intersects: " << snippet->docElementId() << ": " << snippet->ownerArea().toRect();
-      snippet->update();
-    }
-  }
-
-  // Clear dirty region.
-  m_dirtyRegion = QRegion();
-}
-
-
-// Update owner areas of all snippets to allow for changes in chrome page geometry.
-void ChromeWidget::updateOwnerAreas() {
-  foreach(ChromeSnippet *snippet, m_snippetMap) {
-    snippet->setOwnerArea(getDocElementRect(snippet->docElementId()));
-  }
-}
-
-//NB: The following methods should also be implementable, and possibly
-//more efficient, via the C++ DOM API
-
-void ChromeWidget::debugAlert(const QString &msg){
-  chromePage()->mainFrame()->evaluateJavaScript("alert('" + msg + "')");
-}
-
-QVariant ChromeWidget::getDocElement(const QString &id) {
-  return chromePage()->mainFrame()->evaluateJavaScript("document.getElementById('" + id + "')");
-}
-
-QVariant ChromeWidget::getDocIdsByName(const QString &name){
-
-  QString js (
-	      "var elements = document.getElementsByName('" + name + "');"
-              "var result = new Array();"
-              "for(i = 0 ; i< elements.length; i++){"
-              " result[i]=elements[i].id;"
-              "}"
-              "result;"
-	     );
-  return chromePage()->mainFrame()->evaluateJavaScript(js);
-}
-
-QVariant ChromeWidget::getDocIdsByClassName(const QString &name){
-
-  QString js (
-              "var elements = document.getElementsByClassName('" + name + "');"
-              "var result = new Array();"
-              "for(i = 0 ; i< elements.length; i++){"
-              " result[i]=elements[i].id;"
-              "}"
-              "result;"
-             );
-  return chromePage()->mainFrame()->evaluateJavaScript(js);
-}
-
-QVariant ChromeWidget::getChildIdsByClassName(const QString &parentId, const QString &name){
-
-  QString js (
-	      "var elements = document.getElementsByClassName('" + name + "');"
-              "var result = new Array();"
-              "for(i = 0 ; i< elements.length; i++){"
-              "if(elements[i].parentNode.id == '" + parentId +"'){"
-              " result[i]=elements[i].id;"
-              "}"
-              "}"
-              "result;"
-	     );
-  return chromePage()->mainFrame()->evaluateJavaScript(js);
-
-}
-
-QSize ChromeWidget::getDocElementSize(const QString &id) {
-  QSize result;
-  QVariant jObj = getDocElement(id);
-  if(jObj.isValid()) {
-      QMap<QString, QVariant> jMap = jObj.toMap();
-      //qDebug() << "Tagname: " << (jMap["tagName"].toString());
-      result.setWidth(jMap["clientWidth"].toInt());
-      result.setHeight(jMap["clientHeight"].toInt());
-  }
-  else {
-    qDebug() << "ChromeWidget::getDocElementSize: element not found. " << id;
-  }
-  return result;
-}
-
-QString ChromeWidget::getDocElementAttribute(const QString &id, const QString &attribute) {
-  QString result;
-  QVariant jObj = getDocElement(id);
-  if(jObj.isValid()) {
-      QMap<QString, QVariant> jMap = jObj.toMap();
-      //qDebug() << "Tagname: " << (jMap["tagName"].toString());
-      result = jMap[attribute].toString();
-  }
-  else {
-    qDebug() << "ChromeWidget::getDocElementSize: element not found. " << id;
-  }
-  return result;
-}
-
-QRect ChromeWidget::getDocElementRect(const QString &id) {
-  QString js("var obj = document.getElementById('" + id + "');"
-             "var width = obj.clientWidth;"
-             "var height = obj.clientHeight;"
-             "var curleft = curtop = 0;"
-             "do {"
-             "  curleft += obj.offsetLeft;"
-             "  curtop += obj.offsetTop;"
-             "} while (obj = obj.offsetParent);"
-             "[curleft, curtop, width, height]");
-  QVariant jObj = chromePage()->mainFrame()->evaluateJavaScript(js);
-  if(jObj.isValid()) {
-    return QRect(jObj.toList()[0].toInt(), jObj.toList()[1].toInt(), jObj.toList()[2].toInt(), jObj.toList()[3].toInt());
-  }
-  else {
-    qDebug() << "ChromeWidget::getDocElementRect: element not found. " << id;
-    return QRect();
-  }
-}
-
-// Private.  This class shadows the Qt class QComboBoxPrivateContainer to provide access its
-// the 'combo' pointer in eventFilter().
-class xQComboBoxPrivateContainer : public QFrame
-{
-  public:
-    int spacing() const;
-    QTimer blockMouseReleaseTimer;
-    QBasicTimer adjustSizeTimer;
-    QPoint initialClickPosition;
-    QComboBox *combo;
-    QAbstractItemView *view;
-    void *top;
-    void *bottom;
-};
-
-bool ChromeWidget::eventFilter(QObject *object, QEvent *event)
-{
-    // Shameless hack here.  We need to intercept the creation of combobox drop-downs
-    // in the chrome and move them into their correct positions since the system thinks they belong
-    // off-screen over where the chrome page is actually rendered.  Since drop-downs are grandchildren
-    // of the ChromeRenderer we start by watching for child added events, when one is created we
-    // watch it also for child added events too, thereby watching grandchild events.  When we
-    // see a QComboBoxPrivateContainer (the drop-down list) being moved we move it instead into
-    // position just under the combobox.
-
-    //qDebug() << "ChromeWidget::eventFilter: " << event->type();
-
-    switch ((int)event->type()) {
-      case QEvent::ChildAdded:
-      case QEvent::ChildPolished:
-      {
-        QChildEvent *childEvt = static_cast<QChildEvent *>(event);
-        //qDebug() << "    watching " << childEvt->child();
-        childEvt->child()->installEventFilter(this);
-        break;
-      }
-      case QEvent::Move:
-      {
-        //QMoveEvent *evt = static_cast<QMoveEvent *>(event);
-        //qDebug() << "    oldpos " << evt->oldPos() << " pos " << evt->pos();
-        if(object->inherits("QComboBoxPrivateContainer")) {
-            xQComboBoxPrivateContainer *cbpc = static_cast<xQComboBoxPrivateContainer *>(object);
-            QComboBox *combo = cbpc->combo;
-            QRect comboRect = combo->geometry();
-            QPoint comboPos = comboRect.topLeft();
-            ChromeSnippet *snippet = getSnippet(comboPos);
-            if(snippet) {
-                QPoint relativePos = comboPos - snippet->ownerArea().topLeft().toPoint();
-                static_cast<QWidget *>(object)->move(m_parentChromeView->mapToGlobal(QPoint(0,0))
-                                                     + snippet->rect().topLeft().toPoint()
-                                                     + relativePos
-                                                     + QPoint(0, comboRect.height()));
-            }
-        }
-        break;
-      }
-      default:
-      {
-        if(event->type() == UpdateBufferEvent::customType()) {
-            if(object == this) {
-                //qDebug() << "ChromeWidget::eventFilter: UpdateBufferEvent " << (void*)object << event;
-                paintDirtyRegion();
-            }
-        }
-        break;
-      }
-    }
-
-    return QObject::eventFilter(object, event);
-}
-
-ChromeSnippet *ChromeWidget::getSnippet(QPoint pos) const {
-    foreach(ChromeSnippet *snippet, m_snippetMap) {
-        if(snippet->ownerArea().contains(pos))
-            return snippet;
-    }
-    return 0;
-}
-
-void ChromeWidget::dump() {
-    qDebug() << "ChromeWidget::dump";
-    foreach(ChromeSnippet *snippet, m_snippetMap) {
-        snippet->dump();
-        qDebug() << "------";
-    }
-}