-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[wpe-2.38] <video> element is never destoyed when using modern media controls #1285
Comments
Fix patch submitted upstream for review as https://bugs.webkit.org/show_bug.cgi?id=270571 / WebKit/WebKit#25625. |
…ng media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by NOBODY (OOPS!). At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded/WPEWebKit#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to deinitialize the MediaController when HTMLMediaElement is no longer in use. The best place mathing that instant is pauseAfterDetachedTask(). This deinitialization takes care of properly nulling the mentioned objects that hold (or transitively hold) the references to HTMLMediaElement. A new MediaController.deinitialize() method has been added to the JavaScript code for this purpose. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController.prototype.deinitialize): Set references to the media element and the shadow root to null and also detach the UI container from the shadow root, so no references to HTMLMediaElement are held anymore, either directly or transitively. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Add code to call to the MediaController.deinitialize() JavaScript method.
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded/WPEWebKit#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…gi?id=260455 [Modern Media Controls] HTMLMediaElement is never destroyed when showing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded/WPEWebKit#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: #1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
The patch landed upstream as WebKit/WebKit@80dd62a and was backported to wpe-2.38 as 7877902. |
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: #1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
...and to the calvaris/wpe-2.42/upstream branch as 6de0ae1. Closing Issue. |
Tested with the latest webkit build and all my cases work fine now. HTMLMediaElement is correctly destroyed. |
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: #1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: #1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
…ing media controls https://bugs.webkit.org/show_bug.cgi?id=270571 Reviewed by Xabier Rodriguez-Calvar. At least in GStreamer-based ports (WPE and WebKitGTK, I haven't checked on Mac ports because I don't have the proper environment easily available), the media element is leaked after explicit deinitialization and detaching from the HTML document, even after manually triggering garbage collection (GC) using the web inspector. See: WebPlatformForEmbedded#1285 After some debugging, we've detected that 2 extra references to HTMLMediaElement appear when using the controls (3 refs in total), while in a scenario where the controls are hidden on purpose only 1 reference remains, which is released as soon as the GC kicks in. Those references are held (or transitively held) by the MediaController, the shadowRoot referenced by the MediaController and by the IconService, and the <div> element that MediaController adds to the shadowRoot as a container for the controls. This commit adds code to use WeakRefs to the ShadowRoot and to the MediaJSWrapper (media) on MediaController, and to the ShadowRoot on the iconService, instead of the original objects. This allows the garbage collector to kick in when needed and have those objects freed automatically. The WeakRefs are transparently exposed as regular objects by using properties (get/set), to avoid the need to change a lot of code that expects regular objects. There's still the <div> element added to the ShadowRoot, which transitively holds a reference that prevents GC. There's no good place to remove that element, so I removed it in the "less bad place", which is HTMLMediaElement::pauseAfterDetachedTask(). A new deinitialize() JS function takes care of that. Unfortunately, the element can still be used after deinitialization, so there's also a method to reinitialize() it if needed and an extra ControlsState to mark the element as PartiallyDeinitialized in order to know when to recover from that state. * Source/WebCore/Modules/modern-media-controls/controls/icon-service.js: Store shadowRoot as a WeakRef. (const.iconService.new.IconService.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (const.iconService.new.IconService.prototype.set shadowRoot): Ditto, but for the setter. * Source/WebCore/Modules/modern-media-controls/media/media-controller.js: (MediaController): Store shadowRoot and media as WeakRefs. (MediaController.prototype.get media): Expose the mediaWeakRef as a regular media object by binding it to the media property. (MediaController.prototype.get shadowRoot): Expose the shadowRootWeakRef as a regular shadowRoot object by binding it to the shadowRoot property. (MediaController.prototype.get isFullscreen): Take into account the case where media can be null. (MediaController.prototype.deinitialize): Function called from HTMLMediaElement to deinitialize the MediaController. Just removes the shadowRoot child. (MediaController.prototype.reinitialize): Function called from HTMLMediaElement to reinitialize the MediaController. Readds the shadowRoot child and sets again the WeakRefs that might have become by lack of use of the main objects. * Source/WebCore/html/HTMLMediaElement.cpp: (WebCore::convertEnumerationToString): Utility function to get a printable version of ControlsState. Useful for debugging. (WebCore::HTMLMediaElement::pauseAfterDetachedTask): Deinitialize the MediaController by calling its deinitialize() JS method. (WebCore::HTMLMediaElement::ensureMediaControls): Support the case of reinitialization. Call the reinitialize() JS method in MediaController in that case. * Source/WebCore/html/HTMLMediaElement.h: Added new PartiallyDeinitialized state to ControlsState. Give friend access to convertEnumerationToString() so it can do its job. Canonical link: https://commits.webkit.org/277196@main
We observe increased memory consumption for wpe webkit 2.38 (comparing to 2.28) when running YT cert tests. It sometimes leads to OOM killer as WPEWebProcess uses ~550MB of memory despite much lower memory pressure settings.
YT creates separete <video> element for each test. Initial analysis shows that HTMLMediaElement (s) are never destroyed during execution. Also manually triggering GarbageCollector from RWI doesn't help, nothing is destoryd.
Together with HTMLMediaElement there are many other objects that are connected, like SourceBuffers, MediaKeys, etc. As a result memory usage is growing constantly triggering OOM eventually.
Looking into JS sources it looks like enabling video controls attribute is the reason here. When media controls are disabled then issue is not observed. With 2.38 media controls impl changed -> modern media controls was enabled that seems to be the reason here.
Here is a javascript code that reproduces the issue. I use "collect garbage" button from RWI to trigger GC and check if ~HTMLMediaElement() is called:
Note that skipping video.controls(true) or not attaching video element into document's body works perfectly fine.
The text was updated successfully, but these errors were encountered: