Title: [291817] trunk
Revision
291817
Author
grao...@webkit.org
Date
2022-03-24 15:27:19 -0700 (Thu, 24 Mar 2022)

Log Message

DOM GPUP: paintSystemPreviewBadge (AR QuickLook element badge)
https://bugs.webkit.org/show_bug.cgi?id=238295
rdar://83580608

Reviewed by Dean Jackson.

Source/WebCore:

Add a new SystemImage subclass to deal with the ARKit badge, moving the custom drawing code under
RenderThemeIOS::paintSystemPreviewBadge() to ARKitBadgeSystemImage::draw().

To facilitate this, we must also have ARKitBadgeSystemImage wrap the input Image provided to
RenderThemeIOS::paintSystemPreviewBadge() so that the CoreImage filters are applied correctly.

Finally, we remove some use of `using namespace WebCore` in WebSpeechRecognizerTask and
WebSpeechRecognizerTaskMock since it caused some unified build failures.

* Headers.cmake:
* Modules/speech/cocoa/WebSpeechRecognizerTask.mm:
(-[WebSpeechRecognizerTaskImpl initWithIdentifier:locale:doMultipleRecognitions:reportInterimResults:maxAlternatives:delegateCallback:]):
(-[WebSpeechRecognizerTaskImpl callbackWithTranscriptions:isFinal:]):
(-[WebSpeechRecognizerTaskImpl sendSpeechStartIfNeeded]):
(-[WebSpeechRecognizerTaskImpl sendSpeechEndIfNeeded]):
(-[WebSpeechRecognizerTaskImpl sendEndIfNeeded]):
(-[WebSpeechRecognizerTaskImpl speechRecognizer:availabilityDidChange:]):
(-[WebSpeechRecognizerTaskImpl speechRecognitionTask:didFinishSuccessfully:]):
(-[WebSpeechRecognizerTask initWithIdentifier:locale:doMultipleRecognitions:reportInterimResults:maxAlternatives:delegateCallback:]):
* Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm:
(-[WebSpeechRecognizerTaskMock initWithIdentifier:locale:doMultipleRecognitions:reportInterimResults:maxAlternatives:delegateCallback:]):
(-[WebSpeechRecognizerTaskMock audioSamplesAvailable:]):
(-[WebSpeechRecognizerTaskMock abort]):
* Modules/system-preview/ARKitBadgeSystemImage.h: Added.
(WebCore::ARKitBadgeSystemImage::encode const):
(WebCore::ARKitBadgeSystemImage::decode):
(isType):
* Modules/system-preview/ARKitBadgeSystemImage.mm: Added.
(WebCore::arKitBundle):
(WebCore::loadARKitPDFPage):
(WebCore::systemPreviewLogo):
(WebCore::ARKitBadgeSystemImage::draw const):
* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/SystemImage.h:
* platform/graphics/displaylists/DisplayListRecorder.cpp:
(WebCore::DisplayList::Recorder::drawSystemImage):
* rendering/RenderThemeIOS.h:
* rendering/RenderThemeIOS.mm:
(WebCore::RenderThemeIOS::paintSystemPreviewBadge):
(WebCore::arKitBundle): Deleted.
(WebCore::loadARKitPDFPage): Deleted.
(WebCore::systemPreviewLogo): Deleted.

Source/WebKit:

Make sure we restore the Image on the ARKitBadgeSystemImage before we attempt to draw it.

* GPUProcess/graphics/RemoteDisplayListRecorder.cpp:
(WebKit::RemoteDisplayListRecorder::drawSystemImage):
* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<Ref<SystemImage>>::encode):
(IPC::ArgumentCoder<Ref<SystemImage>>::decode):

LayoutTests:

The system-preview/badge.html test now passes reliably with DOM GPUP enabled,
which incidentally fixes bug 236922.

* platform/ios-wk2/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (291816 => 291817)


--- trunk/LayoutTests/ChangeLog	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/LayoutTests/ChangeLog	2022-03-24 22:27:19 UTC (rev 291817)
@@ -1,3 +1,16 @@
+2022-03-24  Antoine Quint  <grao...@webkit.org>
+
+        DOM GPUP: paintSystemPreviewBadge (AR QuickLook element badge)
+        https://bugs.webkit.org/show_bug.cgi?id=238295
+        rdar://83580608
+
+        Reviewed by Dean Jackson.
+
+        The system-preview/badge.html test now passes reliably with DOM GPUP enabled,
+        which incidentally fixes bug 236922.
+
+        * platform/ios-wk2/TestExpectations:
+
 2022-03-24  Kate Cheney  <katherine_che...@apple.com>
 
         REGRESSION (Safari 15.4): Nonce from link isn't used when loading style sheet

Modified: trunk/LayoutTests/platform/ios-wk2/TestExpectations (291816 => 291817)


--- trunk/LayoutTests/platform/ios-wk2/TestExpectations	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/LayoutTests/platform/ios-wk2/TestExpectations	2022-03-24 22:27:19 UTC (rev 291817)
@@ -2250,9 +2250,6 @@
 webkit.org/b/236921 imported/w3c/web-platform-tests/css/css-writing-modes/vertical-alignment-vlr-023.xht [ ImageOnlyFailure ]
 webkit.org/b/236921 imported/w3c/web-platform-tests/css/css-writing-modes/vertical-alignment-vrl-022.xht [ ImageOnlyFailure ]
 
-# Colors are significantly different enough
-webkit.org/b/236922 system-preview/badge.html [ ImageOnlyFailure ]
-
 # No/bad colored boxes
 webkit.org/b/236923 fast/css/paint-order-shadow.html [ ImageOnlyFailure ]
 webkit.org/b/236923 imported/blink/svg/text/obb-paintserver.html [ ImageOnlyFailure ]

Modified: trunk/Source/WebCore/ChangeLog (291816 => 291817)


