Bug 217596

Summary: [GPU Process][Resource caching 6/7]: Cache the NativeImage in GPU Process and allow referencing it with its RemoteResourceIdentifier
Product: WebKit Reporter: Said Abou-Hallawa <sabouhallawa>
Component: Layout and RenderingAssignee: Said Abou-Hallawa <sabouhallawa>
Status: RESOLVED FIXED    
Severity: Normal CC: annulen, berto, bfulgham, calvaris, cdumez, cgarcia, changseok, cmarcelo, dino, eric.carlson, esprehn+autocc, ews-watchlist, fmalita, glenn, graouts, gustavo, gyuyoung.kim, hta, japhet, jer.noble, kondapallykalyan, luiz, menard, mmaxfield, pdr, philipj, pnormand, ryuan.choi, schenney, sergio, simon.fraser, tommyw, vjaquez, webkit-bug-importer, wenson_hsieh, zalan
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=218773
Bug Depends on: 217573, 218427    
Bug Blocks: 217166, 217342    
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch for review
none
Patch
none
Patch for review
none
Patch
none
Patch
none
Patch for review
none
Patch
ews-feeder: commit-queue-
Patch
none
Patch
none
Patch
ews-feeder: commit-queue-
Patch
none
Patch
none
Patch
simon.fraser: review+
Patch none

Description Said Abou-Hallawa 2020-10-11 18:50:26 PDT
Currently we draw the NativeImage into a ShareableBitmap and send it to the GPU Process. The GPU Process receives the ShareableBitmap and convert it to a NativeImage. These steps happen every time the same NativeImage is drawn. This would require memory, CPU cycles and IPC communications. We need to cache the BitmapImage frame once and reference it with its RemoteResourceIdentifier.

The life cycle of the cached NativeImages will be determined by the Web Process. If the BitmapImage decides to destroy its decoded data, the GPU Process will delete the same NativeImages which correspond to the same deleted decoded frames.
Comment 1 Said Abou-Hallawa 2020-10-11 19:01:34 PDT
Created attachment 411086 [details]
Patch
Comment 2 Said Abou-Hallawa 2020-10-11 21:54:07 PDT
Created attachment 411096 [details]
Patch
Comment 3 Said Abou-Hallawa 2020-10-12 00:08:16 PDT
Created attachment 411098 [details]
Patch
Comment 4 Said Abou-Hallawa 2020-10-12 09:58:56 PDT
Created attachment 411125 [details]
Patch for review
Comment 5 Radar WebKit Bug Importer 2020-10-18 18:51:15 PDT
<rdar://problem/70424954>
Comment 6 Said Abou-Hallawa 2020-10-21 20:49:04 PDT
Created attachment 412064 [details]
Patch
Comment 7 Said Abou-Hallawa 2020-10-21 23:33:35 PDT
Created attachment 412070 [details]
Patch for review
Comment 8 Said Abou-Hallawa 2020-10-28 16:33:19 PDT
Created attachment 412586 [details]
Patch
Comment 9 Simon Fraser (smfr) 2020-10-29 14:38:41 PDT
Comment on attachment 412586 [details]
Patch

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

> Source/WebCore/platform/graphics/BitmapImage.cpp:214
> +static inline void drawNativeImage(BitmapImage& image, GraphicsContext& context, const NativeImagePtr& nativeImage, const FloatRect& destRect, const FloatRect& srcRect, const IntSize& srcSize, const ImagePaintingOptions& options)

It's really confusing for this to take both a BitmapImage and a NativeImage. Can the latter be derived from the former?

> Source/WebCore/platform/graphics/GraphicsContext.cpp:734
> +void GraphicsContext::drawNativeImage(const NativeImagePtr& image, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options, CachedImage* cachedImage)

This is a layering violation. You can't use CachedImage in platform code.

> Source/WebCore/platform/graphics/displaylists/DisplayListItems.h:1736
> +    WEBCORE_EXPORT DrawNativeImage(const NativeImageType&, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions&);

I don't think it makes sense to encode draw native image. If we're drawing an image with GPUP, can't it always be represented as an ImageBuffer?

> Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp:190
> +void Recorder::drawNativeImage(const NativeImagePtr& image, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options, CachedImage* cachedImage)

