Bug 180770

Summary: Web Inspector: replace HTMLCanvasElement with CanvasRenderingContext for instrumentation logic
Product: WebKit Reporter: Devin Rousso <hi>
Component: Web InspectorAssignee: Devin Rousso <hi>
Status: RESOLVED FIXED    
Severity: Normal CC: cdumez, commit-queue, dbates, dino, esprehn+autocc, ews-watchlist, glenn, graouts, gyuyoung.kim, inspector-bugzilla-changes, joepeck, kangil.han, keith_miller, kondapallykalyan, mark.lam, msaboff, rniwa, ryanhaddad, saam, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: All   
OS: All   
See Also: https://bugs.webkit.org/show_bug.cgi?id=180877
Bug Depends on: 172623, 180736    
Bug Blocks: 180833    
Attachments:
Description Flags
[Patch] WIP
none
Archive of layout-test-results from ews103 for mac-elcapitan
none
Archive of layout-test-results from ews107 for mac-elcapitan-wk2
none
Archive of layout-test-results from ews122 for ios-simulator-wk2
none
Archive of layout-test-results from ews116 for mac-elcapitan
none
[Patch] WIP
none
Archive of layout-test-results from ews103 for mac-elcapitan
none
Archive of layout-test-results from ews104 for mac-elcapitan-wk2
none
Archive of layout-test-results from ews125 for ios-simulator-wk2
none
Patch
none
Archive of layout-test-results from ews122 for ios-simulator-wk2
none
Archive of layout-test-results from ews100 for mac-elcapitan
none
Patch
none
Archive of layout-test-results from ews100 for mac-elcapitan
none
Archive of layout-test-results from ews113 for mac-elcapitan
none
Patch
none
Archive of layout-test-results from ews100 for mac-elcapitan
none
Archive of layout-test-results from ews106 for mac-elcapitan-wk2
none
Archive of layout-test-results from ews122 for ios-simulator-wk2
none
Archive of layout-test-results from ews114 for mac-elcapitan
none
Patch
none
Patch
none
Patch
none
Patch
none
Archive of layout-test-results from ews102 for mac-elcapitan
none
Archive of layout-test-results from ews106 for mac-elcapitan-wk2
none
Archive of layout-test-results from ews112 for mac-elcapitan
none
Archive of layout-test-results from ews125 for ios-simulator-wk2
none
Patch
none
Archive of layout-test-results from ews116 for mac-elcapitan
none
Archive of layout-test-results from ews100 for mac-elcapitan
none
Archive of layout-test-results from ews105 for mac-elcapitan-wk2
none
Patch
none
Archive of layout-test-results from ews103 for mac-elcapitan
none
Patch
none
Archive of layout-test-results from ews116 for mac-elcapitan
none
Patch
none
Archive of layout-test-results from ews117 for mac-elcapitan
none
Patch
none
Patch
none
Patch
none
Archive of layout-test-results from ews105 for mac-elcapitan-wk2
none
Patch
none
Patch
none
Patch none

Description Devin Rousso 2017-12-13 15:14:02 PST
Since everything we do with canvases really only cares about the CanvasRenderingContext (except for the DOM Node), we should really be tracking those instead of instances of HTMLCanvasElement.  

This should also make it smoother to provide support for OffscreenCanvas once it's complete.
Comment 1 Devin Rousso 2017-12-13 15:16:24 PST
Created attachment 329265 [details]
[Patch] WIP
Comment 2 Joseph Pecoraro 2017-12-13 15:59:35 PST
Comment on attachment 329265 [details]
[Patch] WIP

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

> Source/JavaScriptCore/inspector/protocol/Canvas.json:-49
> -                { "name": "frameId", "$ref": "Network.FrameId", "description": "Parent frame identifier." },

If the frontend wants to associate the Canvas with a Frame it would need to use resolve this to a DOMNode and then get the node's frame? That seems okay.

> Source/WebCore/inspector/InspectorCanvas.cpp:95
> +HTMLCanvasElement* InspectorCanvas::getIfHTMLCanvasElement()

This is a clunky name. How about:

    HTMLCanvasElement* canvasElement() const;

