OCT
20
2009

Cutting the Web Down to Size

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.