--- trunk/Source/WebCore/ChangeLog	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/ChangeLog	2022-03-24 22:27:19 UTC (rev 291817)
@@ -1,3 +1,55 @@
+2022-03-24  Antoine Quint  <grao...@webkit.org>
+
+        DOM GPUP: paintSystemPreviewBadge (AR QuickLook element badge)
+        https://bugs.webkit.org/show_bug.cgi?id=238295
+        rdar://83580608
+
+        Reviewed by Dean Jackson.
+
+        Add a new SystemImage subclass to deal with the ARKit badge, moving the custom drawing code under
+        RenderThemeIOS::paintSystemPreviewBadge() to ARKitBadgeSystemImage::draw().
+
+        To facilitate this, we must also have ARKitBadgeSystemImage wrap the input Image provided to
+        RenderThemeIOS::paintSystemPreviewBadge() so that the CoreImage filters are applied correctly.
+
+        Finally, we remove some use of `using namespace WebCore` in WebSpeechRecognizerTask and
+        WebSpeechRecognizerTaskMock since it caused some unified build failures.
+
+        * Headers.cmake:
+        * Modules/speech/cocoa/WebSpeechRecognizerTask.mm:
+        (-[WebSpeechRecognizerTaskImpl initWithIdentifier:locale:doMultipleRecognitions:reportInterimResults:maxAlternatives:delegateCallback:]):
+        (-[WebSpeechRecognizerTaskImpl callbackWithTranscriptions:isFinal:]):
+        (-[WebSpeechRecognizerTaskImpl sendSpeechStartIfNeeded]):
+        (-[WebSpeechRecognizerTaskImpl sendSpeechEndIfNeeded]):
+        (-[WebSpeechRecognizerTaskImpl sendEndIfNeeded]):
+        (-[WebSpeechRecognizerTaskImpl speechRecognizer:availabilityDidChange:]):
+        (-[WebSpeechRecognizerTaskImpl speechRecognitionTask:didFinishSuccessfully:]):
+        (-[WebSpeechRecognizerTask initWithIdentifier:locale:doMultipleRecognitions:reportInterimResults:maxAlternatives:delegateCallback:]):
+        * Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm:
+        (-[WebSpeechRecognizerTaskMock initWithIdentifier:locale:doMultipleRecognitions:reportInterimResults:maxAlternatives:delegateCallback:]):
+        (-[WebSpeechRecognizerTaskMock audioSamplesAvailable:]):
+        (-[WebSpeechRecognizerTaskMock abort]):
+        * Modules/system-preview/ARKitBadgeSystemImage.h: Added.
+        (WebCore::ARKitBadgeSystemImage::encode const):
+        (WebCore::ARKitBadgeSystemImage::decode):
+        (isType):
+        * Modules/system-preview/ARKitBadgeSystemImage.mm: Added.
+        (WebCore::arKitBundle):
+        (WebCore::loadARKitPDFPage):
+        (WebCore::systemPreviewLogo):
+        (WebCore::ARKitBadgeSystemImage::draw const):
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/SystemImage.h:
+        * platform/graphics/displaylists/DisplayListRecorder.cpp:
+        (WebCore::DisplayList::Recorder::drawSystemImage):
+        * rendering/RenderThemeIOS.h:
+        * rendering/RenderThemeIOS.mm:
+        (WebCore::RenderThemeIOS::paintSystemPreviewBadge):
+        (WebCore::arKitBundle): Deleted.
+        (WebCore::loadARKitPDFPage): Deleted.
+        (WebCore::systemPreviewLogo): Deleted.
+
 2022-03-24  Kate Cheney  <katherine_che...@apple.com>
 
         REGRESSION (Safari 15.4): Nonce from link isn't used when loading style sheet

Modified: trunk/Source/WebCore/Headers.cmake (291816 => 291817)


--- trunk/Source/WebCore/Headers.cmake	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/Headers.cmake	2022-03-24 22:27:19 UTC (rev 291817)
@@ -331,6 +331,8 @@
     Modules/streams/ReadableStreamSink.h
     Modules/streams/ReadableStreamSource.h
 
+    Modules/system-preview/ARKitBadgeSystemImage.h
+
     Modules/web-locks/WebLockIdentifier.h
     Modules/web-locks/WebLockManagerSnapshot.h
     Modules/web-locks/WebLockMode.h

Modified: trunk/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm (291816 => 291817)


--- trunk/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm	2022-03-24 22:27:19 UTC (rev 291817)
@@ -37,14 +37,12 @@
 // Set the maximum duration to be an hour; we can adjust this if needed.
 static constexpr size_t maximumRecognitionDuration = 60 * 60;
 
-using namespace WebCore;
-
 NS_ASSUME_NONNULL_BEGIN
 
 @interface WebSpeechRecognizerTaskImpl : NSObject<SFSpeechRecognitionTaskDelegate, SFSpeechRecognizerDelegate> {
 @private
-    SpeechRecognitionConnectionClientIdentifier _identifier;
-    BlockPtr<void(const SpeechRecognitionUpdate&)> _delegateCallback;
+    WebCore::SpeechRecognitionConnectionClientIdentifier _identifier;
+    BlockPtr<void(const WebCore::SpeechRecognitionUpdate&)> _delegateCallback;
     bool _doMultipleRecognitions;
     uint64_t _maxAlternatives;
     RetainPtr<SFSpeechRecognizer> _recognizer;
@@ -55,7 +53,7 @@
     bool _hasSentEnd;
 }
 
-- (instancetype)initWithIdentifier:(SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const SpeechRecognitionUpdate&))callback;
+- (instancetype)initWithIdentifier:(WebCore::SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const WebCore::SpeechRecognitionUpdate&))callback;
 - (void)callbackWithTranscriptions:(NSArray<SFTranscription *> *)transcriptions isFinal:(BOOL)isFinal;
 - (void)audioSamplesAvailable:(CMSampleBufferRef)sampleBuffer;
 - (void)abort;
@@ -68,7 +66,7 @@
 
 @implementation WebSpeechRecognizerTaskImpl
 
-- (instancetype)initWithIdentifier:(SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const SpeechRecognitionUpdate&))callback
+- (instancetype)initWithIdentifier:(WebCore::SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const WebCore::SpeechRecognitionUpdate&))callback
 {
     if (!(self = [super init]))
         return nil;
@@ -115,7 +113,7 @@
 
 - (void)callbackWithTranscriptions:(NSArray<SFTranscription *> *)transcriptions isFinal:(BOOL)isFinal
 {
-    Vector<SpeechRecognitionAlternativeData> alternatives;
+    Vector<WebCore::SpeechRecognitionAlternativeData> alternatives;
     alternatives.reserveInitialCapacity(_maxAlternatives);
     for (SFTranscription* transcription in transcriptions) {
         // FIXME: <rdar://73629573> get confidence of SFTranscription when possible.
@@ -124,11 +122,11 @@
             double confidence = [segment confidence];
             maxConfidence = maxConfidence < confidence ? confidence : maxConfidence;
         }
-        alternatives.uncheckedAppend(SpeechRecognitionAlternativeData { [transcription formattedString], maxConfidence });
+        alternatives.uncheckedAppend(WebCore::SpeechRecognitionAlternativeData { [transcription formattedString], maxConfidence });
         if (alternatives.size() == _maxAlternatives)
             break;
     }
-    _delegateCallback(SpeechRecognitionUpdate::createResult(_identifier, { SpeechRecognitionResultData { WTFMove(alternatives), !!isFinal } }));
+    _delegateCallback(WebCore::SpeechRecognitionUpdate::createResult(_identifier, { WebCore::SpeechRecognitionResultData { WTFMove(alternatives), !!isFinal } }));
 }
 
 - (void)audioSamplesAvailable:(CMSampleBufferRef)sampleBuffer
@@ -175,7 +173,7 @@
         return;
 
     _hasSentSpeechStart = true;
-    _delegateCallback(SpeechRecognitionUpdate::create(_identifier, SpeechRecognitionUpdateType::SpeechStart));
+    _delegateCallback(WebCore::SpeechRecognitionUpdate::create(_identifier, WebCore::SpeechRecognitionUpdateType::SpeechStart));
 }
 
 - (void)sendSpeechEndIfNeeded
@@ -184,7 +182,7 @@
         return;
 
     _hasSentSpeechEnd = true;
