Skip to content

Cutting the Web Down to Size

Tuesday, 20 October 2009  |  rich

A feature that has been floating around in a few places but hasn't been a significant feature in KDE is web slicing. This is the ability to take a piece of a web page (commonly a div) and render it as a standalone object. It's useful for stuff like putting a weather forcast on your desktop, watching new comments on a forum etc. This weekend I made a start on implementing it as tool for Project Silk.

The first version I wrote was pretty simple - it lets you specify the element you want rendered, then presents it to the client application as a QPixmap. This was fairly easy thanks to the new QWebElement API, the core of the code is as simple as this:

QPixmap Slicer::renderElement( const QString &selector )
{
    QWebFrame *frame = d->page->mainFrame();
    d->page->setViewportSize( frame->contentsSize() );

    QWebElement element = frame->findFirstElement( selector );
    if ( element.isNull() )
	return QPixmap();

    QRect rect = element.geometry();
    QPixmap result = QPixmap( rect.size() );
    result.fill( Qt::white );

    QPainter painter( &result );
    painter.translate( -rect.x(), -rect.y() );
    frame->render( &painter, QRegion(rect) );

    return result;
}

This is enough to let you specify a CSS selector and render it to a pixmap thanks to the nice API of QWebElement. Doing the same using the DOM API would be simple enough, but a lot more verbose (and probably less flexible). The code above was enough for me to make it trivial to write tools that present a slice of a web page as part of their UI.

As ever in life, some people are never satisfied so a common response was to ask if I could make it so the slice is interactive. This is a bit of a can of worms as everyone has their own definition - eg. simply responding to requests from the page to repaint could be trivially added to the code above and would offer the same functionality as that I'm told MacOS offers. Rather than try the half-way solution, I wrote a prototype that actually gives you a fully interactive slice - eg. you can type into the form elements. It's not production quality, but it proves the point. You can see the result below:

Around the point I got this working, Kenneth let me know that a commit had just landed in QtWebkit that would make the earlier version even simpler - there's now a render() method on QWebElement that does exactly the same thing my original code did. This is great news, as that solution is the correct one for a lot of use-cases.

Of course, by this time, I was quite tired but Sebas was still feeling lively. The result is that 'live slice' code gained support for being embedded in QGraphicsView overnight using the new QGraphicsWebView. There's a support class that makes it available as a widget like before, but the implementation is using this (new in 4.6) class. All in all this means we can nicely integrate this functionality into apps using QGraphicsView like plasma or amarok, and into QWidget based apps too.

All in all, a successful couple of days in the stealthy advance of project silk.