How to Scale a WebView in OSX to Preview Content

While working on updates to NewsBee, I decided to tackle a thorny problem I pushed off in version 1.0: scaling a WebView in OSX.

For those of you who don’t know, NewsBee is a minimalist RSS reader that lives in your status bar and helps keep you clued into what’s happening without causing the usual distractions that plague most newsreaders (i.e. +1000 unread stories filling you with “RSS remorse”). One of the things NewsBee can do is show a little popover window to display the content of the RSS feed. It’s a fun feature and for sites with nice RSS entries, it’s a quick way to see what’s happening without getting too invested in the noise of the feed.

NewsBee can show mini previews of content.

This feature makes use of a NSPopover with a WebView embedded inside and it works pretty well. The problem is that I chose to make the popover a bit small to stay out of the way. However, if an image is too larger to fit within the constraints of the page, it’s likely to overflow beyond the visible page. Here’s an example using Apple’s home page.

You’ll notice that the rest of the iPad Mini is off the screen. This is exactly what will happen if you have a WebView in an OSX app and the content is larger than the visible area.

In iOS, this is no big deal since scaling is part of the UIWebView class (scalesPagesToFit:). In OSX, you have to roll your own as the WebView class does not support this method.

To solve this problem, I could add hack the HTML I’m putting into the WebView. I could add some CSS3 scaling or even do some fancy Javascript to resize the WebView based on the calculated size of the page. And as you might expect, I tried these options and ultimately decided to abandon them because they either:

a) Made the WebView too large
b) Scaled the page in a way that made the content look funny
c) Produced inconsistent results

So, I launched NewsBee 1.0 without scaling content and of course the first request I received from live users was the ability to resize the popovers. 🙂

How to Scale a WebView in OSX to Preview Content

As I noodled through the problem, a friend pointed out that Apple Mail has a preview button on all URLs. When you tap it, Mail shows you a snapshot of the page in a NSPopover. Here’s what that looks like:

After testing with a variety of links, I saw that Apple was getting flawless results on resizing content. Then it occurred to me that they were likely loading the content in an off screen WebView, taking a image representation of the view, and then scaling that according to the size of the NSPopover view. And guess, what? It works.

Here’s the process for setting up the off-screen WebView:

  1. Create a WebView about the size of a regular browser window (eg. 1000px x 1000px).
  2. Set the delegate so that you can handle didFinishLoadForFrame: when content is loaded.
  3. Load the content by calling loadRequest: on the mainFrame of the WebView or by passing HTML to the mainFrame by using loadHTMLString:.

WebView * placeHolder = [[WebView alloc] initWithFrame:NSMakeRect(0, 0, 1000, 1000)];
[placeHolder setFrameLoadDelegate:self];
// Assumes displayHTML is a NSString with valid HTML.
[placeHolder.mainFrame loadHTMLString:displayHTML baseURL:yourNSURL];

At this point, you just need to implement didFinishLoadForFrame: method of the WebFrameLoadDelegate class to capture and process the results.

Here’s the code for implementing the didFinishLoadForFrame: method of the WebFrameLoadDelegate class:

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
NSBitmapImageRep *imageRep = [sender
bitmapImageRepForCachingDisplayInRect:[sender frame]];
[sender cacheDisplayInRect:[sender frame] toBitmapImageRep:imageRep];
popoverBackground = [[NSImage alloc] initWithSize:[imageRep size]];
[popoverBackground addRepresentation: imageRep];

// imageView is a NSImageView I've hooked up in IB
[imageView setImage:popoverBackground];


In Interface Builder, my NSPopover xib as a Custom View with a single NSImageView inside. The NSImageView uses autosizing to stay aligned with the size of the Custom View. The Image Cell inside the NSImageView is also set to scale proportionally down.

As a result, NewsBee 1.1 will have much better popover previews. Users can select from multiple sizes and the full page will be displayed and scaled accordingly. The other side benefit is that doing all the loading in an offscreen WebView seems to speed things up quite a bit.