-    _delegateCallback(SpeechRecognitionUpdate::create(_identifier, SpeechRecognitionUpdateType::SpeechEnd));
+    _delegateCallback(WebCore::SpeechRecognitionUpdate::create(_identifier, WebCore::SpeechRecognitionUpdateType::SpeechEnd));
 }
 
 - (void)sendEndIfNeeded
@@ -193,7 +191,7 @@
         return;
 
     _hasSentEnd = true;
-    _delegateCallback(SpeechRecognitionUpdate::create(_identifier, SpeechRecognitionUpdateType::End));
+    _delegateCallback(WebCore::SpeechRecognitionUpdate::create(_identifier, WebCore::SpeechRecognitionUpdateType::End));
 }
 
 #pragma mark SFSpeechRecognizerDelegate
@@ -205,8 +203,8 @@
     if (available || !_task)
         return;
 
-    auto error = SpeechRecognitionError { SpeechRecognitionErrorType::ServiceNotAllowed, "Speech recognition service becomes unavailable"_s };
-    _delegateCallback(SpeechRecognitionUpdate::createError(_identifier, WTFMove(error)));
+    auto error = WebCore::SpeechRecognitionError { WebCore::SpeechRecognitionErrorType::ServiceNotAllowed, "Speech recognition service becomes unavailable"_s };
+    _delegateCallback(WebCore::SpeechRecognitionUpdate::createError(_identifier, WTFMove(error)));
 }
 
 #pragma mark SFSpeechRecognitionTaskDelegate
@@ -243,8 +241,8 @@
     ASSERT(isMainThread());
 
     if (!successfully) {
-        auto error = SpeechRecognitionError { SpeechRecognitionErrorType::Aborted, task.error.localizedDescription };
-        _delegateCallback(SpeechRecognitionUpdate::createError(_identifier, WTFMove(error)));
+        auto error = WebCore::SpeechRecognitionError { WebCore::SpeechRecognitionErrorType::Aborted, task.error.localizedDescription };
+        _delegateCallback(WebCore::SpeechRecognitionUpdate::createError(_identifier, WTFMove(error)));
     }
     
     [self sendEndIfNeeded];
@@ -254,7 +252,7 @@
 
 @implementation WebSpeechRecognizerTask
 
-- (instancetype)initWithIdentifier:(SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const SpeechRecognitionUpdate&))callback
+- (instancetype)initWithIdentifier:(WebCore::SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const WebCore::SpeechRecognitionUpdate&))callback
 {
     if (!(self = [super init]))
         return nil;

Modified: trunk/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm (291816 => 291817)


--- trunk/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm	2022-03-24 22:27:19 UTC (rev 291817)
@@ -28,13 +28,11 @@
 
 #if HAVE(SPEECHRECOGNIZER)
 
-using namespace WebCore;
-
 NS_ASSUME_NONNULL_BEGIN
 
 @implementation WebSpeechRecognizerTaskMock
 
-- (instancetype)initWithIdentifier:(SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const SpeechRecognitionUpdate&))callback
+- (instancetype)initWithIdentifier:(WebCore::SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const WebCore::SpeechRecognitionUpdate&))callback
 {
     UNUSED_PARAM(localeIdentifier);
     UNUSED_PARAM(interimResults);
@@ -59,12 +57,12 @@
     
     if (!_hasSentSpeechStart) {
         _hasSentSpeechStart = true;
-        _delegateCallback(SpeechRecognitionUpdate::create(_identifier, SpeechRecognitionUpdateType::SpeechStart));
+        _delegateCallback(WebCore::SpeechRecognitionUpdate::create(_identifier, WebCore::SpeechRecognitionUpdateType::SpeechStart));
     }
 
     // Fake some recognition results.
-    SpeechRecognitionAlternativeData alternative { "Test", 1.0 };
-    _delegateCallback(SpeechRecognitionUpdate::createResult(_identifier, { SpeechRecognitionResultData { { WTFMove(alternative) }, true } }));
+    WebCore::SpeechRecognitionAlternativeData alternative { "Test", 1.0 };
+    _delegateCallback(WebCore::SpeechRecognitionUpdate::createResult(_identifier, { WebCore::SpeechRecognitionResultData { { WTFMove(alternative) }, true } }));
 
     if (!_doMultipleRecognitions)
         [self abort];
@@ -78,10 +76,10 @@
 
     if (!_hasSentSpeechEnd && _hasSentSpeechStart) {
         _hasSentSpeechEnd = true;
-        _delegateCallback(SpeechRecognitionUpdate::create(_identifier, SpeechRecognitionUpdateType::SpeechEnd));
+        _delegateCallback(WebCore::SpeechRecognitionUpdate::create(_identifier, WebCore::SpeechRecognitionUpdateType::SpeechEnd));
     }
 
-    _delegateCallback(SpeechRecognitionUpdate::create(_identifier, SpeechRecognitionUpdateType::End));
+    _delegateCallback(WebCore::SpeechRecognitionUpdate::create(_identifier, WebCore::SpeechRecognitionUpdateType::End));
 }
 
 - (void)stop

Added: trunk/Source/WebCore/Modules/system-preview/ARKitBadgeSystemImage.h (0 => 291817)


--- trunk/Source/WebCore/Modules/system-preview/ARKitBadgeSystemImage.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/system-preview/ARKitBadgeSystemImage.h	2022-03-24 22:27:19 UTC (rev 291817)
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if USE(SYSTEM_PREVIEW)
+
+#include "NativeImage.h"
+#include "SystemImage.h"
+#include <optional>
+#include <wtf/Forward.h>
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
+
+OBJC_CLASS CIContext;
+
+namespace WebCore {
+
+class WEBCORE_EXPORT ARKitBadgeSystemImage final : public SystemImage {
+public:
+    static Ref<ARKitBadgeSystemImage> create(Image& image)
+    {
+        return adoptRef(*new ARKitBadgeSystemImage(image));
+    }
+
+    static Ref<ARKitBadgeSystemImage> create(RenderingResourceIdentifier renderingResourceIdentifier, FloatSize size)
+    {
+        return adoptRef(*new ARKitBadgeSystemImage(renderingResourceIdentifier, size));
+    }
+
+    virtual ~ARKitBadgeSystemImage() = default;
+
+    void draw(GraphicsContext&, const FloatRect&) const final;
+
+    Image* image() const { return m_image.get(); }
+    void setImage(Image& image) { m_image = &image; }
+
+    RenderingResourceIdentifier imageIdentifier() const { return m_renderingResourceIdentifier; }
+
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static std::optional<Ref<ARKitBadgeSystemImage>> decode(Decoder&);
+
+private:
+    ARKitBadgeSystemImage(Image& image)
+        : SystemImage(SystemImageType::ARKitBadge)
+        , m_image(&image)
+        , m_imageSize(image.size())
+    {
+    }
+
+    ARKitBadgeSystemImage(RenderingResourceIdentifier renderingResourceIdentifier, FloatSize size)
+        : SystemImage(SystemImageType::ARKitBadge)
+        , m_renderingResourceIdentifier(renderingResourceIdentifier)
+        , m_imageSize(size)
+    {
+    }
+
+    RefPtr<Image> m_image;
+    RenderingResourceIdentifier m_renderingResourceIdentifier;
+    FloatSize m_imageSize;
+};
+
+template<class Encoder>
+void ARKitBadgeSystemImage::encode(Encoder& encoder) const
+{
+    ASSERT(m_image);
+    ASSERT(m_image->nativeImage());
+    encoder << m_image->nativeImage()->renderingResourceIdentifier();
+    encoder << m_imageSize;
+}
+
+template<class Decoder>
+std::optional<Ref<ARKitBadgeSystemImage>> ARKitBadgeSystemImage::decode(Decoder& decoder)
+{
+    std::optional<RenderingResourceIdentifier> renderingResourceIdentifier;
+    decoder >> renderingResourceIdentifier;
+    if (!renderingResourceIdentifier)
+        return std::nullopt;
+
+    std::optional<FloatSize> imageSize;
+    decoder >> imageSize;
+    if (!imageSize)
+        return std::nullopt;
+
+    return ARKitBadgeSystemImage::create(WTFMove(*renderingResourceIdentifier), WTFMove(*imageSize));
+}
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ARKitBadgeSystemImage)
+    static bool isType(const WebCore::SystemImage& systemImage) { return systemImage.systemImageType() == WebCore::SystemImageType::ARKitBadge; }
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif // USE(SYSTEM_PREVIEW)