layering violation.
Comment 10 Said Abou-Hallawa 2020-11-01 12:52:47 PST
The life cycle of the PlatformImage will be controlled by a new called called NativeImage, see bug 218427.
Comment 11 Said Abou-Hallawa 2020-11-02 11:00:29 PST
Created attachment 412945 [details]
Patch
Comment 12 EWS Watchlist 2020-11-02 11:01:07 PST
Thanks for the patch. If this patch contains new public API please make sure it follows the guidelines for new WebKit2 GTK+ API. See https://trac.webkit.org/wiki/WebKitGTK/AddingNewWebKit2API
Comment 13 Said Abou-Hallawa 2020-11-02 11:02:19 PST
Created attachment 412947 [details]
Patch for review
Comment 14 Myles C. Maxfield 2020-11-02 23:07:58 PST
Comment on attachment 412947 [details]
Patch for review

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

> Source/WebCore/platform/graphics/GraphicsContext.cpp:761
> +    if (m_impl && image.isPDFDocumentImage())

Why should we need to check PDF document images here? This seems to break encapsulation.

> Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp:179
> +void RemoteRenderingBackend::cachePlatformImage(const PlatformImagePtr& image, RenderingResourceIdentifier renderingResourceIdentifier)

I don't see the type PlatformImagePtr defined anywhere.

> Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.cpp:84
> +bool RemoteResourceCacheProxy::lockRemoteNativeImageForRemoteClient(NativeImage& image, RenderingResourceIdentifier remoteClientIdentifier)

I don't see the NativeImage type defined anywhere.
Comment 15 Myles C. Maxfield 2020-11-02 23:10:14 PST
Comment on attachment 412947 [details]
Patch for review

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

> Source/WebKit/GPUProcess/graphics/RemoteResourceCache.cpp:51
> +PlatformImagePtr RemoteResourceCache::cachedPlatformImage(RenderingResourceIdentifier renderingResourceIdentifier)

Nit: It's not really a "cache" if there is no automatic eviction. This seems more like a "repository" or something like that.
Comment 16 Myles C. Maxfield 2020-11-02 23:16:41 PST
Comment on attachment 412947 [details]
Patch for review

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

This looks like a good direction.

> Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.h:59
> +    void nativeImageWillBeDeleted(WebCore::RenderingResourceIdentifier) override;

final?
Comment 17 Myles C. Maxfield 2020-11-02 23:32:11 PST
Comment on attachment 412947 [details]
Patch for review

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

>> Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.cpp:84
>> +bool RemoteResourceCacheProxy::lockRemoteNativeImageForRemoteClient(NativeImage& image, RenderingResourceIdentifier remoteClientIdentifier)
> 
> I don't see the NativeImage type defined anywhere.

