Safari browser plug-in only works under debugger...!


#1

Hi Jules,

Right, I’m really confused by this one.

The demo browser plug-in (and also my own plug-in…) only works properly under Safari, if I run it directly with the debugger.

NB: I’ve copied the file to the right folder (I know this as it works OK from Firefox!).

If I run-up Safari without using the debugger, and open the test page, the plug-in doesn’t display, but it does respond to scripting. So: that proves that the plug-in is there… but makes me think the display area isn’t initialised properly.

If I enable the DGB output in the release build, I get this in the log.txt file that you create… (this from loading the plug-in test page, then refreshing, then quitting…) (NB the sizes of 178 etc. are just the sizes I’m happening to use for the plug-in in this test…)

NP_Initialize
NP_GetEntryPoints
NPP_New
initialiseJuce_GUI()
BrowserPluginHolderComponent created
plugin window clip: 445 80 178 206
plugin window target: 445 80 178 206
plugin window intersection: 445 80 178 206
wx: 0 0 951 662   128 321 951 684
parent: 
plugin window clip: 445 80 178 206
plugin window target: 445 80 178 206
plugin window intersection: 445 80 178 206
wx: 206 -2147483648 0 178   0 0 0 -1
parent: 
plugin window clip: 445 96 178 206
plugin window target: 445 96 178 206
plugin window intersection: 445 96 178 206
wx: 0 0 0 0   0 0 0 0
parent: 
NPP_Destroy
BrowserPluginHolderComponent deleted
shutdownJuce_GUI()
NP_Shutdown

That second set of coordinates looks VERY weird!! Is there maybe an uninitialised memory thing going on?

There are also some console messages you can see that might give you a clue as to what is going wrong…! … which seem pretty interesting. :slight_smile:

Hoping you can help!

My first thought was that this because the plug-in isn’t signed … if I look inside the package contents for the pre-installed plug-ins, that they have Contents/_CodeSignature folders… !!!

So, I ran through the steps for self-signing the plug-in before copying it, which are in the “Code Signing Guide” in XCode… only to find that didn’t actually solve the problem. :slight_smile:

BTW, I found some interesting source code here: https://dev.mobileread.com/svn/webkitbrowser/trunk/WebKit-r30377/WebKit/mac/Carbon/CarbonWindowAdapter.m … and http://codenotifier.com/projects/218/commits/7107

@implementation CarbonWindowAdapter
117	111	
...	...	@@ -169,25 +163,15 @@
169	163	
170	164	// Find out the window's Carbon window attributes.
171		osStatus = GetWindowAttributes(inWindowRef, &windowAttributes);
172		if (osStatus!=noErr) NSLog(@"A Carbon window's attributes couldn't be gotten.");
	165	GetWindowAttributes(inWindowRef, &windowAttributes);
173	166	
174	167	// Find out the window's Carbon window features.
175		osStatus = GetWindowFeatures(inWindowRef, &windowFeatures);
176		if (osStatus!=noErr) NSLog(@"A Carbon window's features couldn't be gotten.");
	168	GetWindowFeatures(inWindowRef, &windowFeatures);

Best wishes,

Pete


#2

Very strange. Almost certainly it’s that weird-looking coordinate that’s buggering it up, but it’s just the window’s content view’s frame… I can’t see think how it could get garbled, unless the view isn’t valid for some reason.


#3

Hi Jules,

Yep, this is really, really strange. I presume it can’t be the code generation (as it works under the debugger). I guess it could be timing related (?) or maybe even permissions. Appears on the surface at least that the right APIs are seemingly getting called. Might be unitialized data that is delivered differently when run under the debugger…? Wondered if it might be a rounding error, going between float and int! :slight_smile:

Just in case somthing weird is going on with my setup… could you possibly build your demo plugin in release mode, copy to the Plug-ins folder… and verify:

  • Safari runs test.html OK using debugger!!
  • Safari fails to show plug-in window for test.html without debugger!

…? It would be good at least to know that it isn’t just my machine that has this problem. :slight_smile:

Pete


#4

Yes, I can reproduce it… Bit stuck for ideas on how to fix it though! Will play around with it and see what I can figure out…


#5

Jules, you are the man … your fast response is one of the many reasons I keep recommending Juce to all and sundry. :slight_smile:

My thought was to Google for some alternative implementations of that window size/positioning code, maybe the one in Juce isn’t quite right…?

Pete


#6

Hi Jules,

This seems to do things a little differently…?

http://developer.apple.com/mac/library/documentation/InternetWeb/Conceptual/WebKit_PluginProgTopic/Tasks/NetscapePlugins.html