It seems clear this would return a nullptr if this is not an HTMLCanvasElement.
Comment 3 Devin Rousso 2017-12-13 16:09:16 PST
Comment on attachment 329265 [details]
[Patch] WIP

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

>> Source/JavaScriptCore/inspector/protocol/Canvas.json:-49
>> -                { "name": "frameId", "$ref": "Network.FrameId", "description": "Parent frame identifier." },
> 
> If the frontend wants to associate the Canvas with a Frame it would need to use resolve this to a DOMNode and then get the node's frame? That seems okay.

Yeah.  I was trying to think about it, but when would we want to do that?  I figure that it might be better for us to provide data relating to what context/target (document vs worker) we are dealing with, but that would be for a followup (and once worker support is done).

>> Source/WebCore/inspector/InspectorCanvas.cpp:95
>> +HTMLCanvasElement* InspectorCanvas::getIfHTMLCanvasElement()
> 
> This is a clunky name. How about:
> 
>     HTMLCanvasElement* canvasElement() const;
> 
> It seems clear this would return a nullptr if this is not an HTMLCanvasElement.

I personally don't like that naming convention, as just having an HTMLCanvasElement* doesn't mean that it might be a nullptr.  Also, it would make naming a bit more annoying at a few of the call-sites (e.g. InspectorCanvas::buildObjectForCanvas) where there is already a `canvas` or `element` variable, especially since I can't reuse `canvasElement`.  If you have a better name that avoids this, I'd be happy to change it.
Comment 4 EWS Watchlist 2017-12-13 16:22:39 PST Comment hidden (obsolete)
Comment 5 EWS Watchlist 2017-12-13 16:22:41 PST Comment hidden (obsolete)
Comment 6 Joseph Pecoraro 2017-12-13 16:22:50 PST
Comment on attachment 329265 [details]
[Patch] WIP

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

>>> Source/JavaScriptCore/inspector/protocol/Canvas.json:-49
>>> -                { "name": "frameId", "$ref": "Network.FrameId", "description": "Parent frame identifier." },
>> 
>> If the frontend wants to associate the Canvas with a Frame it would need to use resolve this to a DOMNode and then get the node's frame? That seems okay.
> 
> Yeah.  I was trying to think about it, but when would we want to do that?  I figure that it might be better for us to provide data relating to what context/target (document vs worker) we are dealing with, but that would be for a followup (and once worker support is done).

