Cutting the Web Down to Size

    rich's picture
    2009
    20
    Oct

    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.