I’m wondering if maybe the plug-in needs to specify a drawing model to use… (e.g. QuickDraw or CoreGraphics)…?

Some other bits that might be useful…?

http://groups.google.com/group/mozilla.dev.tech.plugins/browse_thread/thread/a726033404802006
http://www.sand-labs.org/aros/browser/trunk/WebKit/mac/Plugins/WebNetscapePluginView.mm?rev=1020&format=txt
http://discussions.apple.com/thread.jspa?threadID=1786090

Anways, just my 2 cents. HTH!

Pete


#7

I’m stumped. Had a quick look, and it seems that the initWithWindowRef: call only works the first time, but the window that it returns has garbage coordinates. Then subsequent calls fail to create the window at all and return a null pointer.

The CGContext also gives junk coords, though they’d be useless anyway, as you can’t actually find out what window or view they’re relative to…

I do set the drawing model correctly… and that’s it, really, I’m out of ideas…


#8

Wow. This really is the strangest thing I’ve seen for a long time.

When you run it in the debugger, the safari window is a BrowserWindow class, which contains lots of views with all the WebKit names, like you’d expect.

But when you run it normally, the window is a completely different type of object - an NSCarbonWindow, which only contains one strange sub-view.

Completely weird… Any ideas please!?


#9

Hi Jules,

Thanks for checking!

What really puzzles me, is how can there possibly be a difference when running under a debugger…?!

On a separate note, I see these in npapi.h …

#ifdef XP_MACOSX
  /* Used for negotiating drawing models */
  , NPNVpluginDrawingModel = 1000
#ifndef NP_NO_QUICKDRAW
  , NPNVsupportsQuickDrawBool = 2000
#endif
  , NPNVsupportsCoreGraphicsBool = 2001
#endif

… which makes me wonder if the plug-in has an obligation to announce what drawing mode it should be using?

It looks like this is the definitive article on this subject… Probably a red-herring, as of course it all works OK when run under debugger. :slight_smile:

https://wiki.mozilla.org/Mac:NPAPI_Drawing_Models

This is also very interesting…

http://src.chromium.org/viewvc/chrome/trunk/src/o3d/plugin/mac/main_mac.mm?revision=18600&pathrev=18600