I'd guess that an OffscreenCanvas created by a Worker would be exposed through the Worker's InspectorController (all happening on the Worker's Thread).

In which case we'd:
• Enable the Canvas domain for Workers
• Give WI.Canvas a `target` property and populate it.

At which point we'd be able to know from `canvas.target` if it was in a Page / Worker.
Comment 7 EWS Watchlist 2017-12-13 16:30:36 PST Comment hidden (obsolete)
Comment 8 EWS Watchlist 2017-12-13 16:30:37 PST Comment hidden (obsolete)
Comment 9 EWS Watchlist 2017-12-13 16:48:01 PST Comment hidden (obsolete)
Comment 10 EWS Watchlist 2017-12-13 16:48:03 PST Comment hidden (obsolete)
Comment 11 EWS Watchlist 2017-12-13 17:35:54 PST Comment hidden (obsolete)
Comment 12 EWS Watchlist 2017-12-13 17:35:56 PST Comment hidden (obsolete)
Comment 13 Devin Rousso 2017-12-13 18:40:15 PST
Created attachment 329306 [details]
[Patch] WIP

Rebase
Comment 14 EWS Watchlist 2017-12-13 20:09:51 PST Comment hidden (obsolete)
Comment 15 EWS Watchlist 2017-12-13 20:09:53 PST Comment hidden (obsolete)
Comment 16 EWS Watchlist 2017-12-13 20:38:25 PST Comment hidden (obsolete)
Comment 17 EWS Watchlist 2017-12-13 20:38:27 PST Comment hidden (obsolete)
Comment 18 EWS Watchlist 2017-12-13 20:51:16 PST Comment hidden (obsolete)
Comment 19 EWS Watchlist 2017-12-13 20:51:18 PST Comment hidden (obsolete)
Comment 20 Devin Rousso 2017-12-13 21:01:38 PST
Created attachment 329324 [details]
Patch
Comment 21 EWS Watchlist 2017-12-13 22:32:33 PST Comment hidden (obsolete)
Comment 22 EWS Watchlist 2017-12-13 22:32:35 PST Comment hidden (obsolete)
Comment 23 EWS Watchlist 2017-12-13 22:35:22 PST Comment hidden (obsolete)
Comment 24 EWS Watchlist 2017-12-13 22:35:24 PST Comment hidden (obsolete)
Comment 25 Devin Rousso 2017-12-13 22:59:26 PST
Created attachment 329328 [details]
Patch

I think some of the test failures were due to the fact that the CanvasRenderingContext would be destroyed before the frame navigation event is fired, but I could be wrong
Comment 26 EWS Watchlist 2017-12-14 00:05:44 PST Comment hidden (obsolete)
Comment 27 EWS Watchlist 2017-12-14 00:05:46 PST Comment hidden (obsolete)
Comment 28 EWS Watchlist 2017-12-14 00:44:03 PST Comment hidden (obsolete)
Comment 29 EWS Watchlist 2017-12-14 00:44:05 PST Comment hidden (obsolete)
Comment 30 Devin Rousso 2017-12-14 01:08:56 PST
Created attachment 329336 [details]
Patch

Based on the mac-debug results, I think we do need a timer when destroying contexts to prevent JS allocations.
Comment 31 EWS Watchlist 2017-12-14 02:14:46 PST Comment hidden (obsolete)
Comment 32 EWS Watchlist 2017-12-14 02:14:48 PST Comment hidden (obsolete)
Comment 33 EWS Watchlist 2017-12-14 02:26:13 PST Comment hidden (obsolete)
Comment 34 EWS Watchlist 2017-12-14 02:26:14 PST Comment hidden (obsolete)
Comment 35 EWS Watchlist 2017-12-14 02:40:30 PST Comment hidden (obsolete)
Comment 36 EWS Watchlist 2017-12-14 02:40:31 PST Comment hidden (obsolete)
Comment 37 EWS Watchlist 2017-12-14 02:49:44 PST Comment hidden (obsolete)
Comment 38 EWS Watchlist 2017-12-14 02:49:46 PST Comment hidden (obsolete)
Comment 39 Devin Rousso 2017-12-14 08:05:30 PST
Created attachment 329353 [details]
Patch

Oops.  I added back the logic inside frameNavigated.
Comment 40 Joseph Pecoraro 2017-12-14 11:44:38 PST
Comment on attachment 329353 [details]
Patch

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

r=me

> Source/WebCore/inspector/InspectorCanvas.cpp:96
> +HTMLCanvasElement* InspectorCanvas::getIfHTMLCanvasElement()

I still don't like this name. We normally don't include `get` in a getter name either.

> Source/WebCore/inspector/InspectorCanvas.cpp:313
> +    auto* canvasElement = getIfHTMLCanvasElement();

Should we have a FIXME here for OffscreenCanvas?

> Source/WebCore/inspector/InspectorCanvas.h:49
> +class OffscreenCanvas;

Not used?

> Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp:153
> +        errorString = ASCIILiteral("OffscreenCanvas is currently not supported.");

OffscreenCanvas won't have a node. So probably a better error might be something like:

    errorString = ASCIILiteral("No node for this canvas");
    errorString = ASCIILiteral("No node for OffscreenCanvas");

Also I know we aren't consistent, but I don't think we have periods with these errors most of the time.

> Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp:215
> +    auto* canvasElement = inspectorCanvas->getIfHTMLCanvasElement();
> +    if (!canvasElement) {
> +        errorString = ASCIILiteral("OffscreenCanvas is currently not supported.");
> +        return;
> +    }

Would it be possible for an OffscreenCanvas to have client nodes? If not we should update this error messages.

> Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp:-380
> -    Vector<InspectorCanvas*> inspectorCanvases;
> -    for (auto& inspectorCanvas : m_identifierToInspectorCanvas.values()) {
> -        if (inspectorCanvas->canvas().document().frame() == &frame)
> -            inspectorCanvases.append(inspectorCanvas.get());
> -    }
> -
> -    for (auto* inspectorCanvas : inspectorCanvases) {
> -        String identifier = unbindCanvas(*inspectorCanvas);
> -        if (m_enabled)
> -            m_frontendDispatcher->canvasRemoved(identifier);
> -    }

Hmm. So this relies on the GC to eliminate canvases in subframes instead of immediately eliminating them when the frame goes away? I suppose this is fine but if I have a long running top frame and short lived sub-frames it might be annoying if the frontend updates out of sync with the frames coming and going.
Comment 41 Devin Rousso 2017-12-14 13:48:14 PST
Created attachment 329395 [details]
Patch
Comment 42 Devin Rousso 2017-12-14 13:54:07 PST
Created attachment 329399 [details]
Patch
Comment 43 WebKit Commit Bot 2017-12-14 16:02:22 PST
Comment on attachment 329399 [details]
Patch

Clearing flags on attachment: 329399

Committed r225941: <https://trac.webkit.org/changeset/225941>
Comment 44 WebKit Commit Bot 2017-12-14 16:02:25 PST
All reviewed patches have been landed.  Closing bug.
Comment 45 Radar WebKit Bug Importer 2017-12-14 16:04:26 PST
<rdar://problem/36061461>
Comment 46 Ryan Haddad 2017-12-15 15:48:52 PST
webgl/1.0.2/conformance/context/context-release-with-workers.html is failing an assertion after this change:
https://build.webkit.org/results/Apple%20El%20Capitan%20Debug%20WK1%20(Tests)/r225980%20(5403)/results.html

SHOULD NEVER BE REACHED
/Volumes/Data/slave/elcapitan-debug/build/Source/WebCore/inspector/agents/InspectorCanvasAgent.cpp(397) : void WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext(WebCore::CanvasRenderingContext &)
1   0x10be08dfd WTFCrash
2   0x116183bc5 WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext(WebCore::CanvasRenderingContext&)
3   0x116131395 WebCore::InspectorInstrumentation::didCreateCanvasRenderingContextImpl(WebCore::InstrumentingAgents&, WebCore::CanvasRenderingContext&)
4   0x116033bc1 WebCore::InspectorInstrumentation::didCreateCanvasRenderingContext(WebCore::CanvasRenderingContext&)
5   0x11723021e WebCore::WebGLRenderingContext::create(WebCore::CanvasBase&, WTF::Ref<WebCore::GraphicsContext3D>&&, WebCore::GraphicsContext3DAttributes)
6   0x1172400ef WebCore::WebGLRenderingContextBase::create(WebCore::CanvasBase&, WebCore::GraphicsContext3DAttributes&, WTF::String const&)
7   0x115ee752b WebCore::HTMLCanvasElement::createContextWebGL(WTF::String const&, WebCore::GraphicsContext3DAttributes&&)
8   0x115ee6503 WebCore::HTMLCanvasElement::getContext(JSC::ExecState&, WTF::String const&, WTF::Vector<JSC::Strong<JSC::Unknown>, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&)
9   0x114826c8d WebCore::jsHTMLCanvasElementPrototypeFunctionGetContextBody(JSC::ExecState*, WebCore::JSHTMLCanvasElement*, JSC::ThrowScope&)
10  0x11481f70e long long WebCore::IDLOperation<WebCore::JSHTMLCanvasElement>::call<&(WebCore::jsHTMLCanvasElementPrototypeFunctionGetContextBody(JSC::ExecState*, WebCore::JSHTMLCanvasElement*, JSC::ThrowScope&)), (WebCore::CastedThisErrorBehavior)0>(JSC::ExecState&, char const*)
11  0x11481f49c WebCore::jsHTMLCanvasElementPrototypeFunctionGetContext(JSC::ExecState*)
12  0x36c7aa401178
13  0x10a99721b llint_entry
14  0x10a99721b llint_entry
15  0x10a98f2f7 vmEntryToJavaScript
16  0x10b6c439e JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*)
17  0x10b66a1e2 JSC::Interpreter::executeProgram(JSC::SourceCode const&, JSC::ExecState*, JSC::JSObject*)
18  0x10b8e6ee7 JSC::evaluate(JSC::ExecState*, JSC::SourceCode const&, JSC::JSValue, WTF::NakedPtr<JSC::Exception>&)
19  0x10b8e7030 JSC::profiledEvaluate(JSC::ExecState*, JSC::ProfilingReason, JSC::SourceCode const&, JSC::JSValue, WTF::NakedPtr<JSC::Exception>&)
20  0x11578e19b WebCore::JSMainThreadExecState::profiledEvaluate(JSC::ExecState*, JSC::ProfilingReason, JSC::SourceCode const&, JSC::JSValue, WTF::NakedPtr<JSC::Exception>&)
21  0x11577bc78 WebCore::ScriptController::evaluateInWorld(WebCore::ScriptSourceCode const&, WebCore::DOMWrapperWorld&, WebCore::ExceptionDetails*)
22  0x11577bd9d WebCore::ScriptController::evaluate(WebCore::ScriptSourceCode const&, WebCore::ExceptionDetails*)
23  0x115d131e7 WebCore::ScriptElement::executeClassicScript(WebCore::ScriptSourceCode const&)
24  0x115d11882 WebCore::ScriptElement::prepareScript(WTF::TextPosition const&, WebCore::ScriptElement::LegacyTypeSupport)
25  0x116076b00 WebCore::HTMLScriptRunner::runScript(WebCore::ScriptElement&, WTF::TextPosition const&)
26  0x11607696f WebCore::HTMLScriptRunner::execute(WTF::Ref<WebCore::ScriptElement>&&, WTF::TextPosition const&)
27  0x1160589e5 WebCore::HTMLDocumentParser::runScriptsForPausedTreeBuilder()
28  0x116058b33 WebCore::HTMLDocumentParser::pumpTokenizerLoop(WebCore::HTMLDocumentParser::SynchronousMode, bool, WebCore::PumpSession&)
29  0x116057c28 WebCore::HTMLDocumentParser::pumpTokenizer(WebCore::HTMLDocumentParser::SynchronousMode)
30  0x11605783b WebCore::HTMLDocumentParser::pumpTokenizerIfPossible(WebCore::HTMLDocumentParser::SynchronousMode)
31  0x116059a8a WebCore::HTMLDocumentParser::append(WTF::RefPtr<WTF::StringImpl>&&)