Added: trunk/Source/WebCore/Modules/system-preview/ARKitBadgeSystemImage.mm (0 => 291817)


--- trunk/Source/WebCore/Modules/system-preview/ARKitBadgeSystemImage.mm	                        (rev 0)
+++ trunk/Source/WebCore/Modules/system-preview/ARKitBadgeSystemImage.mm	2022-03-24 22:27:19 UTC (rev 291817)
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "ARKitBadgeSystemImage.h"
+
+#if USE(SYSTEM_PREVIEW)
+
+#import "ColorSpaceCG.h"
+#import "FloatRect.h"
+#import "GeometryUtilities.h"
+#import "GraphicsContext.h"
+#import "IOSurface.h"
+#import <CoreGraphics/CoreGraphics.h>
+#import <CoreImage/CoreImage.h>
+#import <wtf/NeverDestroyed.h>
+#import <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+static NSBundle *arKitBundle()
+{
+    static NSBundle *arKitBundle;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        arKitBundle = []() {
+#if PLATFORM(IOS_FAMILY_SIMULATOR)
+            dlopen("/System/Library/PrivateFrameworks/AssetViewer.framework/AssetViewer", RTLD_NOW);
+            return [NSBundle bundleForClass:NSClassFromString(@"ASVThumbnailView")];
+#else
+            return [NSBundle bundleWithURL:[NSURL fileURLWithPath:@"/System/Library/PrivateFrameworks/AssetViewer.framework"]];
+#endif
+        }();
+    });
+    return arKitBundle;
+}
+
+static RetainPtr<CGPDFPageRef> loadARKitPDFPage(NSString *imageName)
+{
+    NSURL *url = "" URLForResource:imageName withExtension:@"pdf"];
+    if (!url)
+        return nullptr;
+    auto document = adoptCF(CGPDFDocumentCreateWithURL((CFURLRef)url));
+    if (!document)
+        return nullptr;
+    if (!CGPDFDocumentGetNumberOfPages(document.get()))
+        return nullptr;
+    return CGPDFDocumentGetPage(document.get(), 1);
+}
+
+static RetainPtr<CGPDFPageRef> systemPreviewLogo()
+{
+    static NeverDestroyed<RetainPtr<CGPDFPageRef>> logoPage;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        logoPage.get() = loadARKitPDFPage(@"ARKitBadge");
+    });
+    return logoPage;
+}
+
+void ARKitBadgeSystemImage::draw(GraphicsContext& graphicsContext, const FloatRect& rect) const
+{
+    auto page = systemPreviewLogo();
+    if (!page)
+        return;
+
+    static const int largeBadgeDimension = 70;
+    static const int largeBadgeOffset = 20;
+
+    static const int smallBadgeDimension = 35;
+    static const int smallBadgeOffset = 8;
+
+    static const int minimumSizeForLargeBadge = 240;
+
+    bool useSmallBadge = rect.width() < minimumSizeForLargeBadge || rect.height() < minimumSizeForLargeBadge;
+    int badgeOffset = useSmallBadge ? smallBadgeOffset : largeBadgeOffset;
+    int badgeDimension = useSmallBadge ? smallBadgeDimension : largeBadgeDimension;
+
+    int minimumDimension = badgeDimension + 2 * badgeOffset;
+    if (rect.width() < minimumDimension || rect.height() < minimumDimension)
+        return;
+
+    CGRect absoluteBadgeRect = CGRectMake(rect.x() + rect.width() - badgeDimension - badgeOffset, rect.y() + badgeOffset, badgeDimension, badgeDimension);
+    CGRect insetBadgeRect = CGRectMake(rect.width() - badgeDimension - badgeOffset, badgeOffset, badgeDimension, badgeDimension);
+    CGRect badgeRect = CGRectMake(0, 0, badgeDimension, badgeDimension);
+
+    if (!m_image || !m_image->nativeImage())
+        return;
+
+    CIImage *inputImage = [CIImage imageWithCGImage:m_image->nativeImage()->platformImage().get()];
+
+    // Create a circle to be used for the clipping path in the badge, as well as the drop shadow.
+    RetainPtr<CGPathRef> circle = adoptCF(CGPathCreateWithRoundedRect(absoluteBadgeRect, badgeDimension / 2, badgeDimension / 2, nullptr));
+
+    if (graphicsContext.paintingDisabled())
+        return;
+
+    GraphicsContextStateSaver stateSaver(graphicsContext);
+
+    CGContextRef ctx = graphicsContext.platformContext();
+    if (!ctx)
+        return;
+
+    CGContextSaveGState(ctx);
+
+    // Draw a drop shadow around the circle.
+    // Use the GraphicsContext function, because it calculates the blur radius in context space,
+    // rather than screen space.
+    constexpr auto shadowColor = Color::black.colorWithAlphaByte(26);
+    graphicsContext.setShadow(FloatSize { }, 16, shadowColor);
+
+    // The circle must have an alpha channel value of 1 for the shadow color to appear.
+    CGFloat circleColorComponents[4] = { 0, 0, 0, 1 };
+    RetainPtr<CGColorRef> circleColor = adoptCF(CGColorCreate(sRGBColorSpaceRef(), circleColorComponents));
+    CGContextSetFillColorWithColor(ctx, circleColor.get());
+
+    // Clip out the circle to only show the shadow.
+    CGContextBeginPath(ctx);
+    CGContextAddRect(ctx, rect);
+    CGContextAddPath(ctx, circle.get());
+    CGContextClosePath(ctx);
+    CGContextEOClip(ctx);
+
+    // Draw a slightly smaller circle with a shadow, otherwise we'll see a fringe of the solid
+    // black circle around the edges of the clipped path below.
+    CGContextBeginPath(ctx);
+    CGRect slightlySmallerAbsoluteBadgeRect = CGRectMake(absoluteBadgeRect.origin.x + 0.5, absoluteBadgeRect.origin.y + 0.5, badgeDimension - 1, badgeDimension - 1);
+    RetainPtr<CGPathRef> slightlySmallerCircle = adoptCF(CGPathCreateWithRoundedRect(slightlySmallerAbsoluteBadgeRect, slightlySmallerAbsoluteBadgeRect.size.width / 2, slightlySmallerAbsoluteBadgeRect.size.height / 2, nullptr));
+    CGContextAddPath(ctx, slightlySmallerCircle.get());
+    CGContextClosePath(ctx);
+    CGContextFillPath(ctx);
+
+    CGContextRestoreGState(ctx);
+
+    // Draw the blurred backdrop. Scale from intrinsic size to render size.
+    CGAffineTransform transform = CGAffineTransformIdentity;
+    transform = CGAffineTransformScale(transform, rect.width() / m_imageSize.width(), rect.height() / m_imageSize.height());
+    CIImage *scaledImage = [inputImage imageByApplyingTransform:transform];
+
+    // CoreImage coordinates are y-up, so we need to flip the badge rectangle within the image frame.
+    CGRect flippedInsetBadgeRect = CGRectMake(insetBadgeRect.origin.x, rect.height() - insetBadgeRect.origin.y - insetBadgeRect.size.height, badgeDimension, badgeDimension);
+
+    // Create a cropped region with pixel values extending outwards.
+    CIImage *clampedImage = [scaledImage imageByClampingToRect:flippedInsetBadgeRect];
+
+    // Blur.
+    CIImage *blurredImage = [clampedImage imageByApplyingGaussianBlurWithSigma:10];
+
+    // Saturate.
+    CIFilter *saturationFilter = [CIFilter filterWithName:@"CIColorControls"];
+    [saturationFilter setValue:blurredImage forKey:kCIInputImageKey];
+    [saturationFilter setValue:@1.8 forKey:kCIInputSaturationKey];
+
+    // Tint.
+    CIFilter *tintFilter1 = [CIFilter filterWithName:@"CIConstantColorGenerator"];
+    CIColor *tintColor1 = [CIColor colorWithRed:1 green:1 blue:1 alpha:0.18];
+    [tintFilter1 setValue:tintColor1 forKey:kCIInputColorKey];
+
+    // Blend the tint with the saturated output.
+    CIFilter *sourceOverFilter = [CIFilter filterWithName:@"CISourceOverCompositing"];
+    [sourceOverFilter setValue:tintFilter1.outputImage forKey:kCIInputImageKey];
+    [sourceOverFilter setValue:saturationFilter.outputImage forKey:kCIInputBackgroundImageKey];
+
+    RetainPtr<CIContext> ciContext = [CIContext context];
+
+    RetainPtr<CGImageRef> cgImage;
+#if HAVE(IOSURFACE_COREIMAGE_SUPPORT)
+    // Crop the result to the badge location.
+    CIImage *croppedImage = [sourceOverFilter.outputImage imageByCroppingToRect:flippedInsetBadgeRect];
+    CIImage *translatedImage = [croppedImage imageByApplyingTransform:CGAffineTransformMakeTranslation(-flippedInsetBadgeRect.origin.x, -flippedInsetBadgeRect.origin.y)];
+
+    auto surfaceDimension = useSmallBadge ? smallBadgeDimension : largeBadgeDimension;
+    std::unique_ptr<IOSurface> badgeSurface = IOSurface::create({ surfaceDimension, surfaceDimension }, DestinationColorSpace::SRGB());
+    IOSurfaceRef surface = badgeSurface->surface();
+    [ciContext render:translatedImage toIOSurface:surface bounds:badgeRect colorSpace:sRGBColorSpaceRef()];
+    cgImage = useSmallBadge ? badgeSurface->createImage() : badgeSurface->createImage();
+#else
+    cgImage = adoptCF([ciContext createCGImage:sourceOverFilter.outputImage fromRect:flippedInsetBadgeRect]);
+#endif
+
+    // Before we render the result, we should clip to a circle around the badge rectangle.
+    CGContextSaveGState(ctx);
+    CGContextBeginPath(ctx);
+    CGContextAddPath(ctx, circle.get());
+    CGContextClosePath(ctx);
+    CGContextClip(ctx);
+
+    CGContextTranslateCTM(ctx, absoluteBadgeRect.origin.x, absoluteBadgeRect.origin.y);
+    CGContextTranslateCTM(ctx, 0, badgeDimension);
+    CGContextScaleCTM(ctx, 1, -1);
+    CGContextDrawImage(ctx, badgeRect, cgImage.get());
+
+    CGSize pdfSize = CGPDFPageGetBoxRect(page.get(), kCGPDFMediaBox).size;
+    CGFloat scaleX = badgeDimension / pdfSize.width;
+    CGFloat scaleY = badgeDimension / pdfSize.height;
+    CGContextScaleCTM(ctx, scaleX, scaleY);
+    CGContextDrawPDFPage(ctx, page.get());
+
+    CGContextFlush(ctx);
+    CGContextRestoreGState(ctx);
+}
+
+} // namespace WebCore
+
+#endif // USE(SYSTEM_PREVIEW)

