RESOLVED FIXED 221236
Introduce image overlays and add UA shadow root support for image extraction
https://bugs.webkit.org/show_bug.cgi?id=221236
Summary Introduce image overlays and add UA shadow root support for image extraction
Wenson Hsieh
Reported 2021-02-01 17:40:46 PST
SSIA
Attachments
WIP (29.53 KB, patch)
2021-02-02 18:07 PST, Wenson Hsieh
no flags
WIP (28.97 KB, patch)
2021-02-02 18:10 PST, Wenson Hsieh
hi: review+
Patch (35.92 KB, patch)
2021-02-04 17:01 PST, Wenson Hsieh
no flags
Patch (35.32 KB, patch)
2021-02-04 22:33 PST, Wenson Hsieh
ews-feeder: commit-queue-
Fix GTK/WPE builds (35.86 KB, patch)
2021-02-04 23:16 PST, Wenson Hsieh
no flags
Patch (24.12 KB, patch)
2021-02-05 10:25 PST, Wenson Hsieh
no flags
Fix title (24.11 KB, patch)
2021-02-05 10:27 PST, Wenson Hsieh
no flags
Move code out of HTMLImageElement (23.95 KB, patch)
2021-02-06 13:16 PST, Wenson Hsieh
rniwa: review+
Patch (23.69 KB, patch)
2021-02-06 17:14 PST, Wenson Hsieh
no flags
Wenson Hsieh
Comment 1 2021-02-02 18:07:49 PST Comment hidden (obsolete)
Wenson Hsieh
Comment 2 2021-02-02 18:10:52 PST
Devin Rousso
Comment 3 2021-02-03 14:38:50 PST
Comment on attachment 419090 [details] WIP View in context: https://bugs.webkit.org/attachment.cgi?id=419090&action=review r=me > Source/WebCore/html/shadow/ImageExtractionContentContainer.cpp:41 > +class RenderImageExtractionContentContainer : public RenderBlockFlow { should the entire class be `final`? > Source/WebCore/html/shadow/ImageExtractionContentContainer.h:35 > +class HTMLDivElement; NIT: you've already `#include` this so no need to forward declare again :P > Source/WebCore/html/shadow/ImageExtractionContentContainer.h:39 > +class ImageExtractionContentContainer : public HTMLDivElement { should the entire class be `final`? > Source/WebCore/rendering/RenderImage.cpp:839 > + LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode()); does this need to be hoisted outside the `for` so that it also covers `clearChildNeedsLayout()` like before?
Wenson Hsieh
Comment 4 2021-02-03 15:23:08 PST
Comment on attachment 419090 [details] WIP View in context: https://bugs.webkit.org/attachment.cgi?id=419090&action=review I'm going to additionally try to simplify the logic here by avoiding a custom renderer subclass (RenderImageExtractionContentContainer). >> Source/WebCore/html/shadow/ImageExtractionContentContainer.cpp:41 >> +class RenderImageExtractionContentContainer : public RenderBlockFlow { > > should the entire class be `final`? Good call. Although, from chatting with Simon and Alan, it looks like I should be able to remove this custom renderer subclass altogether, so I'll try that first. >> Source/WebCore/html/shadow/ImageExtractionContentContainer.h:35 >> +class HTMLDivElement; > > NIT: you've already `#include` this so no need to forward declare again :P Whoops, good catch. >> Source/WebCore/html/shadow/ImageExtractionContentContainer.h:39 >> +class ImageExtractionContentContainer : public HTMLDivElement { > > should the entire class be `final`? ๐Ÿ‘๐Ÿป >> Source/WebCore/rendering/RenderImage.cpp:839 >> + LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode()); > > does this need to be hoisted outside the `for` so that it also covers `clearChildNeedsLayout()` like before? From reading the code, it looks like the `LayoutStateMaintainer` just needs to encompass the recursive layout calls on the children, and clearChildNeedsLayout() just clears a few "needs layout" flags, so I *think* this should be okay...
Wenson Hsieh
Comment 5 2021-02-04 15:40:32 PST
(In reply to Wenson Hsieh from comment #4) > Comment on attachment 419090 [details] > WIP > > View in context: > https://bugs.webkit.org/attachment.cgi?id=419090&action=review > > I'm going to additionally try to simplify the logic here by avoiding a > custom renderer subclass (RenderImageExtractionContentContainer). Alan helped me figure out how to do this โ€” we needed to make a slight adjustment in RenderImage::layoutShadowControls(), so that we set fixed layout dimensions on the child renderers even in the case where `shadowControlsNeedCustomLayoutMetrics()` is `false` (that is, in the case where the renderer is not a RenderMedia). This method (shadowControlsNeedCustomLayoutMetrics) was added as a part of original support for "image controls", but is currently only used to ensure that the size of media controls (e.g. controls in video elements) matches that of the media element's renderer, since support for "image controls" has been removed. This means we should be able to remove `shadowControlsNeedCustomLayoutMetrics` altogether, and just always set a fixed width and height in RenderImage::layoutShadowControls(), since both regular images and media (video) elements now require it.
Simon Fraser (smfr)
Comment 6 2021-02-04 15:57:31 PST
How does all this work in the face of object-fit?
Wenson Hsieh
Comment 7 2021-02-04 17:01:00 PST
Wenson Hsieh
Comment 8 2021-02-04 17:06:43 PST
(In reply to Simon Fraser (smfr) from comment #6) > How does all this work in the face of object-fit? We'll eventually need to transform the normalized quads in the coordinate space of the image into bounding rects in the coordinate space of the image element. In the case of `object-fit: contain;`, this is going to mean applying an additional x or y offset. This patch doesn't attempt to implement that part yet (it currently just scales each quad's bounds against the size of the container).
Ryosuke Niwa
Comment 9 2021-02-04 20:30:29 PST
Comment on attachment 419342 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=419342&action=review > Source/WebCore/dom/Node.h:211 > +#if ENABLE(IMAGE_EXTRACTION) > + virtual bool isImageExtractionContentContainer() const { return false; } > +#endif Please define this in HTMLElement instead under isTextControlInnerTextElement() and such.
Wenson Hsieh
Comment 10 2021-02-04 22:33:04 PST
Wenson Hsieh
Comment 11 2021-02-04 23:16:07 PST
Created attachment 419365 [details] Fix GTK/WPE builds
Wenson Hsieh
Comment 12 2021-02-04 23:19:07 PST
Comment on attachment 419342 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=419342&action=review >> Source/WebCore/dom/Node.h:211 >> +#endif > > Please define this in HTMLElement instead under isTextControlInnerTextElement() and such. Done! (and also renamed to isImageOverlayElement())
Antti Koivisto
Comment 13 2021-02-05 07:02:07 PST
Comment on attachment 419365 [details] Fix GTK/WPE builds View in context: https://bugs.webkit.org/attachment.cgi?id=419365&action=review > Source/WebCore/dom/Element.cpp:4586 > + auto container = ImageOverlayElement::create(document()); > + ensureUserAgentShadowRoot().appendChild(container); Is updateWithImageExtractionResult() guaranteed to be only called once? I don't see any code to update or remove the existing ImageOverlayElement. > Source/WebCore/html/shadow/ImageOverlayElement.h:39 > +class ImageOverlayElement final : public HTMLDivElement { Why do we need this subclass? As far as I can see it currently has no data members or unique behaviours in virtual functions. Could you just use HTMLDivElement and put the related functions somewhere else?
Antti Koivisto
Comment 14 2021-02-05 07:18:18 PST
Comment on attachment 419365 [details] Fix GTK/WPE builds View in context: https://bugs.webkit.org/attachment.cgi?id=419365&action=review > Source/WebCore/style/UserAgentStyle.cpp:193 > + else if (!imageOverlayStyleSheet && is<ImageOverlayElement>(element)) { > + imageOverlayStyleSheet = parseUASheet(imageOverlayUserAgentStyleSheet, sizeof(imageOverlayUserAgentStyleSheet)); > + addToDefaultStyle(*imageOverlayStyleSheet); > + } Please don't add anything to default style sheet for this. Instead insert a <style> element in the shadow tree. All selectors will be scoped to that tree so nothing leaks out. See HTMLMeterElement::didAddUserAgentShadowRoot for an example.
Wenson Hsieh
Comment 15 2021-02-05 08:33:32 PST
Comment on attachment 419365 [details] Fix GTK/WPE builds View in context: https://bugs.webkit.org/attachment.cgi?id=419365&action=review >> Source/WebCore/dom/Element.cpp:4586 >> + ensureUserAgentShadowRoot().appendChild(container); > > Is updateWithImageExtractionResult() guaranteed to be only called once? I don't see any code to update or remove the existing ImageOverlayElement. In its current form, it will only be called once, yes. In the (near) future, we'll need to be able to remove the overlay if (for instance) the image source changes. >> Source/WebCore/html/shadow/ImageOverlayElement.h:39 >> +class ImageOverlayElement final : public HTMLDivElement { > > Why do we need this subclass? As far as I can see it currently has no data members or unique behaviours in virtual functions. Could you just use HTMLDivElement and put the related functions somewhere else? I was planning to stash some additional members on `ImageOverlayElement` in a future patch, but it looks like an alternative to that is perhaps keeping a map of some sort on like `Document` or `Page`. The `ImageOverlayElement` subclass also allows me to (more easily) identify one of these image overlay elements through a type traits checkโ€ฆthough I suppose I could just check the class list? >> Source/WebCore/style/UserAgentStyle.cpp:193 >> + } > > Please don't add anything to default style sheet for this. Instead insert a <style> element in the shadow tree. All selectors will be scoped to that tree so nothing leaks out. See HTMLMeterElement::didAddUserAgentShadowRoot for an example. Whoops. Will do!
Wenson Hsieh
Comment 16 2021-02-05 08:46:51 PST
Comment on attachment 419365 [details] Fix GTK/WPE builds View in context: https://bugs.webkit.org/attachment.cgi?id=419365&action=review >>> Source/WebCore/style/UserAgentStyle.cpp:193 >>> + } >> >> Please don't add anything to default style sheet for this. Instead insert a <style> element in the shadow tree. All selectors will be scoped to that tree so nothing leaks out. See HTMLMeterElement::didAddUserAgentShadowRoot for an example. > > Whoops. Will do! I suppose this also means I'll need to tie this to HTMLImageElement (at least, for the time being?)
Wenson Hsieh
Comment 17 2021-02-05 10:25:06 PST
Wenson Hsieh
Comment 18 2021-02-05 10:27:48 PST
Created attachment 419426 [details] Fix title
Ryosuke Niwa
Comment 19 2021-02-05 21:23:43 PST
Comment on attachment 419426 [details] Fix title View in context: https://bugs.webkit.org/attachment.cgi?id=419426&action=review > Source/WebCore/html/HTMLImageElement.cpp:827 > +bool HTMLImageElement::hasOverlay() const > +{ Don't we need to have this on HTMLPlugInImageElement too so that this will also work on object element? > Source/WebCore/html/HTMLImageElement.cpp:832 > + for (auto child = makeRefPtr(shadowRoot->firstChild()); child; child = child->nextSibling()) { Use childrenOfType<Element>? > Source/WebCore/html/HTMLImageElement.cpp:878 > + container->appendChild(child); It's more efficient to build tree bottom up so do this before appending children to child. > Source/WebCore/html/HTMLImageElement.cpp:898 > + if (auto* frame = document().frame()) Please use makeRefPtr here. > Source/WebCore/html/shadow/imageOverlay.css:25 > +div#image-overlay { img element is display: inline by default. div is display: block by default. Don't we want this to be inline-block?
Wenson Hsieh
Comment 20 2021-02-06 12:40:12 PST
Comment on attachment 419426 [details] Fix title View in context: https://bugs.webkit.org/attachment.cgi?id=419426&action=review >> Source/WebCore/html/HTMLImageElement.cpp:827 >> +{ > > Don't we need to have this on HTMLPlugInImageElement too so that this will also work on object element? Good point. I will move these helper methods into `HTMLElement` as `HTMLElement::hasImageOverlay()` and `HTMLElement::updateWithImageExtractionResult()`, so it can work for both image plugin elements and regular image elements (as well as anything else we may want to support in the future, such as canvas or video elements). >> Source/WebCore/html/HTMLImageElement.cpp:832 >> + for (auto child = makeRefPtr(shadowRoot->firstChild()); child; child = child->nextSibling()) { > > Use childrenOfType<Element>? ๐Ÿ‘๐Ÿป changed to use childrenOfType<Element> >> Source/WebCore/html/HTMLImageElement.cpp:878 >> + container->appendChild(child); > > It's more efficient to build tree bottom up so do this before appending children to child. Fixed! >> Source/WebCore/html/HTMLImageElement.cpp:898 >> + if (auto* frame = document().frame()) > > Please use makeRefPtr here. ๐Ÿ‘๐Ÿป >> Source/WebCore/html/shadow/imageOverlay.css:25 >> +div#image-overlay { > > img element is display: inline by default. div is display: block by default. > Don't we want this to be inline-block? Good catch โ€” added `display: inline-block;` to the style.
Wenson Hsieh
Comment 21 2021-02-06 13:16:43 PST
Created attachment 419514 [details] Move code out of HTMLImageElement
Ryosuke Niwa
Comment 22 2021-02-06 15:53:03 PST
Comment on attachment 419514 [details] Move code out of HTMLImageElement View in context: https://bugs.webkit.org/attachment.cgi?id=419514&action=review > Source/WebCore/html/HTMLElement.cpp:1210 > + for (auto& child : childrenOfType<Element>(*shadowRoot)) { > + if (child.getIdAttribute() == imageOverlayElementIdentifier()) Oh, now that I'm thinking about this, we should just use TreeScope::hasElementWithId instead. Assuming we don't use this same ID elsewhere in the shadow tree. It would be a single HashMap lookup! > Source/WebCore/rendering/RenderImage.cpp:817 > + for (auto* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) { > + if (!is<RenderBox>(renderer)) Use childrenOfType<RenderBox>?
Wenson Hsieh
Comment 23 2021-02-06 17:01:21 PST
Comment on attachment 419514 [details] Move code out of HTMLImageElement View in context: https://bugs.webkit.org/attachment.cgi?id=419514&action=review >> Source/WebCore/html/HTMLElement.cpp:1210 >> + if (child.getIdAttribute() == imageOverlayElementIdentifier()) > > Oh, now that I'm thinking about this, we should just use TreeScope::hasElementWithId instead. > Assuming we don't use this same ID elsewhere in the shadow tree. > It would be a single HashMap lookup! Nice โ€” changed to use `hasElementWithId()`. >> Source/WebCore/rendering/RenderImage.cpp:817 >> + if (!is<RenderBox>(renderer)) > > Use childrenOfType<RenderBox>? Fixed!
Wenson Hsieh
Comment 24 2021-02-06 17:14:18 PST
EWS
Comment 25 2021-02-06 19:29:02 PST
Committed r272467: <https://commits.webkit.org/r272467> All reviewed patches have been landed. Closing bug and clearing flags on attachment 419516 [details].
Radar WebKit Bug Importer
Comment 26 2021-02-10 14:44:53 PST
Note You need to log in before you can comment on or make changes to this bug.