https://build.webkit.org/results/Apple%20El%20Capitan%20Debug%20WK1%20(Tests)/r225980%20(5403)/results.html
Comment 47 Ryan Haddad 2017-12-15 16:00:15 PST
Reverted r225941 for reason:

This change introduced LayoutTest crashes and assertion failures.

Committed r225990: <https://trac.webkit.org/changeset/225990>
Comment 48 Devin Rousso 2017-12-15 23:07:21 PST
Created attachment 329562 [details]
Patch

I'm not 100% sure about this, but I think that the InstrumentingAgents are wiped out whenever a Frame is removed.  The failing tests checked that canvas contexts within iframes are destroyed after the iframe navigates or is removed.  As a result, since the InstrumentingAgents don't exist anymore, we don't have a way to remove the existing contexts from the CanvasAgent's list, meaning that they are still listed there even though they don't exist anymore.  The solution is to not delete the code inside InspectorCanvasAgent::frameNavigated that finds all the tracked contexts for the navigating frame and removes them.  Hopefully :|
Comment 49 EWS Watchlist 2017-12-16 00:14:36 PST Comment hidden (obsolete)
Comment 50 EWS Watchlist 2017-12-16 00:14:38 PST Comment hidden (obsolete)
Comment 51 EWS Watchlist 2017-12-16 00:23:59 PST Comment hidden (obsolete)
Comment 52 EWS Watchlist 2017-12-16 00:24:01 PST Comment hidden (obsolete)
Comment 53 EWS Watchlist 2017-12-16 00:35:18 PST Comment hidden (obsolete)
Comment 54 EWS Watchlist 2017-12-16 00:35:20 PST Comment hidden (obsolete)
Comment 55 EWS Watchlist 2017-12-16 00:38:28 PST Comment hidden (obsolete)
Comment 56 EWS Watchlist 2017-12-16 00:38:30 PST Comment hidden (obsolete)
Comment 57 Devin Rousso 2017-12-16 17:50:39 PST
Created attachment 329588 [details]
Patch