Modified: trunk/Source/WebCore/SourcesCocoa.txt (291816 => 291817)


--- trunk/Source/WebCore/SourcesCocoa.txt	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/SourcesCocoa.txt	2022-03-24 22:27:19 UTC (rev 291817)
@@ -119,6 +119,7 @@
 Modules/speech/cocoa/SpeechRecognizerCocoa.mm
 Modules/speech/cocoa/WebSpeechRecognizerTask.mm
 Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm
+Modules/system-preview/ARKitBadgeSystemImage.mm
 Modules/webdatabase/cocoa/DatabaseManagerCocoa.mm
 accessibility/ios/AXObjectCacheIOS.mm
 accessibility/ios/AccessibilityObjectIOS.mm

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (291816 => 291817)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-03-24 22:27:19 UTC (rev 291817)
@@ -2310,6 +2310,7 @@
 		7156BCA121CA350F00534397 /* BasicEffectTiming.h in Headers */ = {isa = PBXBuildFile; fileRef = 7156BC9F21CA350600534397 /* BasicEffectTiming.h */; };
 		715AD7202050513200D592DC /* DeclarativeAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = 715AD71D2050512400D592DC /* DeclarativeAnimation.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		715AD7212050513F00D592DC /* CSSTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 7123C186204739BA00789392 /* CSSTransition.h */; };
+		716C4C3627EB60C900531467 /* ARKitBadgeSystemImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 716C4C3527EB608E00531467 /* ARKitBadgeSystemImage.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		71729F7B20F3BA4900801CE6 /* DocumentTimelineOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 71729F7A20F3BA3A00801CE6 /* DocumentTimelineOptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		71729F7E20F3BB4700801CE6 /* JSDocumentTimelineOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 71729F7C20F3BAB900801CE6 /* JSDocumentTimelineOptions.h */; };
 		7173694A275E0B5E003ADA9B /* CustomEffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 71A74B082759293600DE80BA /* CustomEffect.h */; };
