Bug 206310

Summary: Add WKContentWorld SPI, and use it in JavaScript execution
Product: WebKit Reporter: Brady Eidson <beidson>
Component: WebKit APIAssignee: Brady Eidson <beidson>
Status: RESOLVED FIXED    
Severity: Normal CC: achristensen, berto, cgarcia, commit-queue, ews-watchlist, gustavo, tsavell, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Description Brady Eidson 2020-01-15 13:28:51 PST
Add WKContentWorld SPI, and use it in JavaScript execution
Comment 1 Brady Eidson 2020-01-15 13:39:51 PST
Created attachment 387837 [details]
Patch
Comment 2 Brady Eidson 2020-01-15 13:54:21 PST
Created attachment 387842 [details]
Patch
Comment 3 EWS Watchlist 2020-01-15 13:55:06 PST
Thanks for the patch. If this patch contains new public API please make sure it follows the guidelines for new WebKit2 GTK+ API. See http://trac.webkit.org/wiki/WebKitGTK/AddingNewWebKit2API
Comment 4 Brady Eidson 2020-01-15 14:08:39 PST
Created attachment 387843 [details]
Patch
Comment 5 Alex Christensen 2020-01-15 15:19:37 PST
Comment on attachment 387843 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=387843&action=review

> Source/WebKit/UIProcess/API/APIContentWorld.cpp:55
> +        world = new ContentWorld();

In general, a pattern of calling an empty constructor and then setting members is an anti-pattern.  Just add to the constructor parameters.

> Source/WebKit/UIProcess/API/APIContentWorld.cpp:56
> +        world->m_identifier = API::UserContentWorld::normalWorldIdentifer();

Is there really something special about this identifier, or could we use just another generated identifier?

> Source/WebKit/UIProcess/API/APIContentWorld.cpp:63
> +    static ContentWorld* world;

I think we might prefer something like NeverDestroyed<RefPtr<ContentWorld>> for some reason.

> Source/WebKit/UIProcess/API/APIContentWorld.cpp:67
> +        world->m_identifier = API::UserContentWorld::generateIdentifier();

It would probably be useful to give this world a name for future debugging help.  But then we wouldn't be able to use those names for other worlds, so maybe not.

> Source/WebKit/UIProcess/API/APIContentWorld.cpp:80
> +ContentWorld::ContentWorld()
> +{
> +}

I think = default is the cool new way to write this.

> Source/WebKit/UIProcess/API/APIContentWorld.h:50
> +    uint64_t m_identifier;

Strongly-typed identifiers are all the new hotness.
using ContentWorldIdentifier = ObjectIdentifier<ContentWorldType>

> Source/WebKit/UIProcess/API/APIUserContentWorld.h:49
> +    friend class ContentWorld;

Could we add the necessary public interface instead of befriending?

> Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm:910
> +    