Taking a different approach.  Instead of trying to add InspectorInstrumentation hooks to ~CanvasRenderingContext, we can expand the usage of the CanvasObserver concept and rely on the destruction of the CanvasBase to know when the CanvasRenderingContext will be destroyed.
Comment 58 EWS Watchlist 2017-12-16 18:39:44 PST Comment hidden (obsolete)
Comment 59 EWS Watchlist 2017-12-16 18:39:46 PST Comment hidden (obsolete)
Comment 60 EWS Watchlist 2017-12-16 18:54:28 PST Comment hidden (obsolete)
Comment 61 EWS Watchlist 2017-12-16 18:54:31 PST Comment hidden (obsolete)
Comment 62 EWS Watchlist 2017-12-16 19:05:33 PST Comment hidden (obsolete)
Comment 63 EWS Watchlist 2017-12-16 19:05:34 PST Comment hidden (obsolete)
Comment 64 Devin Rousso 2017-12-16 21:04:39 PST
Created attachment 329594 [details]
Patch
Comment 65 EWS Watchlist 2017-12-16 22:09:34 PST Comment hidden (obsolete)
Comment 66 EWS Watchlist 2017-12-16 22:09:36 PST Comment hidden (obsolete)
Comment 67 Devin Rousso 2017-12-16 22:23:46 PST
Created attachment 329597 [details]
Patch