@@ -11186,6 +11187,8 @@
 		716A55AB26FA349B00C96D69 /* range-button.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = "range-button.css"; sourceTree = "<group>"; };
 		716A55AD26FA349C00C96D69 /* volume-button.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode._javascript_; path = "volume-button.js"; sourceTree = "<group>"; };
 		716A55AE26FA349C00C96D69 /* range-button.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode._javascript_; path = "range-button.js"; sourceTree = "<group>"; };
+		716C4C3427EB608E00531467 /* ARKitBadgeSystemImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ARKitBadgeSystemImage.mm; sourceTree = "<group>"; };
+		716C4C3527EB608E00531467 /* ARKitBadgeSystemImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARKitBadgeSystemImage.h; sourceTree = "<group>"; };
 		716FA0D81DB26591007323CC /* airplay-button.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = "airplay-button.css"; sourceTree = "<group>"; };
 		716FA0D91DB26591007323CC /* airplay-button.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "airplay-button.js"; sourceTree = "<group>"; };
 		716FA0DA1DB26591007323CC /* airplay-placard.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "airplay-placard.js"; sourceTree = "<group>"; };
@@ -24665,6 +24668,15 @@
 			path = animation;
 			sourceTree = "<group>";
 		};
+		716C4C3327EB608E00531467 /* system-preview */ = {
+			isa = PBXGroup;
+			children = (
+				716C4C3527EB608E00531467 /* ARKitBadgeSystemImage.h */,
+				716C4C3427EB608E00531467 /* ARKitBadgeSystemImage.mm */,
+			);
+			path = "system-preview";
+			sourceTree = "<group>";
+		};
 		716FA0D71DB26591007323CC /* controls */ = {
 			isa = PBXGroup;
 			children = (
@@ -26175,6 +26187,7 @@
 				AA2A5AB716A485A400975A25 /* speech */,
 				93085DB326E0068E000EC6A7 /* storage */,
 				41A023EA1A39DB7900F722CF /* streams */,
+				716C4C3327EB608E00531467 /* system-preview */,
 				4644F7EA272A1C160055599E /* web-locks */,
 				FD315FA212B025B100C1A359 /* webaudio */,
 				57D8462A1FEAF57F00CA3682 /* webauthn */,
@@ -33598,6 +33611,7 @@
 				512DD8FD0D91E6AF000F89EE /* ArchiveFactory.h in Headers */,
 				512DD8FC0D91E6AF000F89EE /* ArchiveResource.h in Headers */,
 				512DD8F80D91E6AF000F89EE /* ArchiveResourceCollection.h in Headers */,
+				716C4C3627EB60C900531467 /* ARKitBadgeSystemImage.h in Headers */,
 				FD5686CA13AC180200B69C68 /* AsyncAudioDecoder.h in Headers */,
 				E1CDE9221501916900862CC5 /* AsyncFileStream.h in Headers */,
 				0FFD4D6118651FA300512F6E /* AsyncScrollingCoordinator.h in Headers */,

Modified: trunk/Source/WebCore/platform/graphics/SystemImage.h (291816 => 291817)


--- trunk/Source/WebCore/platform/graphics/SystemImage.h	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/platform/graphics/SystemImage.h	2022-03-24 22:27:19 UTC (rev 291817)
@@ -37,6 +37,9 @@
     ApplePayButton,
     ApplePayLogo,
 #endif
+#if USE(SYSTEM_PREVIEW)
+    ARKitBadge,
+#endif
 };
 
 class WEBCORE_EXPORT SystemImage : public RefCounted<SystemImage> {
@@ -69,6 +72,9 @@
         , WebCore::SystemImageType::ApplePayButton,
         WebCore::SystemImageType::ApplePayLogo
 #endif
+#if USE(SYSTEM_PREVIEW)
+        , WebCore::SystemImageType::ARKitBadge
+#endif
     >;
 };
 

Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp (291816 => 291817)


--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp	2022-03-24 22:27:19 UTC (rev 291817)
@@ -39,6 +39,10 @@
 #include <wtf/MathExtras.h>
 #include <wtf/text/TextStream.h>
 
+#if USE(SYSTEM_PREVIEW)
+#include "ARKitBadgeSystemImage.h"
+#endif
+
 namespace WebCore {
 namespace DisplayList {
 
@@ -188,6 +192,12 @@
 
 void Recorder::drawSystemImage(SystemImage& systemImage, const FloatRect& destinationRect)
 {
+#if USE(SYSTEM_PREVIEW)
+    if (is<ARKitBadgeSystemImage>(systemImage)) {
+        if (auto image = downcast<ARKitBadgeSystemImage>(systemImage).image())
+            recordResourceUse(*image->nativeImage());
+    }
+#endif
     recordDrawSystemImage(systemImage, destinationRect);
 }
 

Modified: trunk/Source/WebCore/rendering/RenderThemeIOS.h (291816 => 291817)


--- trunk/Source/WebCore/rendering/RenderThemeIOS.h	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/rendering/RenderThemeIOS.h	2022-03-24 22:27:19 UTC (rev 291817)
@@ -30,12 +30,6 @@
 #include "CSSValueKey.h"
 #include "RenderThemeCocoa.h"
 
-#if USE(SYSTEM_PREVIEW)
-#include "IOSurface.h"
-#include <wtf/RetainPtr.h>
-#endif
-
-OBJC_CLASS CIContext;
 OBJC_CLASS UIImage;
 
 namespace WebCore {
@@ -217,12 +211,6 @@
 
     void adjustStyleForAlternateFormControlDesignTransition(RenderStyle&, const Element*) const;
 
-#if USE(SYSTEM_PREVIEW)
-    RetainPtr<CIContext> m_ciContext;
-    std::unique_ptr<IOSurface> m_largeBadgeSurface;
-    std::unique_ptr<IOSurface> m_smallBadgeSurface;
-#endif
-
     bool m_shouldMockBoldSystemFontForAccessibility { false };
 };
 

Modified: trunk/Source/WebCore/rendering/RenderThemeIOS.mm (291816 => 291817)


--- trunk/Source/WebCore/rendering/RenderThemeIOS.mm	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebCore/rendering/RenderThemeIOS.mm	2022-03-24 22:27:19 UTC (rev 291817)
@@ -28,6 +28,7 @@
 
 #if PLATFORM(IOS_FAMILY)
 
+#import "ARKitBadgeSystemImage.h"
 #import "BitmapImage.h"
 #import "CSSPrimitiveValue.h"
 #import "CSSToLengthConversionData.h"
@@ -2007,186 +2008,9 @@
 #endif
 
 #if USE(SYSTEM_PREVIEW)
-static NSBundle *arKitBundle()
-{
-    static NSBundle *arKitBundle = []() {
-#if PLATFORM(IOS_FAMILY_SIMULATOR)
-        dlopen("/System/Library/PrivateFrameworks/AssetViewer.framework/AssetViewer", RTLD_NOW);
-        return [NSBundle bundleForClass:NSClassFromString(@"ASVThumbnailView")];
-#else
-        return [NSBundle bundleWithURL:[NSURL fileURLWithPath:@"/System/Library/PrivateFrameworks/AssetViewer.framework"]];
-#endif
-    }();
-
-    return arKitBundle;
-}
-
-static RetainPtr<CGPDFPageRef> loadARKitPDFPage(NSString *imageName)
-{
-    NSURL *url = "" URLForResource:imageName withExtension:@"pdf"];
-
-    if (!url)
-        return nullptr;
-
-    auto document = adoptCF(CGPDFDocumentCreateWithURL((CFURLRef)url));
-    if (!document)
-        return nullptr;
-
-    if (!CGPDFDocumentGetNumberOfPages(document.get()))
-        return nullptr;
-
-    return CGPDFDocumentGetPage(document.get(), 1);
-}
-
-static CGPDFPageRef systemPreviewLogo()
-{
-    static CGPDFPageRef logoPage = loadARKitPDFPage(@"ARKitBadge").leakRef();
-    return logoPage;
-}
-
 void RenderThemeIOS::paintSystemPreviewBadge(Image& image, const PaintInfo& paintInfo, const FloatRect& rect)
 {
-    static const int largeBadgeDimension = 70;
-    static const int largeBadgeOffset = 20;
-
-    static const int smallBadgeDimension = 35;
-    static const int smallBadgeOffset = 8;
-
-    static const int minimumSizeForLargeBadge = 240;
-
-    bool useSmallBadge = rect.width() < minimumSizeForLargeBadge || rect.height() < minimumSizeForLargeBadge;
-    int badgeOffset = useSmallBadge ? smallBadgeOffset : largeBadgeOffset;
-    int badgeDimension = useSmallBadge ? smallBadgeDimension : largeBadgeDimension;
-
-    int minimumDimension = badgeDimension + 2 * badgeOffset;
-    if (rect.width() < minimumDimension || rect.height() < minimumDimension)
-        return;
-
-    CGRect absoluteBadgeRect = CGRectMake(rect.x() + rect.width() - badgeDimension - badgeOffset, rect.y() + badgeOffset, badgeDimension, badgeDimension);
-    CGRect insetBadgeRect = CGRectMake(rect.width() - badgeDimension - badgeOffset, badgeOffset, badgeDimension, badgeDimension);
-    CGRect badgeRect = CGRectMake(0, 0, badgeDimension, badgeDimension);
-
-    CIImage *inputImage = [CIImage imageWithCGImage:image.nativeImage()->platformImage().get()];
-
-    // Create a circle to be used for the clipping path in the badge, as well as the drop shadow.
-    RetainPtr<CGPathRef> circle = adoptCF(CGPathCreateWithRoundedRect(absoluteBadgeRect, badgeDimension / 2, badgeDimension / 2, nullptr));
-
-    auto& graphicsContext = paintInfo.context();
-    if (graphicsContext.paintingDisabled())
-        return;
-
-    GraphicsContextStateSaver stateSaver(graphicsContext);
-
-    CGContextRef ctx = graphicsContext.platformContext();
-    if (!ctx)
-        return;
-
-    CGContextSaveGState(ctx);
-
-    // Draw a drop shadow around the circle.
-    // Use the GraphicsContext function, because it calculates the blur radius in context space,
-    // rather than screen space.
-    constexpr auto shadowColor = Color::black.colorWithAlphaByte(26);
-    graphicsContext.setShadow(FloatSize { }, 16, shadowColor);
-
-    // The circle must have an alpha channel value of 1 for the shadow color to appear.
-    CGFloat circleColorComponents[4] = { 0, 0, 0, 1 };
-    RetainPtr<CGColorRef> circleColor = adoptCF(CGColorCreate(sRGBColorSpaceRef(), circleColorComponents));
-    CGContextSetFillColorWithColor(ctx, circleColor.get());
-
-    // Clip out the circle to only show the shadow.
-    CGContextBeginPath(ctx);
-    CGContextAddRect(ctx, rect);
-    CGContextAddPath(ctx, circle.get());
-    CGContextClosePath(ctx);
-    CGContextEOClip(ctx);
-
-    // Draw a slightly smaller circle with a shadow, otherwise we'll see a fringe of the solid
-    // black circle around the edges of the clipped path below.
-    CGContextBeginPath(ctx);
-    CGRect slightlySmallerAbsoluteBadgeRect = CGRectMake(absoluteBadgeRect.origin.x + 0.5, absoluteBadgeRect.origin.y + 0.5, badgeDimension - 1, badgeDimension - 1);
-    RetainPtr<CGPathRef> slightlySmallerCircle = adoptCF(CGPathCreateWithRoundedRect(slightlySmallerAbsoluteBadgeRect, slightlySmallerAbsoluteBadgeRect.size.width / 2, slightlySmallerAbsoluteBadgeRect.size.height / 2, nullptr));
-    CGContextAddPath(ctx, slightlySmallerCircle.get());
-    CGContextClosePath(ctx);
-    CGContextFillPath(ctx);
-
-    CGContextRestoreGState(ctx);
-
-    // Draw the blurred backdrop. Scale from intrinsic size to render size.
-    CGAffineTransform transform = CGAffineTransformIdentity;
-    transform = CGAffineTransformScale(transform, rect.width() / image.width(), rect.height() / image.height());
-    CIImage *scaledImage = [inputImage imageByApplyingTransform:transform];
-
-    // CoreImage coordinates are y-up, so we need to flip the badge rectangle within the image frame.
-    CGRect flippedInsetBadgeRect = CGRectMake(insetBadgeRect.origin.x, rect.height() - insetBadgeRect.origin.y - insetBadgeRect.size.height, badgeDimension, badgeDimension);
-
-    // Create a cropped region with pixel values extending outwards.
-    CIImage *clampedImage = [scaledImage imageByClampingToRect:flippedInsetBadgeRect];
-
-    // Blur.
-    CIImage *blurredImage = [clampedImage imageByApplyingGaussianBlurWithSigma:10];
-
-    // Saturate.
-    CIFilter *saturationFilter = [CIFilter filterWithName:@"CIColorControls"];
-    [saturationFilter setValue:blurredImage forKey:kCIInputImageKey];
-    [saturationFilter setValue:@1.8 forKey:kCIInputSaturationKey];
-
-    // Tint.
-    CIFilter *tintFilter1 = [CIFilter filterWithName:@"CIConstantColorGenerator"];
-    CIColor *tintColor1 = [CIColor colorWithRed:1 green:1 blue:1 alpha:0.18];
-    [tintFilter1 setValue:tintColor1 forKey:kCIInputColorKey];
-
-    // Blend the tint with the saturated output.
-    CIFilter *sourceOverFilter = [CIFilter filterWithName:@"CISourceOverCompositing"];
-    [sourceOverFilter setValue:tintFilter1.outputImage forKey:kCIInputImageKey];
-    [sourceOverFilter setValue:saturationFilter.outputImage forKey:kCIInputBackgroundImageKey];
-
-    if (!m_ciContext)
-        m_ciContext = [CIContext context];
-
-    RetainPtr<CGImageRef> cgImage;
-#if HAVE(IOSURFACE_COREIMAGE_SUPPORT)
-    // Crop the result to the badge location.
-    CIImage *croppedImage = [sourceOverFilter.outputImage imageByCroppingToRect:flippedInsetBadgeRect];
-    CIImage *translatedImage = [croppedImage imageByApplyingTransform:CGAffineTransformMakeTranslation(-flippedInsetBadgeRect.origin.x, -flippedInsetBadgeRect.origin.y)];
-    IOSurfaceRef surface;
-    if (useSmallBadge) {
-        if (!m_smallBadgeSurface)
-            m_smallBadgeSurface = IOSurface::create({ smallBadgeDimension, smallBadgeDimension }, DestinationColorSpace::SRGB());
-        surface = m_smallBadgeSurface->surface();
-    } else {
-        if (!m_largeBadgeSurface)
-            m_largeBadgeSurface = IOSurface::create({ largeBadgeDimension, largeBadgeDimension }, DestinationColorSpace::SRGB());
-        surface = m_largeBadgeSurface->surface();
-    }
-    [m_ciContext render:translatedImage toIOSurface:surface bounds:badgeRect colorSpace:sRGBColorSpaceRef()];
-    cgImage = useSmallBadge ? m_smallBadgeSurface->createImage() : m_largeBadgeSurface->createImage();
-#else
-    cgImage = adoptCF([m_ciContext createCGImage:sourceOverFilter.outputImage fromRect:flippedInsetBadgeRect]);
-#endif
-
-    // Before we render the result, we should clip to a circle around the badge rectangle.
-    CGContextSaveGState(ctx);
-    CGContextBeginPath(ctx);
-    CGContextAddPath(ctx, circle.get());
-    CGContextClosePath(ctx);
-    CGContextClip(ctx);
-
-    CGContextTranslateCTM(ctx, absoluteBadgeRect.origin.x, absoluteBadgeRect.origin.y);
-    CGContextTranslateCTM(ctx, 0, badgeDimension);
-    CGContextScaleCTM(ctx, 1, -1);
-    CGContextDrawImage(ctx, badgeRect, cgImage.get());
-
-    if (auto logo = systemPreviewLogo()) {
-        CGSize pdfSize = CGPDFPageGetBoxRect(logo, kCGPDFMediaBox).size;
-        CGFloat scaleX = badgeDimension / pdfSize.width;
-        CGFloat scaleY = badgeDimension / pdfSize.height;
-        CGContextScaleCTM(ctx, scaleX, scaleY);
-        CGContextDrawPDFPage(ctx, logo);
-    }
-
-    CGContextFlush(ctx);
-    CGContextRestoreGState(ctx);
+    paintInfo.context().drawSystemImage(ARKitBadgeSystemImage::create(image), rect);
 }
 #endif
 

Modified: trunk/Source/WebKit/ChangeLog (291816 => 291817)


--- trunk/Source/WebKit/ChangeLog	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebKit/ChangeLog	2022-03-24 22:27:19 UTC (rev 291817)
@@ -1,3 +1,19 @@
+2022-03-24  Antoine Quint  <grao...@webkit.org>
+
+        DOM GPUP: paintSystemPreviewBadge (AR QuickLook element badge)
+        https://bugs.webkit.org/show_bug.cgi?id=238295
+        rdar://83580608
+
+        Reviewed by Dean Jackson.
+
+        Make sure we restore the Image on the ARKitBadgeSystemImage before we attempt to draw it.
+
+        * GPUProcess/graphics/RemoteDisplayListRecorder.cpp:
+        (WebKit::RemoteDisplayListRecorder::drawSystemImage):
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<Ref<SystemImage>>::encode):
+        (IPC::ArgumentCoder<Ref<SystemImage>>::decode):
+
 2022-03-24  Michael Saboff  <msab...@apple.com>
 
         Update Sandbox profiles for system content path

Modified: trunk/Source/WebKit/GPUProcess/graphics/RemoteDisplayListRecorder.cpp (291816 => 291817)


--- trunk/Source/WebKit/GPUProcess/graphics/RemoteDisplayListRecorder.cpp	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebKit/GPUProcess/graphics/RemoteDisplayListRecorder.cpp	2022-03-24 22:27:19 UTC (rev 291817)
@@ -32,6 +32,10 @@
 #include <WebCore/BitmapImage.h>
 #include <WebCore/FilterResults.h>
 
+#if USE(SYSTEM_PREVIEW)
+#include <WebCore/ARKitBadgeSystemImage.h>
+#endif
+
 namespace WebKit {
 using namespace WebCore;
 
@@ -285,6 +289,17 @@
 
 void RemoteDisplayListRecorder::drawSystemImage(SystemImage& systemImage, const FloatRect& destinationRect)
 {
+#if USE(SYSTEM_PREVIEW)
+    if (is<ARKitBadgeSystemImage>(systemImage)) {
+        ARKitBadgeSystemImage& badge = downcast<ARKitBadgeSystemImage>(systemImage);
+        RefPtr nativeImage = resourceCache().cachedNativeImage({ badge.imageIdentifier(), m_webProcessIdentifier });
+        if (!nativeImage) {
+            ASSERT_NOT_REACHED();
+            return;
+        }
+        badge.setImage(BitmapImage::create(WTFMove(nativeImage)));
+    }
+#endif
     handleItem(DisplayList::DrawSystemImage(systemImage, destinationRect));
 }
 

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (291816 => 291817)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2022-03-24 22:22:33 UTC (rev 291816)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2022-03-24 22:27:19 UTC (rev 291817)
@@ -31,6 +31,7 @@
 #include "StreamConnectionEncoder.h"
 #include <_javascript_Core/GenericTypedArrayViewInlines.h>
 #include <_javascript_Core/JSGenericTypedArrayViewInlines.h>
+#include <WebCore/ARKitBadgeSystemImage.h>
 #include <WebCore/ApplePayButtonSystemImage.h>
 #include <WebCore/ApplePayLogoSystemImage.h>
 #include <WebCore/AuthenticationChallenge.h>
@@ -3173,6 +3174,11 @@
         downcast<ApplePayLogoSystemImage>(systemImage.get()).encode(encoder);
         return;
 #endif
+#if USE(SYSTEM_PREVIEW)
+    case SystemImageType::ARKitBadge:
+        downcast<ARKitBadgeSystemImage>(systemImage.get()).encode(encoder);
+        return;
+#endif
     }
 
     ASSERT_NOT_REACHED();
@@ -3198,6 +3204,10 @@
     case SystemImageType::ApplePayLogo:
         return ApplePayLogoSystemImage::decode(decoder);
 #endif
+#if USE(SYSTEM_PREVIEW)
+    case SystemImageType::ARKitBadge:
+        return ARKitBadgeSystemImage::decode(decoder);
+#endif
     }
 
     ASSERT_NOT_REACHED();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to