whitespace.
Comment 6 Brady Eidson 2020-01-15 16:20:45 PST
(In reply to Alex Christensen from comment #5)
> Comment on attachment 387843 [details]
> Patch
> 
> > Source/WebKit/UIProcess/API/APIContentWorld.cpp:56
> > +        world->m_identifier = API::UserContentWorld::normalWorldIdentifer();
> 
> Is there really something special about this identifier, or could we use
> just another generated identifier?

Yes, there is something special about it.

> > Source/WebKit/UIProcess/API/APIContentWorld.cpp:63
> > +    static ContentWorld* world;
> 
> I think we might prefer something like NeverDestroyed<RefPtr<ContentWorld>>
> for some reason.
> 
> > Source/WebKit/UIProcess/API/APIContentWorld.cpp:67
> > +        world->m_identifier = API::UserContentWorld::generateIdentifier();
> 
> It would probably be useful to give this world a name for future debugging
> help.  But then we wouldn't be able to use those names for other worlds, so
> maybe not.

Right - These are explicitly name-free on purpose.

> 
> > Source/WebKit/UIProcess/API/APIContentWorld.cpp:80
> > +ContentWorld::ContentWorld()
> > +{
> > +}
> 
> I think = default is the cool new way to write this.
> 
> > Source/WebKit/UIProcess/API/APIContentWorld.h:50
> > +    uint64_t m_identifier;
> 
> Strongly-typed identifiers are all the new hotness.
> using ContentWorldIdentifier = ObjectIdentifier<ContentWorldType>

I dodged that on purpose because the other classes these interact with (InjectedBundleScriptWorld, etc) don't have them.

> 
> > Source/WebKit/UIProcess/API/APIUserContentWorld.h:49
> > +    friend class ContentWorld;
> 
> Could we add the necessary public interface instead of befriending?

Nah, generateIdentifier() should remain private to all who have no business touching it.
Comment 7 Brady Eidson 2020-01-15 16:29:02 PST
Created attachment 387864 [details]
Patch
Comment 8 Alex Christensen 2020-01-15 16:42:42 PST
Comment on attachment 387864 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=387864&action=review

r=me

> Source/WebKit/UIProcess/API/APIContentWorld.cpp:68
> +ContentWorld::ContentWorld(uint64_t identifier)

Could you add a FIXME here saying we should use ObjectIdentifier?

> Source/WebKit/UIProcess/API/APIUserContentWorld.h:49
> +    friend class ContentWorld;

I still don't think this is great.

> Source/WebKit/WebProcess/WebPage/WebPage.cpp:3385
> +        send(Messages::WebPageProxy::ScriptValueCallback({ }, ExceptionDetails { "Unable to execute JavaScript: Cannot find specified content world"_s }, callbackID));

Could you add a FIXME somewhere saying to use sendWithAsyncReply rather than two messages with a CallbackID?
Comment 9 Alex Christensen 2020-01-15 16:44:03 PST
Comment on attachment 387864 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=387864&action=review

> Source/WebKit/UIProcess/API/Cocoa/_WKContentWorld.mm:43
> +    return wrapper(API::ContentWorld::sharedWorldWithName(name));

Even though name is non-nullable, do you think it would be worth throwing if name is nil?  Should we add such a test that ignores compiler warnings and does a horrible thing?
Comment 10 Brady Eidson 2020-01-15 16:59:26 PST
(In reply to Alex Christensen from comment #9)
> Comment on attachment 387864 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=387864&action=review
> 
> > Source/WebKit/UIProcess/API/Cocoa/_WKContentWorld.mm:43
> > +    return wrapper(API::ContentWorld::sharedWorldWithName(name));
> 
> Even though name is non-nullable, do you think it would be worth throwing if
> name is nil?  Should we add such a test that ignores compiler warnings and
> does a horrible thing?

In our brave new world of playing nice with Swift, throwing is strongly frowned upon. I don't think it would pass muster.

In Obj-C land, you shoot yourself in the foot purposefully misbehaving with a non-nullable argument like that.

In Swift land the compiler doesn't even let you.
Comment 11 Brady Eidson 2020-01-15 17:02:20 PST
Created attachment 387871 [details]
Patch
Comment 12 WebKit Commit Bot 2020-01-15 21:41:08 PST
Comment on attachment 387871 [details]
Patch

Clearing flags on attachment: 387871

Committed r254668: <https://trac.webkit.org/changeset/254668>
Comment 13 WebKit Commit Bot 2020-01-15 21:41:10 PST
All reviewed patches have been landed.  Closing bug.
Comment 14 Radar WebKit Bug Importer 2020-01-15 21:42:12 PST
<rdar://problem/58633355>
Comment 15 Truitt Savell 2020-01-16 08:12:11 PST
It looks like the changes in https://trac.webkit.org/changeset/254668/webkit

broke 21 tests with an assert. Tracking in https://bugs.webkit.org/show_bug.cgi?id=206357
Comment 16 Brady Eidson 2020-01-16 09:00:49 PST
(In reply to Truitt Savell from comment #15)
> It looks like the changes in https://trac.webkit.org/changeset/254668/webkit
> 
> broke 21 tests with an assert. Tracking in
> https://bugs.webkit.org/show_bug.cgi?id=206357

Does Mac-debug only run WK1 debug?
Do we seriously not have a WK2-debug EWS bot?
Comment 17 Alex Christensen 2020-03-04 15:42:40 PST
Comment on attachment 387871 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=387871&action=review

> Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewEvaluateJavaScript.mm:199
> +        isDone = true;
> +    }];
> +    isDone = false;

These tests don't actually wait until isDone is set to true.  This test finishes in one runloop iteration without waiting for any results.  I'm fixing this in a patch I'm working on now.