NPError NPP_SetWindow(NPP instance, NPWindow* window) 
...
   switch (obj->drawing_model_) {
...
      case NPDrawingModelCoreGraphics: {
        // Safari 4 sets window->window to NULL when in Cocoa event mode.
        if (window->window != NULL) {
          NP_CGContext* np_cg = reinterpret_cast<NP_CGContext*>(window->window);
          if (obj->event_model_ == NPEventModelCocoa) {
            NSWindow * ns_window = reinterpret_cast<NSWindow*>(np_cg->window);
            new_window = reinterpret_cast<WindowRef>([ns_window windowRef]);
          } else {
            new_window = np_cg->window;
          }
          obj->mac_2d_context_ = np_cg->context;
        }
        break;
...

Bah humbug!

Pete


#10

If you look here…

http://svn.webkit.org/repository/webkit/branches/Safari-3-2-branch/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm

Look for this…

#ifndef NP_NO_QUICKDRAW

// The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers 
// the entire window frame (or structure region to use the Carbon term) rather then just the window content.
// We can remove this when <rdar://problem/4201099> is fixed.
- (void)fixWindowPort
{
    ASSERT(drawingModel == NPDrawingModelQuickDraw);
    
    NSWindow *currentWindow = [self currentWindow];
    if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")])
        return;

I wonder if because you’re not explicitly defining the drawing mode, it doesn’t always end-up in the drawing mode you expect…?

Just an idea, anyways!

Edit: this is a more recent version of the above file… http://svn.webkit.org/repository/webkit/branches/Safari-6528/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm

HTH

Pete


#11

Nice thinking - but I’ve just tried setting the model, and it doesn’t make any difference. This seems more fundamental than that anyway. I’ll keep looking, but any thoughts are appreciated!


#12

Bah!

Do you have safari 3 by any chance - was wondering if there is any difference in behaviour…?

Let me know if you want me to try anything out on my Mac…

Will keep searching in interim!

Pete


#13

BTW, have you tried setting the draw model to Quartz…?


#14

This is interesting…

http://developer.apple.com/mac/library/documentation/InternetWeb/Conceptual/WebKit_PluginProgTopic/Concepts/AboutPlugins.html

Surely we don’t need to use the WebKit framework for Safari on Mac…?

Pete


#15

Don’t think this is anything to do with the draw model.

You could rewrite it as a webkit plugin, but the fact is that this should work just fine - and we know that because it’s ok in the debugger.


#16

Interesting…

From Safari->Preferences, select the Advanced tab and check the Show Develop menu in menu bar option

Open the test page.

Select Develop -> Show Error Console
In the console that appears, you’ll be able to find that it is in two parts (by dragging the grabber etc. around, you can reveal them).
Select Elements, and you’ll be able to reveal the html source on the left side of the top one of the two bottom panels. As you click on each element, you’ll see the item it represents drawn as a rectangle in the top area (where the rendered webpage sits).

This shows the embed statement is represented by the area we’d expect; so webkit recognises the embed tag, and seemingly draws it (somehow or other!) with the right size and at the right position…!

If you look in the right side of the panel, you’ll see the various properties of the tag. e.g. HTMLEmbedElement … anyways, HTH!

Pete


#17

Also interesting…

Putting revised (very hacky!!) logging in the setWindow function shows some weird stuff happening (though you probably know this already!!)

void setWindow (NPWindow* window)
    {
        const ScopedAutoReleasePool pool;

        NSView* parentView = 0;
        WindowRef windowRef = 0;
        NP_CGContext *cg = NULL;
        CGRect boundingBox;

        char lTemp[500];

        log("------------------ setWindow ------------------");
        if (window != 0)
        {
            sprintf (lTemp, "window->window=%p", window->window); log(lTemp);
            sprintf (lTemp, "window->x=%d", (int)window->x); log(lTemp);
            sprintf (lTemp, "window->y=%d", (int)window->y); log(lTemp);
            sprintf (lTemp, "window->width=%d", window->width); log(lTemp);
            sprintf (lTemp, "window->height=%d", window->height); log(lTemp);
            sprintf (lTemp, "window->clipRect.top=%d", (int)window->clipRect.top); log(lTemp);
            sprintf (lTemp, "window->clipRect.left=%d", (int)window->clipRect.left); log(lTemp);
            sprintf (lTemp, "window->clipRect.bottom=%d", (int)window->clipRect.bottom); log(lTemp);
            sprintf (lTemp, "window->clipRect.right=%d", (int)window->clipRect.right); log(lTemp);

            cg = (NP_CGContext*)window->window;
            sprintf (lTemp, "cg=%p", cg); log(lTemp);
            if (cg != NULL)
            {
                sprintf (lTemp, "cg->context=%p", cg->context); log(lTemp);
                sprintf (lTemp, "cg->window=%p", cg->window); log(lTemp);

                windowRef = cg->window;

                sprintf (lTemp, "windowRef=%p\n", windowRef); log(lTemp);
              
                boundingBox = CGContextGetClipBoundingBox(cg->context); 
                sprintf (lTemp, "origin.x=%d y=%d, size.width=%d height=%d", (int)boundingBox.origin.x, (int) boundingBox.origin.y, (int) boundingBox.size.width, (int) boundingBox.size.height); log(lTemp);
            }
        }

BTW, the documentation for initWithWindowRef says “For historical reasons, contrary to normal memory management policy initWithWindowRef: does not retain windowRef. It is therefore recommended that you make sure you retain windowRef before calling this method. If windowRef is still valid when the Cocoa window is deallocated, the Cocoa window will release it.”

Putting that in seemed to make more sense in the output, but I’m too tired to investigate further today. :slight_smile:

Pete


#18

The autorelease call does retain the window, and then releases it at the end of the method - which is the intended behaviour, as it’s only needed temporarily… Adding an extra retain will cause a leak unless you keep a pointer somewhere and release it when the plugin exits, but it shouldn’t be needed (and obviously isn’t needed when the debugger’s running).

Hmm. It feels as if there are two different versions of the safari executable being loaded, one of which exposes its internal obj-C classes, and the other doesn’t… I wonder if it’s running 32-bit in the debugger and 64-bit normally?? Or can a UB contain both debug/release versions of the same exe?


#19

Hi Jules,

Ah - now then, that is a very interesting thought. Top thinking!

http://macosx.com/forums/mac-os-x-system-mac-software/310271-run-32-bit.html

Do you see that as well?

Also this…

http://www.icoretech.org/2009/08/block-ads-in-safari-64-bit-mode-on-snow-leopard/

Which implies that you can run Safari in either 32-bit or 64-bit mode…!

Hmmm! Is your Safari set-up to run in 64-bit or 32-bit mode? And if you flip modes, do our plug-ins now work…?

Do we actually need to build the plug-in as a UB with both 32-bit and 64-bit variants? And as an aside, I wonder if this might affect audio plug-ins moving forwards…?

Pete


#20

Now I know what to look for, it is getting clearer! :slight_smile:

http://lists.apple.com/archives/webkitsdk-dev/2009/Sep/msg00043.html

And following the thread…

And finally

HTH!

Pete