Title: [293137] trunk
Revision
293137
Author
wenson_hs...@apple.com
Date
2022-04-20 18:51:03 -0700 (Wed, 20 Apr 2022)

Log Message

Avoid falling back to snapshots for transparent images when triggering batch text recognition
https://bugs.webkit.org/show_bug.cgi?id=239555
rdar://91622151

Reviewed by Aditya Keerthi.

Source/WebCore:

For normal Live Text, our existing heuristics fall back to analyzing a snapshot rather than the image data
itself for transparent image elements (e.g. on Twitter). However, when installing block-style image overlay
content using `ImageAnalysisQueue`, it doesn't make sense to use this compatibility hack, since this flavor of
image overlay content is directly visible to the user, and would still show up underneath fully transparent
image elements, as long as we're able to analyze the other (non-fully-transparent) image element underneath.

* Headers.cmake:
* WebCore.xcodeproj/project.pbxproj:
* accessibility/AXImage.cpp:
* page/ChromeClient.h:

Plumb the new `TextRecognitionOptions` struct through this client method.

(WebCore::ChromeClient::requestTextRecognition):
* page/EventHandler.cpp:
(WebCore::EventHandler::textRecognitionHoverTimerFired):
* page/ImageAnalysisQueue.cpp:
(WebCore::ImageAnalysisQueue::resumeProcessing):

Use the presence of an identifier as a cue to determine whether or not we should opt into the snapshotting
fallback behavior, for the time being. I also considered just keying this behavior off of the `identifier` in
`WebPage::requestTextRecognition`, but chose this approach because it seems fragile to couple those two
behaviors.

* platform/TextRecognitionOptions.h: Added.
* testing/Internals.cpp:

Source/WebKit:

Refactor `requestTextRecognition()` to take in `TextRecognitionOptions`.
See WebCore/ChangeLog for more details.

* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::requestTextRecognition):
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::requestTextRecognition):
* WebProcess/WebPage/WebPage.h:
(WebKit::WebPage::requestTextRecognition):

Tools:

Add an API test to exercise the bug, by triggering batch image analysis on an image with `opacity: 0;` that
fades in on a timer.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/ImageAnalysisTests.mm:
(TestWebKitAPI::CGImagePixelReader::CGImagePixelReader):
(TestWebKitAPI::CGImagePixelReader::isTransparentBlack const):
(TestWebKitAPI::CGImagePixelReader::at const):
(TestWebKitAPI::CGImagePixelReader::width const):
(TestWebKitAPI::CGImagePixelReader::height const):

Add a simple helper class to read pixel values at a given location in a given CGImage; this helper class works
by first rendering the given image into a plain SRGB bitmap context, which we then use to read back pixel data
in RGBA format.

(TestWebKitAPI::processRequestWithError):
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/fade-in-image.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (293136 => 293137)


--- trunk/Source/WebCore/ChangeLog	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebCore/ChangeLog	2022-04-21 01:51:03 UTC (rev 293137)
@@ -1,3 +1,38 @@
+2022-04-20  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Avoid falling back to snapshots for transparent images when triggering batch text recognition
+        https://bugs.webkit.org/show_bug.cgi?id=239555
+        rdar://91622151
+
+        Reviewed by Aditya Keerthi.
+
+        For normal Live Text, our existing heuristics fall back to analyzing a snapshot rather than the image data
+        itself for transparent image elements (e.g. on Twitter). However, when installing block-style image overlay
+        content using `ImageAnalysisQueue`, it doesn't make sense to use this compatibility hack, since this flavor of
+        image overlay content is directly visible to the user, and would still show up underneath fully transparent
+        image elements, as long as we're able to analyze the other (non-fully-transparent) image element underneath.
+
+        * Headers.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        * accessibility/AXImage.cpp:
+        * page/ChromeClient.h:
+
+        Plumb the new `TextRecognitionOptions` struct through this client method.
+
+        (WebCore::ChromeClient::requestTextRecognition):
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::textRecognitionHoverTimerFired):
+        * page/ImageAnalysisQueue.cpp:
+        (WebCore::ImageAnalysisQueue::resumeProcessing):
+
+        Use the presence of an identifier as a cue to determine whether or not we should opt into the snapshotting
+        fallback behavior, for the time being. I also considered just keying this behavior off of the `identifier` in
+        `WebPage::requestTextRecognition`, but chose this approach because it seems fragile to couple those two
+        behaviors.
+
+        * platform/TextRecognitionOptions.h: Added.
+        * testing/Internals.cpp:
+
 2022-04-20  Chris Dumez  <cdu...@apple.com>
 
         Move true / false AtomStrings to a central location and reuse them