Oh, it's in https://bugs.webkit.org/show_bug.cgi?id=218427
Comment 18 Said Abou-Hallawa 2020-11-10 14:13:49 PST
Created attachment 413740 [details]
Patch
Comment 19 Said Abou-Hallawa 2020-11-10 14:21:06 PST
(In reply to Said Abou-Hallawa from comment #18)
> Created attachment 413740 [details]
> Patch

Three notes about this patch:

1. PDFDocumentImage will be broken but the rest of images should be fine with this patch. Once it is landed I am going to file a bug for PDFDocumentImage.

2. The following DisplayList items should be removed in a follow-up patch since they are used with this patch:

    DrawImage,
    DrawTiledImage,
    DrawTiledScaledImage,

3. Drawing a canvas into another canvas is blocked by bug 218773.
Comment 20 Said Abou-Hallawa 2020-11-10 14:34:25 PST
Created attachment 413742 [details]
Patch
Comment 21 Said Abou-Hallawa 2020-11-10 14:36:14 PST
(In reply to Said Abou-Hallawa from comment #19)
> (In reply to Said Abou-Hallawa from comment #18)
> > Created attachment 413740 [details]
> > Patch
> 
> Three notes about this patch:
> 
> 1. PDFDocumentImage will be broken but the rest of images should be fine
> with this patch. Once it is landed I am going to file a bug for
> PDFDocumentImage.
> 
> 2. The following DisplayList items should be removed in a follow-up patch
> since they are used with this patch:
> 
>     DrawImage,
>     DrawTiledImage,
>     DrawTiledScaledImage,
> 
> 3. Drawing a canvas into another canvas is blocked by bug 218773.

A fourth comment

4. I think the class ImageDataReference can be replaced by just

using ImageDataReference = RefPtr<ImageData>;
Comment 22 Wenson Hsieh 2020-11-10 14:59:44 PST
Comment on attachment 413742 [details]
Patch

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

I think this patch looks pretty good! A couple of minor comments:

> Source/WebCore/platform/graphics/displaylists/DisplayListItems.h:1280
> +    DrawNativeImage(RenderingResourceIdentifier renderingResourceIdentifier, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options)

Nit - I think we might actually be able to remove this and just use the default constructor instead?

> Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.cpp:52
> +bool RemoteResourceCacheProxy::cacheNativeImage(NativeImage& image)

Nit - it wasn't obvious at first what the bool argument here represents; could we use an enum instead, like `enum class AddedNewEntry : bool { No, Yes };`?
Comment 23 Said Abou-Hallawa 2020-11-10 15:58:31 PST
Created attachment 413754 [details]
Patch
Comment 24 Said Abou-Hallawa 2020-11-10 15:59:15 PST
Comment on attachment 413742 [details]
Patch

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

>> Source/WebCore/platform/graphics/displaylists/DisplayListItems.h:1280
>> +    DrawNativeImage(RenderingResourceIdentifier renderingResourceIdentifier, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options)
> 
> Nit - I think we might actually be able to remove this and just use the default constructor instead?

What do you mean by the default constructor in this context? The default constructor does not expect any parameters and all the members of this class are private.

>> Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.cpp:52
>> +bool RemoteResourceCacheProxy::cacheNativeImage(NativeImage& image)
> 
> Nit - it wasn't obvious at first what the bool argument here represents; could we use an enum instead, like `enum class AddedNewEntry : bool { No, Yes };`?

I changed the code such that we do not need to return a bool from this function. I made sending the CacheNativeImage message initiated by this function. This will correspond to what we do in RemoteResourceCacheProxy::nativeImageWillBeDeleted() where we initiate sending the ReleaseRemoteResource message.
Comment 25 Wenson Hsieh 2020-11-10 16:07:50 PST
Comment on attachment 413742 [details]
Patch

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

>>> Source/WebCore/platform/graphics/displaylists/DisplayListItems.h:1280
>>> +    DrawNativeImage(RenderingResourceIdentifier renderingResourceIdentifier, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options)
>> 
>> Nit - I think we might actually be able to remove this and just use the default constructor instead?
> 
> What do you mean by the default constructor in this context? The default constructor does not expect any parameters and all the members of this class are private.

My bad — that's correct, we need this constructor because the members are private.

>>> Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.cpp:52
>>> +bool RemoteResourceCacheProxy::cacheNativeImage(NativeImage& image)
>> 
>> Nit - it wasn't obvious at first what the bool argument here represents; could we use an enum instead, like `enum class AddedNewEntry : bool { No, Yes };`?
> 
> I changed the code such that we do not need to return a bool from this function. I made sending the CacheNativeImage message initiated by this function. This will correspond to what we do in RemoteResourceCacheProxy::nativeImageWillBeDeleted() where we initiate sending the ReleaseRemoteResource message.

👍🏻
Comment 26 Said Abou-Hallawa 2020-11-10 17:26:40 PST
(In reply to Said Abou-Hallawa from comment #21)
> (In reply to Said Abou-Hallawa from comment #19)
> > (In reply to Said Abou-Hallawa from comment #18)
> > > Created attachment 413740 [details]
> > > Patch
> > 
> > Three notes about this patch:
> > 
> > 1. PDFDocumentImage will be broken but the rest of images should be fine
> > with this patch. Once it is landed I am going to file a bug for
> > PDFDocumentImage.
> > 
> > 2. The following DisplayList items should be removed in a follow-up patch
> > since they are used with this patch:
> > 
> >     DrawImage,
> >     DrawTiledImage,
> >     DrawTiledScaledImage,
> > 
> > 3. Drawing a canvas into another canvas is blocked by bug 218773.
> 
> A fourth comment
> 
> 4. I think the class ImageDataReference can be replaced by just
> 
> using ImageDataReference = RefPtr<ImageData>;

5. Maybe it is time to add something like DisplayList::ResourceCache and have both
RemoteResourceCacheProxy and RemoteResourceCache inherit from it.

namespace DisplayList {

class ResourceCache {
public:
    virtual void cacheImageBuffer(Ref<ImageBuffer>&&);
    virtual void releaseImageBuffer(WebCore::RenderingResourceIdentifier);
    ImageBuffer* cachedImageBuffer(RenderingResourceIdentifier);

    virtual void cacheNativeImage(WebCore::NativeImage&);
    virtual void releaseNativeImage(WebCore::RenderingResourceIdentifier);

    const ImageBufferHashMap& imageBuffers() const { return m_imageBuffers; }
    const NativeImageHashMap& nativeImages() const { return m_nativeImages; }

private:
    ImageBufferHashMap m_imageBuffers;
    NativeImageHashMap m_nativeImages;
};

}

And a pointer to ResourceCache can be passed to DisplayList::Replayer.
Comment 27 Said Abou-Hallawa 2020-11-10 18:37:29 PST
Created attachment 413761 [details]
Patch
Comment 28 Simon Fraser (smfr) 2020-11-10 19:28:55 PST
Comment on attachment 413761 [details]
Patch

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

> Source/WebCore/platform/graphics/NativeImage.cpp:48
> +    if (m_observer)
> +        m_observer->releaseNativeImage(m_renderingResourceIdentifier);

The observer is holding a ref to the NativeImage, so this code will never get hit. I think you're leaking all the images.

> Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.messages.in:30
> +    CacheNativeImage(WebCore::NativeImageReference nativeImage)

I think it's deceptive to state that we can encode NativeImages like this. We can't losslessly encode PDF images, SVG Images etc. I think this should take ShareableBitmap and RenderingRsourceIdentifier arguments.

> Source/WebKit/GPUProcess/graphics/RemoteResourceCache.h:55
>      WebCore::ImageBufferHashMap m_imageBuffers;
> +    WebCore::NativeImageHashMap m_nativeImages;

At some point m_imageBuffers will go away, and m_nativeImages will be SharableBitmaps, right?
Comment 29 Said Abou-Hallawa 2020-11-10 23:01:06 PST
Created attachment 413786 [details]
Patch
Comment 30 Said Abou-Hallawa 2020-11-11 10:44:09 PST
The failure on iOS is happening because custom painting uses DisplayList for drawing. Because I removed recording the DrawImage, calling BitmapImage() is now allowed while the GraphicsContext is backed by a DisplayList::Recorder. And because allowSubsampling is allowed on iOS only, we end up calling the function BitmapImage::subsamplingLevelForScaleFactor() which expects a GraphicsContext with a valid platformContext(). I think the fix for this function is to check context.hasPlatformContext() before using context.platformContext().
Comment 31 Said Abou-Hallawa 2020-11-11 11:09:11 PST
Created attachment 413842 [details]
Patch
Comment 32 Said Abou-Hallawa 2020-11-11 11:56:56 PST
Created attachment 413847 [details]
Patch
Comment 33 Said Abou-Hallawa 2020-11-11 12:19:57 PST
Comment on attachment 413761 [details]
Patch

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

>> Source/WebCore/platform/graphics/NativeImage.cpp:48
>> +        m_observer->releaseNativeImage(m_renderingResourceIdentifier);
> 
> The observer is holding a ref to the NativeImage, so this code will never get hit. I think you're leaking all the images.

Yes you right. I also mistakenly replaced the type of RemoteResourceCacheProxy::m_imageBuffers from 

    using RemoteImageBufferProxyHashMap = HashMap<WebCore::RenderingResourceIdentifier, WebCore::ImageBuffer*>

to NativeImageHashMap which is 

    using ImageBufferHashMap = HashMap<RenderingResourceIdentifier, Ref<ImageBuffer>>;

So the NativeImage and the ImageBuffers were leaking when GPU rendering for canvas is enabled. I made RemoteResourceCacheProxy holds raw pointer for ImageBuffer and NativeImage and I made sure the destructor of NativeImage is being called when the decoded frame is destroyed.

>> Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.messages.in:30
>> +    CacheNativeImage(WebCore::NativeImageReference nativeImage)
> 
> I think it's deceptive to state that we can encode NativeImages like this. We can't losslessly encode PDF images, SVG Images etc. I think this should take ShareableBitmap and RenderingRsourceIdentifier arguments.

I do not fully understand this comment. I think:

1. We need to decode the PlatformImagePtr into a SharableBitmap inside the NativeImage. So encoding/decoding the NativeImage will be done by sending a Handle from WebP to GPUP.
2. We need to have CachePDFDocumentImage([no sure what should be here but maybe a SharedBuffer])
3. For the reset of the images they are already fixed by removing the recording from the GraphicsContext functions. For example, SVGImage should work if DOM rendering is enabled.

>> Source/WebKit/GPUProcess/graphics/RemoteResourceCache.h:55
>> +    WebCore::NativeImageHashMap m_nativeImages;
> 
> At some point m_imageBuffers will go away, and m_nativeImages will be SharableBitmaps, right?

m_imageBuffers have to stay since this is where the RemoteImageBuffers in the GPU side can live. The m_nativeImages have to stay as well but the underlying data will be a SharableBitmap instead of PlatformImagePtr. These two HashMaps are used to

1. Keep the resources alive in the GPU side
2. Resolve the renderingResourceIdentifier in DrawImageBuffer and DrawNativeImage to a resource when replaying back the DisplayList.
Comment 34 Simon Fraser (smfr) 2020-11-11 13:46:15 PST
Comment on attachment 413847 [details]
Patch

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

> Source/WebCore/platform/graphics/NativeImage.h:61
> +    void setRenderingResourceIdentifier(RenderingResourceIdentifier renderingResourceIdentifier) { m_renderingResourceIdentifier = renderingResourceIdentifier; }

It's a bit weird to have m_renderingResourceIdentifier be initialized to the generated value, then set here. Should RenderingResourceIdentifier be passed into the constructor as an Optional<>?

> Source/WebCore/platform/graphics/displaylists/DisplayListItems.h:1300
> +    RenderingResourceIdentifier m_renderingResourceIdentifier;

We can all this m_imageIdentifier here

> Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp:201
> +    if (!m_delegate)
> +        m_displayList.cacheNativeImage(image);
> +    else
> +        m_delegate->cacheNativeImage(image);

This is a bit confusing. It assumes knowledge of delegate behavior.

> Source/WebKit/WebProcess/GPU/graphics/RemoteImageBufferProxy.h:65
>          if (!m_remoteRenderingBackendProxy)
>              return;
>          flushDrawingContext();
> +        m_remoteRenderingBackendProxy->remoteResourceCacheProxy().releaseImageBuffer(m_renderingResourceIdentifier);
>          m_remoteRenderingBackendProxy->releaseRemoteResource(m_renderingResourceIdentifier);

Please move to the .cpp file.

> Source/WebKit/WebProcess/GPU/graphics/RemoteImageBufferProxy.h:89
>      {
>          ASSERT(m_remoteRenderingBackendProxy);
> +        m_remoteRenderingBackendProxy->remoteResourceCacheProxy().cacheImageBuffer(*this);
> +
>          m_drawingContext.displayList().setItemBufferClient(this);
>          m_drawingContext.displayList().setTracksDrawingItemExtents(false);
>      }

Move to the cpp file.

> Source/WebKit/WebProcess/GPU/graphics/RemoteImageBufferProxy.h:191
> +    void cacheNativeImage(WebCore::NativeImage& image) override
> +    {
> +        if (m_remoteRenderingBackendProxy)
> +            m_remoteRenderingBackendProxy->remoteResourceCacheProxy().cacheNativeImage(image);
> +    }

Put in the cpp file.

> Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.h:54
> +    using ImageBufferHashMap = HashMap<WebCore::RenderingResourceIdentifier, WebCore::ImageBuffer*>;
> +    using NativeImageHashMap = HashMap<WebCore::RenderingResourceIdentifier, WebCore::NativeImage*>;

Can we use WeakPtr here?
Comment 35 Said Abou-Hallawa 2020-11-11 15:37:53 PST
Created attachment 413875 [details]
Patch
Comment 36 Said Abou-Hallawa 2020-11-11 16:15:42 PST
Comment on attachment 413847 [details]
Patch

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

>> Source/WebCore/platform/graphics/NativeImage.h:61
>> +    void setRenderingResourceIdentifier(RenderingResourceIdentifier renderingResourceIdentifier) { m_renderingResourceIdentifier = renderingResourceIdentifier; }
> 
> It's a bit weird to have m_renderingResourceIdentifier be initialized to the generated value, then set here. Should RenderingResourceIdentifier be passed into the constructor as an Optional<>?

This function was removed. Instead a new create and a new constructor were added to take PlatformImagePtr and RenderingResourceIdentifier.

>> Source/WebCore/platform/graphics/displaylists/DisplayListItems.h:1300
>> +    RenderingResourceIdentifier m_renderingResourceIdentifier;
> 
> We can all this m_imageIdentifier here

The name of this member was changed to m_imageIdentifier.

>> Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp:201
>> +        m_delegate->cacheNativeImage(image);
> 
> This is a bit confusing. It assumes knowledge of delegate behavior.

Yes this is right. I was trying to save a call to DisplayList::cacheNativeImage() but calling it unconditionally is cleaner and can make the DisplayList re-playable by itself.

>> Source/WebKit/WebProcess/GPU/graphics/RemoteImageBufferProxy.h:191
>> +    }
> 
> Put in the cpp file.

There is no cpp file for this header file.

>> Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.h:54
>> +    using NativeImageHashMap = HashMap<WebCore::RenderingResourceIdentifier, WebCore::NativeImage*>;
> 
> Can we use WeakPtr here?

Yes we can. Done.
Comment 37 EWS 2020-11-11 17:00:15 PST
Committed r269708: <https://trac.webkit.org/changeset/269708>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 413875 [details].