I love it how all of these tests run fine on my machine...
Comment 68 EWS Watchlist 2017-12-16 23:51:07 PST Comment hidden (obsolete)
Comment 69 EWS Watchlist 2017-12-16 23:51:09 PST Comment hidden (obsolete)
Comment 70 Devin Rousso 2017-12-17 00:15:02 PST
Created attachment 329599 [details]
Patch

Rebase
Comment 71 EWS Watchlist 2017-12-17 01:48:53 PST Comment hidden (obsolete)
Comment 72 EWS Watchlist 2017-12-17 01:48:55 PST Comment hidden (obsolete)
Comment 73 Devin Rousso 2017-12-17 12:46:28 PST
Created attachment 329619 [details]
Patch

It looks like it's possible for willDeleteProgram and isShaderProgramDisabled to be called on a ShaderProgram that has already been deleted via deleteProgram, so we don't want to ASSERT for an InspectorShaderProgram.
Comment 74 Devin Rousso 2017-12-18 14:35:53 PST
Created attachment 329686 [details]
Patch

Let's see if I can get the win EWS to be happy :P
Comment 75 Joseph Pecoraro 2017-12-18 16:39:04 PST
Comment on attachment 329686 [details]
Patch

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

> Source/WebCore/ChangeLog:138
> +22017-12-18  Megan Gardner  <megan_gardner@apple.com>

Extra 2.

> Source/WebCore/ChangeLog:-258
> -2017-12-16  Dan Bernstein  <mitz@apple.com>

Missing 2.
Comment 76 Devin Rousso 2017-12-18 16:43:43 PST
Created attachment 329709 [details]
Patch

Oops.
Comment 77 EWS Watchlist 2017-12-18 18:16:43 PST Comment hidden (obsolete)
Comment 78 EWS Watchlist 2017-12-18 18:16:45 PST Comment hidden (obsolete)
Comment 79 Devin Rousso 2017-12-18 19:40:44 PST
Created attachment 329729 [details]
Patch

Rebase
Comment 80 Joseph Pecoraro 2018-01-04 16:13:57 PST
Comment on attachment 329729 [details]
Patch

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

Some open questions.

> Source/WebCore/html/CanvasBase.h:29
> +#include "IntSize.h"

Is this needed? It is also forward declared below.

> Source/WebCore/html/CanvasBase.h:82
> +    HashSet<CanvasObserver*> m_observers;

I'd have expected this to be private.

> Source/WebCore/html/OffscreenCanvas.cpp:45
> +OffscreenCanvas::~OffscreenCanvas()

Why isn't this done in ~CanvasBase?

> Tools/ChangeLog:8
> +        * Scripts/webkitpy/common/config/watchlist:

The watchlist stuff could probably be its own unrelated change. No need to include it with a code change like this. Its also super generic given there are 260+ files many (WebGPU).
Comment 81 Devin Rousso 2018-01-04 16:57:51 PST
Comment on attachment 329729 [details]
Patch

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

