PDA

View Full Version : Drawing on top of a WebView




beon
Sep 25, 2008, 12:07 PM
I've been beating my head against this for almost a week, and've done a lot of searching - so if I've missed the obvious reference and this question is redundant, it's not that I didn't look. That said...

I want to be able to draw rectangles around specific content in a WebView. Say I have:
DOMNode * theNode = (some node in the DOMDocument of the current MainFrame);
NSRect nodeRect = [theNode boundingBox];
NSFrameRect(nodeRect);

That draws a correctly sized rectangle, but the placement is way off - for reasons I'm pretty sure I understand. Apparently, boundingBox gives me a point of origin relative to the WebFrameView object that was used to display the node. But when I call NSFrameRect, it draws from the application's origin. Or something.

So here's my question: how can I make the NSRect I get from boundingBox show up on top of the right place in the web view, and stay there?

I've looked through the Apple documentation on webviews, webframes, webframeviews, drawing in cocoa, coordinate systems, bezierpaths... all to no avail. I'd greatly appriciate any help yall can offer.

-Beon.



whooleytoo
Sep 25, 2008, 12:29 PM
Haven't used WebViews all that much, so I'm not sure.

Could it be as simple as you need to offset all rectangles by the origin of the WebFrameView?

HiRez
Sep 25, 2008, 01:15 PM
Have a look at the NSWindow methods

- (NSPoint)convertBaseToScreen:(NSPoint)aPoint
- (NSPoint)convertScreenToBase:(NSPoint)aPoint

Also, you could maybe intercept the web document rendering and draw directly into the web document using CSS or Javascript, that way your rectangle could stay locked to the content it's highlighting even if the user scrolls it.

beon
Sep 25, 2008, 01:40 PM
Could it be as simple as you need to offset all rectangles by the origin of the WebFrameView?

I do, but then I need to clip them at the edges of the WebView, which is doable but a bit of a pain. So let's try it. I'm gonna use - (NSRect)convertRect:(NSRect)aRect fromView:(NSView *)aView rather than - (NSPoint)convertScreenToBase:(NSPoint)aPoint

That makes sense, yeah? That way I won't have to move the origin around every time I want to draw inside a different WebFrameView (of which there are often several in a single WebView).

Will post progress.

I haven't ruled out using javascript functions - it'd be especially easy since I'm already dealing with DOMNode objects, but darnit I'm going somewhere with this - somewhere cocoa - and more JS feels like a giant step butt-wards. :apple:

kainjow
Sep 25, 2008, 02:04 PM
I'm not sure how reliable boundingBox is. Either way you may have to convert that like HiRez said, plus the Y coordinates may be flipped.

I don't think a WebView is doing anything too crazy with its subviews, unlike a QTMovieView. So you should be able to add a subview to the WebView, making sure it's on top (see addSubview:positioned:relativeTo: and NSWindowAbove).

But I'd say JavaScript might be your best bet. You could create a Canvas element and draw your circle inside that, and then position that Canvas into the webpage.

Edit: seems like WebKit's DOM handling lets you add child nodes, so that may work better instead of using JS since it's all in Cocoa/Obj-C.

beon
Sep 25, 2008, 10:37 PM
seems like WebKit's DOM handling lets you add child nodes, so that may work better instead of using JS since it's all in Cocoa/Obj-C.

Ya ya. Hm. How do you think they did Safari's "Find As You Type" results?

kainjow
Sep 26, 2008, 12:12 AM
Ya ya. Hm. How do you think they did Safari's "Find As You Type" results?

I'm not sure. That functionality is built-in to WebKit (WebView has a public method for performing the search), so you could see if it's part of the open-source WebKit and then take a look at the source code.

beon
Sep 26, 2008, 09:31 AM
Found this in WebDocumentPrivate.h:
@protocol WebDocumentSelection <WebDocumentText>
- (NSArray *)pasteboardTypesForSelection;
- (void)writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard;

// Array of rects that tightly enclose the selected text, in coordinates of selectinView.
- (NSArray *)selectionTextRects;

// Rect tightly enclosing the entire selected area, in coordinates of selectionView.
- (NSRect)selectionRect;

// NSImage of the portion of the selection that's in view. This does not draw backgrounds.
// The text is all black according to the parameter.
- (NSImage *)selectionImageForcingBlackText:(BOOL)forceBlackText;

// NSImage of the portion of the selection that's in view. This does not draw backgrounds.
// The text is all white according to the parameter.
// NOTE: This method is deprecated. It has been supplanted by selectionImageForcingBlackText:,
// and implementations typically just call that method, so its name no longer matches its
// behavior. It will be removed when doing so won't cause trouble for people using the latest
// WebKit with beta releases of Safari 3.0.
- (NSImage *)selectionImageForcingWhiteText:(BOOL)forceWhiteText;

// Rect tightly enclosing the entire selected area, in coordinates of selectionView.
// NOTE: This method is equivalent to selectionRect and shouldn't be used; use selectionRect instead.
- (NSRect)selectionImageRect;

// View that draws the selection and can be made first responder. Often this is self but it could be
// a nested view, as for example in the case of WebPDFView.
- (NSView *)selectionView;
@end
Now that I take a better look at it, this solution doesn't look so good. There's a view over the whole mainFrame, with images (and maybe masks?) onzeetop of it, and it goes away when you try to interact with the web page.

Seems like it might be easier to subclass WebFrameView. Maybe not. I have to do the stuff I'm getting paid to do for a bit now.