Modified: trunk/Source/WebCore/Headers.cmake (293136 => 293137)


--- trunk/Source/WebCore/Headers.cmake	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebCore/Headers.cmake	2022-04-21 01:51:03 UTC (rev 293137)
@@ -1355,6 +1355,7 @@
     platform/SuddenTermination.h
     platform/Supplementable.h
     platform/SystemSoundDelegate.h
+    platform/TextRecognitionOptions.h
     platform/ThemeTypes.h
     platform/ThreadCheck.h
     platform/ThreadGlobalData.h

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (293136 => 293137)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-04-21 01:51:03 UTC (rev 293137)
@@ -5535,6 +5535,7 @@
 		F4034FAC275EAD6E003A81F8 /* RequestCookieConsentOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = F4034F8F275C1686003A81F8 /* RequestCookieConsentOptions.h */; };
 		F4034FAE275EAD76003A81F8 /* NavigatorCookieConsent.h in Headers */ = {isa = PBXBuildFile; fileRef = F4034F8D275C087B003A81F8 /* NavigatorCookieConsent.h */; };
 		F403E7872363B58C00044550 /* EnterKeyHint.h in Headers */ = {isa = PBXBuildFile; fileRef = F403E7852363B58C00044550 /* EnterKeyHint.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		F40B8D5A281072B800346417 /* TextRecognitionOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = F40B8D59281072B800346417 /* TextRecognitionOptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F40DAAEC25D9F25E0011B4FA /* PasteboardContext.h in Headers */ = {isa = PBXBuildFile; fileRef = F40DAAEB25D9F25E0011B4FA /* PasteboardContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F40DAAEF25D9F3BF0011B4FA /* PagePasteboardContext.h in Headers */ = {isa = PBXBuildFile; fileRef = F40DAAEE25D9F3BF0011B4FA /* PagePasteboardContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F420F00A25E47791009251EF /* PointerEventTypeNames.h in Headers */ = {isa = PBXBuildFile; fileRef = F420F00825E47791009251EF /* PointerEventTypeNames.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -17868,6 +17869,7 @@
 		F4034F9C275C4783003A81F8 /* CookieConsentDecisionResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CookieConsentDecisionResult.h; path = "cookie-consent/CookieConsentDecisionResult.h"; sourceTree = "<group>"; };
 		F403E7852363B58C00044550 /* EnterKeyHint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnterKeyHint.h; sourceTree = "<group>"; };
 		F403E7862363B58C00044550 /* EnterKeyHint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = EnterKeyHint.cpp; sourceTree = "<group>"; };
+		F40B8D59281072B800346417 /* TextRecognitionOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextRecognitionOptions.h; sourceTree = "<group>"; };
 		F40DAAEB25D9F25E0011B4FA /* PasteboardContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PasteboardContext.h; sourceTree = "<group>"; };
 		F40DAAEE25D9F3BF0011B4FA /* PagePasteboardContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PagePasteboardContext.h; sourceTree = "<group>"; };
 		F420F00825E47791009251EF /* PointerEventTypeNames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PointerEventTypeNames.h; sourceTree = "<group>"; };
@@ -30373,6 +30375,7 @@
 				E3C04132254CA7110021D0E6 /* SystemSoundManager.cpp */,
 				E3C0412D254CA29B0021D0E6 /* SystemSoundManager.h */,
 				7CC564B618BABEA6001B9652 /* TelephoneNumberDetector.h */,
+				F40B8D59281072B800346417 /* TextRecognitionOptions.h */,
 				F48B7D5225C341E6009E75DD /* TextRecognitionResult.h */,
 				BCE65D310EAD1211007E4533 /* Theme.cpp */,
 				BCE658FE0EA9248A007E4533 /* Theme.h */,
@@ -37957,6 +37960,7 @@
 				1C18DA59181AF6A500C4EF22 /* TextPainter.h in Headers */,
 				E4C91A0E1802343100A17F6D /* TextPaintStyle.h in Headers */,
 				CE212158240DBEB9006ED443 /* TextPlaceholderElement.h in Headers */,
+				F40B8D5A281072B800346417 /* TextRecognitionOptions.h in Headers */,
 				F48B7D5325C341E6009E75DD /* TextRecognitionResult.h in Headers */,
 				93F198F608245E59001E9ABC /* TextResourceDecoder.h in Headers */,
 				A824B4650E2EF2EA0081A7B7 /* TextRun.h in Headers */,

Modified: trunk/Source/WebCore/accessibility/AXImage.cpp (293136 => 293137)


--- trunk/Source/WebCore/accessibility/AXImage.cpp	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebCore/accessibility/AXImage.cpp	2022-04-21 01:51:03 UTC (rev 293137)
@@ -33,6 +33,7 @@
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "DocumentInlines.h"
+#include "TextRecognitionOptions.h"
 
 namespace WebCore {
 

Modified: trunk/Source/WebCore/page/ChromeClient.h (293136 => 293137)


--- trunk/Source/WebCore/page/ChromeClient.h	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebCore/page/ChromeClient.h	2022-04-21 01:51:03 UTC (rev 293137)
@@ -141,6 +141,7 @@
 struct SecurityOriginData;
 struct ShareDataWithParsedURL;
 struct TextIndicatorData;
+struct TextRecognitionOptions;
 struct ViewportArguments;
 struct WindowFeatures;
 
@@ -600,7 +601,7 @@
 #endif
 
 #if ENABLE(IMAGE_ANALYSIS)
-    virtual void requestTextRecognition(Element&, const String& = { }, CompletionHandler<void(RefPtr<Element>&&)>&& completion = { })
+    virtual void requestTextRecognition(Element&, TextRecognitionOptions&&, CompletionHandler<void(RefPtr<Element>&&)>&& completion = { })
     {
         if (completion)
             completion({ });

Modified: trunk/Source/WebCore/page/EventHandler.cpp (293136 => 293137)


--- trunk/Source/WebCore/page/EventHandler.cpp	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2022-04-21 01:51:03 UTC (rev 293137)
@@ -113,6 +113,7 @@
 #include "StyleCachedImage.h"
 #include "TextEvent.h"
 #include "TextIterator.h"
+#include "TextRecognitionOptions.h"
 #include "UserGestureIndicator.h"
 #include "UserTypingGestureIndicator.h"
 #include "ValidationMessageClient.h"
@@ -3491,7 +3492,7 @@
         return;
 
     if (auto* page = m_frame.page())
-        page->chrome().client().requestTextRecognition(*element);
+        page->chrome().client().requestTextRecognition(*element, { });
 }
 
 #endif // ENABLE(IMAGE_ANALYSIS)

Modified: trunk/Source/WebCore/page/ImageAnalysisQueue.cpp (293136 => 293137)


--- trunk/Source/WebCore/page/ImageAnalysisQueue.cpp	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebCore/page/ImageAnalysisQueue.cpp	2022-04-21 01:51:03 UTC (rev 293137)
@@ -36,6 +36,7 @@
 #include "ImageOverlay.h"
 #include "RenderImage.h"
 #include "RenderView.h"
+#include "TextRecognitionOptions.h"
 #include "Timer.h"
 
 namespace WebCore {
@@ -112,7 +113,8 @@
 
         m_pendingRequestCount++;
         m_page->resetTextRecognitionResult(*element);
-        m_page->chrome().client().requestTextRecognition(*element, m_identifier, [this, page = m_page] (auto&&) {
+        auto allowSnapshots = m_identifier.isEmpty() ? TextRecognitionOptions::AllowSnapshots::Yes : TextRecognitionOptions::AllowSnapshots::No;
+        m_page->chrome().client().requestTextRecognition(*element, { m_identifier, allowSnapshots }, [this, page = m_page] (auto&&) {
             if (!page || page->imageAnalysisQueueIfExists() != this)
                 return;
 

Added: trunk/Source/WebCore/platform/TextRecognitionOptions.h (0 => 293137)


--- trunk/Source/WebCore/platform/TextRecognitionOptions.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/TextRecognitionOptions.h	2022-04-21 01:51:03 UTC (rev 293137)
@@ -0,0 +1,41 @@
+/*
+ * 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. ``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
+ * 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 ENABLE(IMAGE_ANALYSIS)
+
+namespace WebCore {
+
+struct TextRecognitionOptions {
+    String identifier;
+
+    enum class AllowSnapshots : bool { No, Yes };
+    AllowSnapshots allowSnapshots { AllowSnapshots::Yes };
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(IMAGE_ANALYSIS)

Modified: trunk/Source/WebCore/testing/Internals.cpp (293136 => 293137)


--- trunk/Source/WebCore/testing/Internals.cpp	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebCore/testing/Internals.cpp	2022-04-21 01:51:03 UTC (rev 293137)
@@ -215,6 +215,7 @@
 #include "SystemSoundManager.h"
 #include "TextIterator.h"
 #include "TextPlaceholderElement.h"
+#include "TextRecognitionOptions.h"
 #include "ThreadableBlobRegistry.h"
 #include "TreeScope.h"
 #include "TypeConversions.h"

Modified: trunk/Source/WebKit/ChangeLog (293136 => 293137)


--- trunk/Source/WebKit/ChangeLog	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebKit/ChangeLog	2022-04-21 01:51:03 UTC (rev 293137)
@@ -1,3 +1,22 @@
+2022-04-20  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Avoid falling back to snapshots for transparent images when triggering batch text recognition
+        https://bugs.webkit.org/show_bug.cgi?id=239555
+        rdar://91622151
+
+        Reviewed by Aditya Keerthi.
+
+        Refactor `requestTextRecognition()` to take in `TextRecognitionOptions`.
+        See WebCore/ChangeLog for more details.
+
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::requestTextRecognition):
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::requestTextRecognition):
+        * WebProcess/WebPage/WebPage.h:
+        (WebKit::WebPage::requestTextRecognition):
+
 2022-04-20  Simon Fraser  <simon.fra...@apple.com>
 
         Add release assert logging in RemoteRenderingBackendProxy::prepareBuffersForDisplay()

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (293136 => 293137)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2022-04-21 01:51:03 UTC (rev 293137)
@@ -92,6 +92,7 @@
 #include <WebCore/SecurityOriginData.h>
 #include <WebCore/Settings.h>
 #include <WebCore/TextIndicator.h>
+#include <WebCore/TextRecognitionOptions.h>
 
 #if HAVE(WEBGPU_IMPLEMENTATION)
 #import <pal/graphics/WebGPU/Impl/WebGPUCreateImpl.h>
@@ -1514,9 +1515,9 @@
 
 #if ENABLE(IMAGE_ANALYSIS)
 
-void WebChromeClient::requestTextRecognition(Element& element, const String& identifier, CompletionHandler<void(RefPtr<Element>&&)>&& completion)
+void WebChromeClient::requestTextRecognition(Element& element, TextRecognitionOptions&& options, CompletionHandler<void(RefPtr<Element>&&)>&& completion)
 {
-    m_page.requestTextRecognition(element, identifier, WTFMove(completion));
+    m_page.requestTextRecognition(element, WTFMove(options), WTFMove(completion));
 }
 
 #endif

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h (293136 => 293137)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2022-04-21 01:51:03 UTC (rev 293137)
@@ -34,6 +34,7 @@
 enum class CookieConsentDecisionResult : uint8_t;
 enum class StorageAccessPromptWasShown : bool;
 enum class StorageAccessWasGranted : bool;
+struct TextRecognitionOptions;
 }
 
 namespace WebKit {
@@ -435,7 +436,7 @@
 #endif
 
 #if ENABLE(IMAGE_ANALYSIS)
-    void requestTextRecognition(WebCore::Element&, const String& identifier = { }, CompletionHandler<void(RefPtr<WebCore::Element>&&)>&& = { }) final;
+    void requestTextRecognition(WebCore::Element&, WebCore::TextRecognitionOptions&&, CompletionHandler<void(RefPtr<WebCore::Element>&&)>&& = { }) final;
 #endif
 
     bool needsImageOverlayControllerForSelectionPainting() const final

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (293136 => 293137)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2022-04-21 01:51:03 UTC (rev 293137)
@@ -256,6 +256,7 @@
 #include <WebCore/SubframeLoader.h>
 #include <WebCore/SubstituteData.h>
 #include <WebCore/TextIterator.h>
+#include <WebCore/TextRecognitionOptions.h>
 #include <WebCore/TranslationContextMenuInfo.h>
 #include <WebCore/UserContentURLPattern.h>
 #include <WebCore/UserGestureIndicator.h>
@@ -7730,7 +7731,7 @@
 
 #if ENABLE(IMAGE_ANALYSIS)
 
-void WebPage::requestTextRecognition(Element& element, const String& identifier, CompletionHandler<void(RefPtr<Element>&&)>&& completion)
+void WebPage::requestTextRecognition(Element& element, TextRecognitionOptions&& options, CompletionHandler<void(RefPtr<Element>&&)>&& completion)
 {
     if (!is<HTMLElement>(element)) {
         if (completion)
@@ -7767,7 +7768,11 @@
     }
 
     auto& renderImage = downcast<RenderImage>(*renderer);
-    auto bitmap = createShareableBitmap(renderImage, { std::nullopt, AllowAnimatedImages::No, UseSnapshotForTransparentImages::Yes });
+    auto bitmap = createShareableBitmap(renderImage, {
+        std::nullopt,
+        AllowAnimatedImages::No,
+        options.allowSnapshots == TextRecognitionOptions::AllowSnapshots::Yes ? UseSnapshotForTransparentImages::Yes : UseSnapshotForTransparentImages::No
+    });
     if (!bitmap) {
         if (completion)
             completion({ });
@@ -7789,7 +7794,7 @@
 
     auto cachedImage = renderImage.cachedImage();
     auto imageURL = cachedImage ? element.document().completeURL(cachedImage->url().string()) : URL { };
-    sendWithAsyncReply(Messages::WebPageProxy::RequestTextRecognition(WTFMove(imageURL), WTFMove(bitmapHandle), identifier), [webPage = WeakPtr { *this }, weakElement = WeakPtr { element }] (auto&& result) {
+    sendWithAsyncReply(Messages::WebPageProxy::RequestTextRecognition(WTFMove(imageURL), WTFMove(bitmapHandle), options.identifier), [webPage = WeakPtr { *this }, weakElement = WeakPtr { element }] (auto&& result) {
         RefPtr protectedPage { webPage.get() };
         if (!protectedPage)
             return;

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (293136 => 293137)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2022-04-21 01:51:03 UTC (rev 293137)
@@ -256,6 +256,7 @@
 struct RequestStorageAccessResult;
 struct RunJavaScriptParameters;
 struct TextCheckingResult;
+struct TextRecognitionOptions;
 struct TextRecognitionResult;
 struct ViewportArguments;
 
@@ -1452,7 +1453,7 @@
     void isPlayingMediaDidChange(WebCore::MediaProducerMediaStateFlags);
 
 #if ENABLE(IMAGE_ANALYSIS)
-    void requestTextRecognition(WebCore::Element&, const String& identifier = { }, CompletionHandler<void(RefPtr<WebCore::Element>&&)>&& = { });
+    void requestTextRecognition(WebCore::Element&, WebCore::TextRecognitionOptions&&, CompletionHandler<void(RefPtr<WebCore::Element>&&)>&& = { });
     void updateWithTextRecognitionResult(const WebCore::TextRecognitionResult&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(TextRecognitionUpdateResult)>&&);
     void startImageAnalysis(const String& identifier);
 #endif

Modified: trunk/Tools/ChangeLog (293136 => 293137)


--- trunk/Tools/ChangeLog	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Tools/ChangeLog	2022-04-21 01:51:03 UTC (rev 293137)
@@ -1,3 +1,30 @@
+2022-04-20  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Avoid falling back to snapshots for transparent images when triggering batch text recognition
+        https://bugs.webkit.org/show_bug.cgi?id=239555
+        rdar://91622151
+
+        Reviewed by Aditya Keerthi.
+
+        Add an API test to exercise the bug, by triggering batch image analysis on an image with `opacity: 0;` that
+        fades in on a timer.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/ImageAnalysisTests.mm:
+        (TestWebKitAPI::CGImagePixelReader::CGImagePixelReader):
+        (TestWebKitAPI::CGImagePixelReader::isTransparentBlack const):
+        (TestWebKitAPI::CGImagePixelReader::at const):
+        (TestWebKitAPI::CGImagePixelReader::width const):
+        (TestWebKitAPI::CGImagePixelReader::height const):
+
+        Add a simple helper class to read pixel values at a given location in a given CGImage; this helper class works
+        by first rendering the given image into a plain SRGB bitmap context, which we then use to read back pixel data
+        in RGBA format.
+
+        (TestWebKitAPI::processRequestWithError):
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/fade-in-image.html: Added.
+
 2022-04-20  Ross Kirsling  <ross.kirsl...@sony.com>
 
         [LayoutTests][Win] Tests can fail if long paths are not enabled in registry.

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (293136 => 293137)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2022-04-21 01:51:03 UTC (rev 293137)
@@ -1027,6 +1027,7 @@
 		F4034FA3275D5AC6003A81F8 /* cookie-consent-basic.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4034FA2275D5449003A81F8 /* cookie-consent-basic.html */; };
 		F407FE391F1D0DFC0017CF25 /* enormous.svg in Copy Resources */ = {isa = PBXBuildFile; fileRef = F407FE381F1D0DE60017CF25 /* enormous.svg */; };
 		F4094CC725545BD5003D73E3 /* DisplayListTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F4094CC625545BD5003D73E3 /* DisplayListTests.cpp */; };
+		F40B8D5E281086E500346417 /* fade-in-image.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F40B8D5D2810855900346417 /* fade-in-image.html */; };
 		F415086D1DA040C50044BE9B /* play-audio-on-click.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F415086C1DA040C10044BE9B /* play-audio-on-click.html */; };
 		F418BE151F71B7DC001970E6 /* RoundedRectTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F418BE141F71B7DC001970E6 /* RoundedRectTests.cpp */; };
 		F4194AD11F5A320100ADD83F /* drop-targets.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4194AD01F5A2EA500ADD83F /* drop-targets.html */; };
@@ -1359,6 +1360,7 @@
 				C5E1AFFE16B221F1006CC1F2 /* execCopy.html in Copy Resources */,
 				7283A9D222FB1E0600B21C7D /* exif-orientation-8-llo.jpg in Copy Resources */,
 				CDA29B2B20FD358400F15CED /* ExitFullscreenOnEnterPiP.html in Copy Resources */,
+				F40B8D5E281086E500346417 /* fade-in-image.html in Copy Resources */,
 				9358C33C273ED07B00F3B38C /* file-system-access.salt in Copy Resources */,
 				F41AB9A31EF4696B0083FA08 /* file-uploading.html in Copy Resources */,
 				BC2D006412AA04CE00E732A3 /* file-with-anchor.html in Copy Resources */,
@@ -3033,6 +3035,7 @@
 		F4034FA2275D5449003A81F8 /* cookie-consent-basic.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "cookie-consent-basic.html"; sourceTree = "<group>"; };
 		F407FE381F1D0DE60017CF25 /* enormous.svg */ = {isa = PBXFileReference; lastKnownFileType = text; path = enormous.svg; sourceTree = "<group>"; };
 		F4094CC625545BD5003D73E3 /* DisplayListTests.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayListTests.cpp; sourceTree = "<group>"; };
+		F40B8D5D2810855900346417 /* fade-in-image.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "fade-in-image.html"; sourceTree = "<group>"; };
 		F4106C6821ACBF84004B89A1 /* WKWebViewFirstResponderTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewFirstResponderTests.mm; sourceTree = "<group>"; };
 		F415086C1DA040C10044BE9B /* play-audio-on-click.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "play-audio-on-click.html"; sourceTree = "<group>"; };
 		F418BE141F71B7DC001970E6 /* RoundedRectTests.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RoundedRectTests.cpp; sourceTree = "<group>"; };
@@ -4172,6 +4175,7 @@
 				F407FE381F1D0DE60017CF25 /* enormous.svg */,
 				7283A9D122FB1D9700B21C7D /* exif-orientation-8-llo.jpg */,
 				CDA29B2A20FD344E00F15CED /* ExitFullscreenOnEnterPiP.html */,
+				F40B8D5D2810855900346417 /* fade-in-image.html */,
 				9358C33B273ED06A00F3B38C /* file-system-access.salt */,
 				F41AB99B1EF4692C0083FA08 /* file-uploading.html */,
 				49D2E5C12731E37400BCCAED /* file-with-iframe.html */,

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ImageAnalysisTests.mm (293136 => 293137)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ImageAnalysisTests.mm	2022-04-21 01:30:19 UTC (rev 293136)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ImageAnalysisTests.mm	2022-04-21 01:51:03 UTC (rev 293137)
@@ -36,6 +36,7 @@
 #import "TestWKWebView.h"
 #import "UIKitSPI.h"
 #import "WKWebViewConfigurationExtras.h"
+#import <WebCore/Color.h>
 #import <WebCore/LocalizedStrings.h>
 #import <WebKit/WKPreferencesPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
@@ -103,6 +104,45 @@
 
 namespace TestWebKitAPI {
 
+// FIXME: We can unify most of this helper class with the logic in `TestPDFPage::colorAtPoint`, and deploy this
+// helper class in several other tests that read pixel data from CGImages.
+class CGImagePixelReader {
+    WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(CGImagePixelReader);
+public:
+    CGImagePixelReader(CGImageRef image)
+        : m_width(CGImageGetWidth(image))
+        , m_height(CGImageGetHeight(image))
+    {
+        auto colorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB));
+        auto bytesPerPixel = 4;
+        auto bytesPerRow = bytesPerPixel * CGImageGetWidth(image);
+        auto bitsPerComponent = 8;
+        auto bitmapInfo = kCGImageAlphaPremultipliedLast | kCGImageByteOrder32Big;
+        m_context = adoptCF(CGBitmapContextCreateWithData(nullptr, m_width, m_height, bitsPerComponent, bytesPerRow, colorSpace.get(), bitmapInfo, nullptr, nullptr));
+        CGContextDrawImage(m_context.get(), CGRectMake(0, 0, m_width, m_height), image);
+    }
+
+    bool isTransparentBlack(unsigned x, unsigned y) const
+    {
+        return at(x, y) == WebCore::Color::transparentBlack;
+    }
+
+    WebCore::Color at(unsigned x, unsigned y) const
+    {
+        auto* data = ""
+        auto offset = 4 * (width() * y + x);
+        return WebCore::makeFromComponentsClampingExceptAlpha<WebCore::SRGBA<uint8_t>>(data[offset], data[offset + 1], data[offset + 2], data[offset + 3]);
+    }
+
+    unsigned width() const { return m_width; }
+    unsigned height() const { return m_height; }
+
+private:
+    unsigned m_width { 0 };
+    unsigned m_height { 0 };
+    RetainPtr<CGContextRef> m_context;
+};
+
 static Vector<RetainPtr<VKImageAnalyzerRequest>>& processedRequests()
 {
     static NeverDestroyed requests = Vector<RetainPtr<VKImageAnalyzerRequest>> { };
@@ -120,6 +160,13 @@
     return adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get()]);
 }
 
+static void processRequestWithError(id, SEL, VKImageAnalyzerRequest *request, void (^)(double progress), void (^completion)(VKImageAnalysis *analysis, NSError *error))
+{
+    gDidProcessRequestCount++;
+    processedRequests().append({ request });
+    completion(nil, [NSError errorWithDomain:NSCocoaErrorDomain code:1 userInfo:nil]);
+}
+
 static void processRequestWithResults(id, SEL, VKImageAnalyzerRequest *request, void (^)(double progress), void (^completion)(VKImageAnalysis *, NSError *))
 {
     gDidProcessRequestCount++;
@@ -143,13 +190,6 @@
 
 #if PLATFORM(IOS_FAMILY)
 
-static void processRequestWithError(id, SEL, VKImageAnalyzerRequest *request, void (^)(double progress), void (^completion)(VKImageAnalysis *analysis, NSError *error))
-{
-    gDidProcessRequestCount++;
-    processedRequests().append({ request });
-    completion(nil, [NSError errorWithDomain:NSCocoaErrorDomain code:1 userInfo:nil]);
-}
-
 TEST(ImageAnalysisTests, DoNotAnalyzeImagesInEditableContent)
 {
     auto requestSwizzler = makeImageAnalysisRequestSwizzler(processRequestWithError);
@@ -266,6 +306,22 @@
     EXPECT_EQ(450U, CGImageGetHeight(lastRequestedImage));
 }
 
+TEST(ImageAnalysisTests, ImageAnalysisWithTransparentImages)
+{
+    auto requestSwizzler = makeImageAnalysisRequestSwizzler(processRequestWithError);
+    auto webView = createWebViewWithTextRecognitionEnhancements();
+    [webView synchronouslyLoadTestPageNamed:@"fade-in-image"];
+    [webView _startImageAnalysis:@"foo"];
+    [webView waitForImageAnalysisRequests:1];
+
+    CGImagePixelReader reader { [processedRequests().first() image] };
+    EXPECT_TRUE(reader.isTransparentBlack(1, 1));
+    EXPECT_TRUE(reader.isTransparentBlack(reader.width() - 1, 1));
+    EXPECT_TRUE(reader.isTransparentBlack(reader.width() - 1, reader.height() - 1));
+    EXPECT_TRUE(reader.isTransparentBlack(1, reader.height() - 1));
+    EXPECT_FALSE(reader.isTransparentBlack(reader.width() / 2, reader.height() / 2));
+}
+
 #if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS) && PLATFORM(IOS_FAMILY)
 
 TEST(ImageAnalysisTests, MenuControllerItems)

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/fade-in-image.html (0 => 293137)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/fade-in-image.html	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/fade-in-image.html	2022-04-21 01:51:03 UTC (rev 293137)
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<head>
+<style>
+body, html {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+}
+
+img {
+    opacity: 0;
+    transition: opacity 1s ease-in-out;
+}
+
+div, img {
+    width: 215px;
+    height: 174px;
+    position: absolute;
+    top: 0;
+    left: 0;
+}
+
+div {
+    background: red;
+}
+</style>
+<script>
+addEventListener("load", () => {
+    setTimeout(() => document.querySelector("img").style.opacity = 1, 500);
+});
+</script>
+</head>
+<body>
+<div></div>
+<img src=""
+</body>
+</html>
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to