Tab History

The last few days I’ve been describing how Odysseus’s combined titlebar/toolbar/menubar works, so now I’ll start looking into how WebKit responds to the actions it exposes.

Most dominantly there’s the back/forward buttons, which (possibly alongside stop/reload) I’ll describe this morning.

When you call WebKit.WebView.go_back() or .go_forward(), which in turn wraps the same API I use to provide a menu of all “BackForwardItem”s in the “BackForwardList”.

The sandbox tells the embedder when to add an entry to it’s BackForwardList. The currentIndex into this array meanwhile is tracked in the embedding process.

Once a BackForwardItem is selected, it initializes the sandboxed if needed and ensurse the item is in the right list before handing off to the sandbox.

The message is forwarded directly to a WebCore HistoryController object via a WebCore Page. Which will then traverse the frame tree, forwarding the message to all of them.

If it was a navigation within the document it’ll save the current state to the tab history, emulates the load changed events, and then restores the new state.

Or if it was a navigation to a different document it’ll restore the cached “DocumentLoader”, before falling back to a full reload.

To be clear, what this accomplishes is it caches the DOM tree for each page you visited in memory. That is history navigation is not treated as a normal load.

Which is very nice because it’s now performant enough to provide good affordances for a “swipe to navigate tab history” gesture, and because (unless overriden by JavaScript) I don’t loose anything I’ve done on those pages.

Though the catch is that the unload event now mostly serves to defeat this optimization.


The reload button is forwarded through the GTK embedding widget, WebPageProxy to send the message into the sandbox, to be received by the WebPage object, through WebCore’s UserInputBridge, and to the FrameLoader. Which’ll construct a new loading event without triggering most of the events before continuing the (re)load as per normal. A flag determines whether the cache may be used.

And the “stop loading” button follows the same path, and forwards the message to all associated requests.