Changeset 278394 in webkit
- Timestamp:
- Jun 2, 2021, 9:59:05 PM (5 years ago)
- Location:
- trunk/Source/WebKit
- Files:
-
- 1 added
- 11 edited
-
ChangeLog (modified) (1 diff)
-
Shared/ImageExtractionUpdateResult.h (added)
-
Shared/ios/InteractionInformationAtPosition.h (modified) (1 diff)
-
Shared/ios/InteractionInformationAtPosition.mm (modified) (2 diffs)
-
UIProcess/WebPageProxy.cpp (modified) (2 diffs)
-
UIProcess/WebPageProxy.h (modified) (2 diffs)
-
UIProcess/ios/WKContentViewInteraction.mm (modified) (6 diffs)
-
WebKit.xcodeproj/project.pbxproj (modified) (2 diffs)
-
WebProcess/WebPage/WebPage.cpp (modified) (4 diffs)
-
WebProcess/WebPage/WebPage.h (modified) (4 diffs)
-
WebProcess/WebPage/WebPage.messages.in (modified) (1 diff)
-
WebProcess/WebPage/ios/WebPageIOS.mm (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r278391 r278394 1 2021-06-02 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 [iOS] Show data detector context menu on long press inside image overlays 4 https://bugs.webkit.org/show_bug.cgi?id=226559 5 <rdar://problem/78789078> 6 7 Reviewed by Tim Horton. 8 9 Add additional support for data detectors that appear inside image overlays on iOS. 10 11 * Shared/ImageExtractionUpdateResult.h: Added. 12 13 Turn the `bool` propagated back to the UI process when calling `updateWithImageExtractionResult` into a separate 14 three-state enum instead; see changes below for more details. 15 16 * Shared/ios/InteractionInformationAtPosition.h: 17 * Shared/ios/InteractionInformationAtPosition.mm: 18 (WebKit::InteractionInformationAtPosition::encode const): 19 (WebKit::InteractionInformationAtPosition::decode): 20 21 Make some minor adjustments to `InteractionInformationAtPosition`: 22 23 - Add `dataDetectorBounds`, which determines the bounds in root view coordinates of the data detector result 24 corresponding to the hit-tested element. 25 26 - Encode and decode `dataDetectorResults`, even if `isDataDetectorLink` is `false`. Unless the data detector 27 is inside an image overlay, this (effectively) has no impact, since `dataDetectorResults` was previously 28 only set if `isDataDetectorLink` was true. 29 30 * UIProcess/WebPageProxy.cpp: 31 (WebKit::WebPageProxy::updateWithImageExtractionResult): 32 * UIProcess/WebPageProxy.h: 33 * UIProcess/ios/WKContentViewInteraction.mm: 34 (-[WKContentView dataDetectionContextForPositionInformation:]): 35 36 Let `dataDetectorResults` take precedence over regular `bounds` when returning the context for the data 37 detector menu configuration. 38 39 (-[WKContentView positionInformationHasImageOverlayDataDetector]): 40 41 Add a helper method that returns `YES` in the case where the currently cached position information object 42 contains a text data detection result inside an image overlay. 43 44 (-[WKContentView _createTargetedContextMenuHintPreviewIfPossible]): 45 46 Use `dataDetectorBounds` instead of `bounds` when creating a fallback targeted preview for a data detection 47 result in an image overlay. 48 49 (-[WKContentView continueContextMenuInteraction:]): 50 (-[WKContentView continueContextMenuInteractionWithDataDetectors:]): 51 52 Adjust these codepaths so that we'll continue through to the data detector case instead of bailing early in the 53 case where both `isImageOverlayText` is set, and `dataDetectionResults` exist. 54 55 * WebKit.xcodeproj/project.pbxproj: 56 * WebProcess/WebPage/WebPage.cpp: 57 (WebKit::WebPage::findDataDetectionResultElementInImageOverlay): 58 59 Add a static helper to locate a data detector element underneath the given point, inside the given element's 60 image overlay in the user agent shadow root. Note that we check each of the element's bounds instead of using 61 a hit-test because we normally just hit-test to the text containers instead of the data detector containers. 62 63 (WebKit::WebPage::updateWithImageExtractionResult): 64 * WebProcess/WebPage/WebPage.h: 65 * WebProcess/WebPage/WebPage.messages.in: 66 * WebProcess/WebPage/ios/WebPageIOS.mm: 67 (WebKit::dataDetectorLinkPositionInformation): 68 (WebKit::dataDetectorImageOverlayPositionInformation): 69 70 Add a static helper function to populate the given `InteractionInformationAtPosition`, if it's over a data 71 detection result inside an image overlay. 72 73 (WebKit::elementPositionInformation): Call the above helper function. 74 1 75 2021-06-02 Alex Christensen <achristensen@webkit.org> 2 76 -
trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.h
r278253 r278394 95 95 String dataDetectorIdentifier; 96 96 RetainPtr<NSArray> dataDetectorResults; 97 WebCore::IntRect dataDetectorBounds; 97 98 #endif 98 99 -
trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.mm
r278253 r278394 78 78 #if ENABLE(DATA_DETECTION) 79 79 encoder << isDataDetectorLink; 80 if (isDataDetectorLink) { 81 encoder << dataDetectorIdentifier; 82 encoder << dataDetectorResults; 83 } 80 encoder << dataDetectorIdentifier; 81 encoder << dataDetectorResults; 82 encoder << dataDetectorBounds; 84 83 #endif 85 84 #if ENABLE(DATALIST_ELEMENT) … … 190 189 if (!decoder.decode(result.isDataDetectorLink)) 191 190 return false; 192 193 if (result.isDataDetectorLink) { 194 if (!decoder.decode(result.dataDetectorIdentifier)) 195 return false; 196 197 auto dataDetectorResults = IPC::decode<NSArray>(decoder, @[ [NSArray class], getDDScannerResultClass() ]); 198 if (!dataDetectorResults) 199 return false; 200 201 result.dataDetectorResults = WTFMove(*dataDetectorResults); 202 } 191 192 if (!decoder.decode(result.dataDetectorIdentifier)) 193 return false; 194 195 auto dataDetectorResults = IPC::decode<NSArray>(decoder, @[ NSArray.class, getDDScannerResultClass() ]); 196 if (!dataDetectorResults) 197 return false; 198 199 result.dataDetectorResults = WTFMove(*dataDetectorResults); 200 201 if (!decoder.decode(result.dataDetectorBounds)) 202 return false; 203 203 #endif 204 204 -
trunk/Source/WebKit/UIProcess/WebPageProxy.cpp
r278318 r278394 67 67 #include "FormDataReference.h" 68 68 #include "FrameInfoData.h" 69 #include "ImageExtractionUpdateResult.h" 69 70 #include "LegacyGlobalSettings.h" 70 71 #include "LoadParameters.h" … … 8482 8483 } 8483 8484 8484 void WebPageProxy::updateWithImageExtractionResult(ImageExtractionResult&& results, const ElementContext& context, const FloatPoint& location, CompletionHandler<void( bool textExistsAtLocation)>&& completionHandler)8485 void WebPageProxy::updateWithImageExtractionResult(ImageExtractionResult&& results, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&& completionHandler) 8485 8486 { 8486 8487 if (!hasRunningProcess()) { 8487 completionHandler( false);8488 completionHandler(ImageExtractionUpdateResult::NoText); 8488 8489 return; 8489 8490 } -
trunk/Source/WebKit/UIProcess/WebPageProxy.h
r278340 r278394 407 407 struct WebSpeechSynthesisVoice; 408 408 409 enum class ImageExtractionUpdateResult : uint8_t; 409 410 enum class NegotiatedLegacyTLS : bool; 410 411 enum class ProcessSwapRequestedByClient : bool; … … 1665 1666 #if ENABLE(IMAGE_EXTRACTION) 1666 1667 void requestImageExtraction(const URL& imageURL, const ShareableBitmap::Handle& imageData, CompletionHandler<void(WebCore::ImageExtractionResult&&)>&&); 1667 void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void( bool textExistsAtLocation)>&&);1668 void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&&); 1668 1669 void computeCanRevealImage(const URL& imageURL, ShareableBitmap& imageBitmap, CompletionHandler<void(bool)>&&); 1669 1670 #endif -
trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
r278340 r278394 7524 7524 if (positionInformation.isLink) 7525 7525 sourceRect = positionInformation.linkIndicator.textBoundingRectInRootViewCoordinates; 7526 else if (!positionInformation.dataDetectorBounds.isEmpty()) 7527 sourceRect = positionInformation.dataDetectorBounds; 7526 7528 else 7527 7529 sourceRect = positionInformation.bounds; … … 8461 8463 } 8462 8464 8465 - (BOOL)positionInformationHasImageOverlayDataDetector 8466 { 8467 return _positionInformation.isImageOverlayText && [_positionInformation.dataDetectorResults count]; 8468 } 8469 8463 8470 - (UITargetedPreview *)_createTargetedContextMenuHintPreviewIfPossible 8464 8471 { … … 8475 8482 } 8476 8483 8477 if (!targetedPreview) 8478 targetedPreview = createFallbackTargetedPreview(self, self.containerForContextMenuHintPreviews, _positionInformation.bounds, nil); 8484 if (!targetedPreview) { 8485 auto boundsForFallbackPreview = self.positionInformationHasImageOverlayDataDetector ? _positionInformation.dataDetectorBounds : _positionInformation.bounds; 8486 targetedPreview = createFallbackTargetedPreview(self, self.containerForContextMenuHintPreviews, boundsForFallbackPreview, nil); 8487 } 8479 8488 8480 8489 [self _updateTargetedPreviewScrollViewUsingContainerScrollingNodeID:_positionInformation.containerScrollingNodeID]; … … 10282 10291 return continueWithContextMenuConfiguration(nil); 10283 10292 10284 if (!_positionInformation.isLink && !_positionInformation.isImage && !_positionInformation.isAttachment )10293 if (!_positionInformation.isLink && !_positionInformation.isImage && !_positionInformation.isAttachment && !self.positionInformationHasImageOverlayDataDetector) 10285 10294 return continueWithContextMenuConfiguration(nil); 10286 10295 … … 10406 10415 // FIXME: Support JavaScript urls here. But make sure they don't show a preview. 10407 10416 // <rdar://problem/50572283> 10408 if (!linkURL.protocolIsInHTTPFamily() && !WebCore::DataDetection::canBePresentedByDataDetectors(linkURL) ) {10417 if (!linkURL.protocolIsInHTTPFamily() && !WebCore::DataDetection::canBePresentedByDataDetectors(linkURL) && ![strongSelf positionInformationHasImageOverlayDataDetector]) { 10409 10418 continueWithContextMenuConfiguration(nil); 10410 10419 return; … … 10450 10459 10451 10460 #if ENABLE(DATA_DETECTION) 10461 10452 10462 - (void)continueContextMenuInteractionWithDataDetectors:(void(^)(UIContextMenuConfiguration *))continueWithContextMenuConfiguration 10453 10463 { 10454 10464 BEGIN_BLOCK_OBJC_EXCEPTIONS 10455 10465 auto ddContextMenuActionClass = getDDContextMenuActionClass(); 10456 URL linkURL = _positionInformation.url; 10457 NSDictionary *context = [self dataDetectionContextForPositionInformation:_positionInformation]; 10458 UIContextMenuConfiguration *configurationFromDD = [ddContextMenuActionClass contextMenuConfigurationForURL:linkURL identifier:_positionInformation.dataDetectorIdentifier selectedText:[self selectedText] results:_positionInformation.dataDetectorResults.get() inView:self context:context menuIdentifier:nil]; 10466 auto context = retainPtr([self dataDetectionContextForPositionInformation:_positionInformation]); 10467 RetainPtr<UIContextMenuConfiguration> configurationFromDataDetectors; 10468 10469 if (self.positionInformationHasImageOverlayDataDetector) { 10470 DDScannerResult *scannerResult = [_positionInformation.dataDetectorResults firstObject]; 10471 configurationFromDataDetectors = [ddContextMenuActionClass contextMenuConfigurationWithResult:scannerResult.coreResult inView:self context:context.get() menuIdentifier:nil]; 10472 } else { 10473 configurationFromDataDetectors = [ddContextMenuActionClass contextMenuConfigurationForURL:_positionInformation.url identifier:_positionInformation.dataDetectorIdentifier selectedText:[self selectedText] results:_positionInformation.dataDetectorResults.get() inView:self context:context.get() menuIdentifier:nil]; 10474 _page->startInteractionWithPositionInformation(_positionInformation); 10475 } 10476 10459 10477 _contextMenuActionProviderDelegateNeedsOverride = YES; 10460 _page->startInteractionWithPositionInformation(_positionInformation); 10461 continueWithContextMenuConfiguration(configurationFromDD); 10478 continueWithContextMenuConfiguration(configurationFromDataDetectors.get()); 10462 10479 END_BLOCK_OBJC_EXCEPTIONS 10463 10480 } 10464 #endif 10481 10482 #endif // ENABLE(DATA_DETECTION) 10465 10483 10466 10484 - (NSArray<UIMenuElement *> *)_contextMenuInteraction:(UIContextMenuInteraction *)interaction overrideSuggestedActionsForConfiguration:(UIContextMenuConfiguration *)configuration -
trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj
r278370 r278394 5986 5986 F4975CF32624B918003C626E /* WKImageExtractionPreviewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKImageExtractionPreviewController.mm; sourceTree = "<group>"; }; 5987 5987 F4A6D6BB254CA3E900B65FAA /* SharedDisplayListHandle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SharedDisplayListHandle.h; sourceTree = "<group>"; }; 5988 F4A7CE842667EB4E00228685 /* ImageExtractionUpdateResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageExtractionUpdateResult.h; sourceTree = "<group>"; }; 5988 5989 F4AC655E22A3140E00A05607 /* WebPreferencesDefaultValuesIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WebPreferencesDefaultValuesIOS.mm; path = ios/WebPreferencesDefaultValuesIOS.mm; sourceTree = "<group>"; }; 5989 5990 F4B378D021DDBBAB0095A378 /* WebUndoStepID.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebUndoStepID.h; sourceTree = "<group>"; }; … … 6720 6721 F40BBB40257FF46E0067463A /* GPUProcessWakeupMessageArguments.h */, 6721 6722 1AC75A1A1B3368270056745B /* HangDetectionDisabler.h */, 6723 F4A7CE842667EB4E00228685 /* ImageExtractionUpdateResult.h */, 6722 6724 BCCF6B2312C93E7A008F9C35 /* ImageOptions.h */, 6723 6725 999B7ED82550E4A800F450A4 /* InspectorExtensionTypes.cpp */, -
trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp
r278253 r278394 41 41 #include "FrameTreeNodeData.h" 42 42 #include "GeolocationPermissionRequestManager.h" 43 #include "ImageExtractionUpdateResult.h" 43 44 #include "InjectUserScriptImmediately.h" 44 45 #include "InjectedBundle.h" … … 4064 4065 } 4065 4066 4067 std::optional<std::pair<Ref<WebCore::HTMLElement>, WebCore::IntRect>> WebPage::findDataDetectionResultElementInImageOverlay(const FloatPoint& location, const HTMLElement& imageOverlayHost) 4068 { 4069 Vector<Ref<HTMLElement>> dataDetectorElements; 4070 for (auto& child : descendantsOfType<HTMLElement>(*imageOverlayHost.shadowRoot())) { 4071 if (child.isImageOverlayDataDetectorResult()) 4072 dataDetectorElements.append(child); 4073 } 4074 4075 for (auto& element : dataDetectorElements) { 4076 auto elementBounds = element->boundsInRootViewSpace(); 4077 if (elementBounds.contains(roundedIntPoint(location))) 4078 return {{ WTFMove(element), elementBounds }}; 4079 } 4080 4081 return std::nullopt; 4082 } 4083 4066 4084 #endif // ENABLE(DATA_DETECTION) 4067 4085 … … 7459 7477 } 7460 7478 7461 void WebPage::updateWithImageExtractionResult(ImageExtractionResult&& result, const ElementContext& context, const FloatPoint& location, CompletionHandler<void( bool)>&& completionHandler)7479 void WebPage::updateWithImageExtractionResult(ImageExtractionResult&& result, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&& completionHandler) 7462 7480 { 7463 7481 auto elementToUpdate = elementForContext(context); 7464 7482 if (!is<HTMLElement>(elementToUpdate)) { 7465 completionHandler( false);7483 completionHandler(ImageExtractionUpdateResult::NoText); 7466 7484 return; 7467 7485 } … … 7475 7493 7476 7494 auto nodeAtLocation = makeRefPtr(hitTestResult.innerNonSharedNode()); 7477 if (!nodeAtLocation || nodeAtLocation->shadowHost() != elementToUpdate) { 7478 completionHandler(false); 7479 return; 7480 } 7481 7482 completionHandler(HTMLElement::isImageOverlayText(*nodeAtLocation)); 7495 auto updateResult = ([&] { 7496 if (!nodeAtLocation || nodeAtLocation->shadowHost() != elementToUpdate || !HTMLElement::isInsideImageOverlay(*nodeAtLocation)) 7497 return ImageExtractionUpdateResult::NoText; 7498 7499 #if ENABLE(DATA_DETECTION) 7500 if (findDataDetectionResultElementInImageOverlay(location, downcast<HTMLElement>(*elementToUpdate))) 7501 return ImageExtractionUpdateResult::DataDetector; 7502 #endif 7503 7504 if (HTMLElement::isImageOverlayText(*nodeAtLocation)) 7505 return ImageExtractionUpdateResult::Text; 7506 7507 return ImageExtractionUpdateResult::NoText; 7508 })(); 7509 7510 completionHandler(updateResult); 7483 7511 } 7484 7512 -
trunk/Source/WebKit/WebProcess/WebPage/WebPage.h
r278253 r278394 311 311 enum class FindOptions : uint16_t; 312 312 enum class DragControllerAction : uint8_t; 313 enum class ImageExtractionUpdateResult : uint8_t; 313 314 enum class SyntheticEditingCommandType : uint8_t; 314 315 … … 1154 1155 void detectDataInAllFrames(uint64_t, CompletionHandler<void(const DataDetectionResult&)>&&); 1155 1156 void removeDataDetectedLinks(CompletionHandler<void(const DataDetectionResult&)>&&); 1157 void handleClickForDataDetectionResult(const WebCore::DataDetectorElementInfo&, const WebCore::IntPoint&); 1158 static std::optional<std::pair<Ref<WebCore::HTMLElement>, WebCore::IntRect>> findDataDetectionResultElementInImageOverlay(const WebCore::FloatPoint& locationInRootView, const WebCore::HTMLElement& host); 1156 1159 #endif 1157 1160 … … 1175 1178 void handleTelephoneNumberClick(const String& number, const WebCore::IntPoint&); 1176 1179 void handleSelectionServiceClick(WebCore::FrameSelection&, const Vector<String>& telephoneNumbers, const WebCore::IntPoint&); 1177 #endif1178 1179 #if ENABLE(DATA_DETECTION)1180 void handleClickForDataDetectionResult(const WebCore::DataDetectorElementInfo&, const WebCore::IntPoint&);1181 1180 #endif 1182 1181 … … 1405 1404 #if ENABLE(IMAGE_EXTRACTION) 1406 1405 void requestImageExtraction(WebCore::Element&, CompletionHandler<void(RefPtr<WebCore::Element>&&)>&&); 1407 void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void( bool)>&&);1406 void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&&); 1408 1407 #endif 1409 1408 -
trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in
r278253 r278394 644 644 645 645 #if ENABLE(IMAGE_EXTRACTION) 646 UpdateWithImageExtractionResult(struct WebCore::ImageExtractionResult result, struct WebCore::ElementContext element, WebCore::FloatPoint location) -> ( bool textExistsAtLocation) Async646 UpdateWithImageExtractionResult(struct WebCore::ImageExtractionResult result, struct WebCore::ElementContext element, WebCore::FloatPoint location) -> (enum:uint8_t WebKit::ImageExtractionUpdateResult result) Async 647 647 #endif 648 648 } -
trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
r278338 r278394 149 149 #import <wtf/SoftLinking.h> 150 150 #import <wtf/cocoa/Entitlements.h> 151 #import <wtf/text/StringToIntegerConversion.h> 151 152 #import <wtf/text/TextStream.h> 152 153 … … 2748 2749 2749 2750 info.isDataDetectorLink = true; 2751 info.dataDetectorBounds = info.bounds; 2750 2752 const int dataDetectionExtendedContextLength = 350; 2751 2753 info.dataDetectorIdentifier = DataDetection::dataDetectorIdentifier(element); … … 2763 2765 } 2764 2766 2765 #endif 2767 static void dataDetectorImageOverlayPositionInformation(const HTMLElement& overlayHost, const InteractionInformationRequest& request, InteractionInformationAtPosition& info) 2768 { 2769 auto frame = makeRefPtr(overlayHost.document().frame()); 2770 if (!frame) 2771 return; 2772 2773 auto elementAndBounds = WebPage::findDataDetectionResultElementInImageOverlay(request.point, overlayHost); 2774 if (!elementAndBounds) 2775 return; 2776 2777 auto [foundElement, elementBounds] = *elementAndBounds; 2778 auto identifierValue = parseInteger<uint64_t>(foundElement->attributeWithoutSynchronization(HTMLNames::x_apple_data_detectors_resultAttr)); 2779 if (!identifierValue) 2780 return; 2781 2782 auto identifier = makeObjectIdentifier<ImageOverlayDataDetectionResultIdentifierType>(*identifierValue); 2783 if (!identifier.isValid()) 2784 return; 2785 2786 auto* dataDetectionResults = frame->dataDetectionResultsIfExists(); 2787 if (!dataDetectionResults) 2788 return; 2789 2790 auto dataDetectionResult = retainPtr(dataDetectionResults->imageOverlayDataDetectionResult(identifier)); 2791 if (!dataDetectionResult) 2792 return; 2793 2794 info.dataDetectorBounds = WTFMove(elementBounds); 2795 info.dataDetectorResults = @[ dataDetectionResult.get() ]; 2796 } 2797 2798 #endif // ENABLE(DATA_DETECTION) 2766 2799 2767 2800 static std::optional<std::pair<RenderImage&, Image&>> imageRendererAndImage(Element& element) … … 2863 2896 boundsPositionInformation(*renderer, info); 2864 2897 } 2898 2899 #if ENABLE(DATA_DETECTION) 2900 if (info.isImageOverlayText && is<HTMLElement>(element)) 2901 dataDetectorImageOverlayPositionInformation(downcast<HTMLElement>(element), request, info); 2902 #endif 2865 2903 2866 2904 info.elementContext = page.contextForElement(element);
Note:
See TracChangeset
for help on using the changeset viewer.