>> Source/WebCore/html/OffscreenCanvas.cpp:45
>> +OffscreenCanvas::~OffscreenCanvas()
> 
> Why isn't this done in ~CanvasBase?

This isn't done in ~CanvasBase because of what ~HTMLCanvasElement does, specifically that we manually set `m_context = nullptr;`.  Due to the inheritance destruction order, having the `CanvasObserver::canvasDestroyed` call be in `~CanvasBase` would mean that the `m_context` would be `nullptr` by the time of the `CanvasObserver::canvasDestroyed` call.  As a result, we keep the existing functionality of `~HTMLCanvasElement`.

If we added the `CanvasObserver::canvasDestroyed` calls to `~CanvasBase`, each `CanvasObserver::canvasDestroyed` would get called multiple times for the same canvas.  Instead, we don't add it to the base and have the subclasses manage the observers themselves (this is also why `m_observers` is protected).
Comment 82 Joseph Pecoraro 2018-01-04 17:14:09 PST
Comment on attachment 329729 [details]
Patch

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

>>> Source/WebCore/html/OffscreenCanvas.cpp:45
>>> +OffscreenCanvas::~OffscreenCanvas()
>> 
>> Why isn't this done in ~CanvasBase?
> 
> This isn't done in ~CanvasBase because of what ~HTMLCanvasElement does, specifically that we manually set `m_context = nullptr;`.  Due to the inheritance destruction order, having the `CanvasObserver::canvasDestroyed` call be in `~CanvasBase` would mean that the `m_context` would be `nullptr` by the time of the `CanvasObserver::canvasDestroyed` call.  As a result, we keep the existing functionality of `~HTMLCanvasElement`.
> 
> If we added the `CanvasObserver::canvasDestroyed` calls to `~CanvasBase`, each `CanvasObserver::canvasDestroyed` would get called multiple times for the same canvas.  Instead, we don't add it to the base and have the subclasses manage the observers themselves (this is also why `m_observers` is protected).

Okay, then I think we really should make this less prone to error that someone subclasses CanvasBase and forgets to notify observers.

Worst case something like:

    class CanvasBase {
    ...
    protected:
        // Subclasses are expected to notify observers in destruction.
        HashSet<CanvasObserver*> m_observers;
        void notifyObserversOfDestruction();
    #ifndef NDEBUG
        bool m_didNotifyObserversOfDestruction { false };
    #endif
    ...
    }

With implementation:

    CanvasBase::~CanvasBase()
    {
        ASSERT(m_didNotifyObserversOfDestruction);
    }

    void CanvasBase::notifyObserversOfDestruction()
    {
#ifndef NDEBUG
        ASSERT(!m_didNotifyObserversOfDestruction);
        m_didNotifyObserversOfDestruction = true;
#endif
        for (auto& observer : m_observers)
            observer->canvasDestroyed(*this);
    }

Would mean when the next person adds `class FutureCanvas : public <CanvasBase>` we would immediately catch if they didn't handle destruction.

---

But all of that said, it would be best to just make this work as expected and make m_observers managed only by CanvasBase.
Comment 83 Devin Rousso 2018-01-04 18:24:40 PST
Created attachment 330506 [details]
Patch
Comment 84 Joseph Pecoraro 2018-01-04 18:44:54 PST
Comment on attachment 330506 [details]
Patch

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

r=me

> Source/WebCore/html/CanvasBase.h:63
> +    void addObserver(CanvasObserver&);
> +    void removeObserver(CanvasObserver&);

Style: I'd put these after the list of virtual methods instead of in the middle. And maybe the notifyObserver functions could be made protected instead of public, but public is fine.
Comment 85 Devin Rousso 2018-01-04 20:43:14 PST
Created attachment 330519 [details]
Patch
Comment 86 WebKit Commit Bot 2018-01-04 22:40:35 PST
Comment on attachment 330519 [details]
Patch

Clearing flags on attachment: 330519

Committed r226439: <https://trac.webkit.org/changeset/226439>
Comment 87 WebKit Commit Bot 2018-01-04 22:40:39 PST
All reviewed patches have been landed.  Closing bug.