Title: [242369] trunk/Source
Revision
242369
Author
cdu...@apple.com
Date
2019-03-04 12:20:59 -0800 (Mon, 04 Mar 2019)

Log Message

[iOS] Improve our file picker
https://bugs.webkit.org/show_bug.cgi?id=195284
<rdar://problem/45655856>

Reviewed by Tim Horton and Wenson Hsieh.

Source/WebCore:

Export UTIUtilities.h so that it can be used from WebKit2.

* WebCore.xcodeproj/project.pbxproj:

Source/WebKit:

Improve our file picker on iOS so that:
- Accepted file extensions specified in the HTML (e.g. <input type="file"> accept=".pdf">) are now
  properly reflected in the file picker. Previously, we only we only supported MIME types in the
  accept attribute that only Image / Video ones.
- If accepted types are specified in the HTML and not of them are Video or Image types, then bypass
  the UIDocumentMenuViewController and show the file picker directly (as if the user had tapped on
  "Browse..." on that menu). Other menu items such as "Take Photo or Video" and "Photo Library" do
  not make sense if the page only accepts PDF files for example.

Things that we should do but are not fixed in this patch:
- Stop using UIDocumentMenuViewController entirely since it was deprecated in favor of using
  UIDocumentPickerViewController directly.
- Add multiple selection support, which is supported both on the HTML side and in the
  UIDocumentPickerViewController API.

* UIProcess/ios/forms/WKFileUploadPanel.mm:
(arrayContainsUTIThatConformsTo):
(-[WKFileUploadPanel dealloc]):
(-[WKFileUploadPanel presentWithParameters:resultListener:]):
(UTIsForMIMETypes):
(-[WKFileUploadPanel _mediaTypesForPickerSourceType:]):
(-[WKFileUploadPanel _cameraButtonLabelAllowingPhoto:allowingVideo:]):
(-[WKFileUploadPanel _showDocumentPickerMenu]):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (242368 => 242369)


--- trunk/Source/WebCore/ChangeLog	2019-03-04 19:58:34 UTC (rev 242368)
+++ trunk/Source/WebCore/ChangeLog	2019-03-04 20:20:59 UTC (rev 242369)
@@ -1,3 +1,15 @@
+2019-03-04  Chris Dumez  <cdu...@apple.com>
+
+        [iOS] Improve our file picker
+        https://bugs.webkit.org/show_bug.cgi?id=195284
+        <rdar://problem/45655856>
+
+        Reviewed by Tim Horton and Wenson Hsieh.
+
+        Export UTIUtilities.h so that it can be used from WebKit2.
+
+        * WebCore.xcodeproj/project.pbxproj:
+
 2019-03-04  Zalan Bujtas  <za...@apple.com>
 
         [ContentChangeObserver] Decouple mouseMoved event and the "is observing content change" status.

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (242368 => 242369)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-03-04 19:58:34 UTC (rev 242368)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-03-04 20:20:59 UTC (rev 242369)
@@ -660,7 +660,7 @@
 		1F3C3BEB135CAF3C00B8C1AC /* MediaControls.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F3C3BE9135CAF3C00B8C1AC /* MediaControls.h */; };
 		1F72BF0B187FD45C0009BCB3 /* TileControllerMemoryHandlerIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F72BF09187FD4270009BCB3 /* TileControllerMemoryHandlerIOS.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		1F8756B21E22C3350042C40D /* WebSQLiteDatabaseTrackerClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F8756B11E22BEEF0042C40D /* WebSQLiteDatabaseTrackerClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		1FAFBF1915A5FA7400083A20 /* UTIUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FAFBF1615A5FA5200083A20 /* UTIUtilities.h */; };
+		1FAFBF1915A5FA7400083A20 /* UTIUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FAFBF1615A5FA5200083A20 /* UTIUtilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		1FC40FBA1655CCB90040F29E /* SubimageCacheWithTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC40FB71655C5910040F29E /* SubimageCacheWithTimer.h */; };
 		20D629271253690B00081543 /* InspectorInstrumentation.h in Headers */ = {isa = PBXBuildFile; fileRef = 20D629251253690B00081543 /* InspectorInstrumentation.h */; };
 		225A16B50D5C11E900090295 /* WebEventRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 225A16B30D5C11E900090295 /* WebEventRegion.h */; settings = {ATTRIBUTES = (Private, ); }; };

Modified: trunk/Source/WebCore/platform/network/mac/UTIUtilities.h (242368 => 242369)


--- trunk/Source/WebCore/platform/network/mac/UTIUtilities.h	2019-03-04 19:58:34 UTC (rev 242368)
+++ trunk/Source/WebCore/platform/network/mac/UTIUtilities.h	2019-03-04 20:20:59 UTC (rev 242369)
@@ -32,7 +32,7 @@
 namespace WebCore {
 String MIMETypeFromUTI(const String&);
 String MIMETypeFromUTITree(const String&);
-String UTIFromMIMEType(const String&);
+WEBCORE_EXPORT String UTIFromMIMEType(const String&);
 bool isDeclaredUTI(const String&);
 }
 

Modified: trunk/Source/WebKit/ChangeLog (242368 => 242369)


--- trunk/Source/WebKit/ChangeLog	2019-03-04 19:58:34 UTC (rev 242368)
+++ trunk/Source/WebKit/ChangeLog	2019-03-04 20:20:59 UTC (rev 242369)
@@ -1,3 +1,35 @@
+2019-03-04  Chris Dumez  <cdu...@apple.com>
+
+        [iOS] Improve our file picker
+        https://bugs.webkit.org/show_bug.cgi?id=195284
+        <rdar://problem/45655856>
+
+        Reviewed by Tim Horton and Wenson Hsieh.
+
+        Improve our file picker on iOS so that:
+        - Accepted file extensions specified in the HTML (e.g. <input type="file"> accept=".pdf">) are now
+          properly reflected in the file picker. Previously, we only we only supported MIME types in the
+          accept attribute that only Image / Video ones.
+        - If accepted types are specified in the HTML and not of them are Video or Image types, then bypass
+          the UIDocumentMenuViewController and show the file picker directly (as if the user had tapped on
+          "Browse..." on that menu). Other menu items such as "Take Photo or Video" and "Photo Library" do
+          not make sense if the page only accepts PDF files for example.
+
+        Things that we should do but are not fixed in this patch:
+        - Stop using UIDocumentMenuViewController entirely since it was deprecated in favor of using
+          UIDocumentPickerViewController directly.
+        - Add multiple selection support, which is supported both on the HTML side and in the
+          UIDocumentPickerViewController API.
+
+        * UIProcess/ios/forms/WKFileUploadPanel.mm:
+        (arrayContainsUTIThatConformsTo):
+        (-[WKFileUploadPanel dealloc]):
+        (-[WKFileUploadPanel presentWithParameters:resultListener:]):
+        (UTIsForMIMETypes):
+        (-[WKFileUploadPanel _mediaTypesForPickerSourceType:]):
+        (-[WKFileUploadPanel _cameraButtonLabelAllowingPhoto:allowingVideo:]):
+        (-[WKFileUploadPanel _showDocumentPickerMenu]):
+
 2019-03-04  Alex Christensen  <achristen...@webkit.org>
 
         REGRESSION: ( r240978-r240985 ) [ iOS Release ] Layout Test imported/w3c/web-platform-tests/xhr/send-redirect-post-upload.htm is crashing

Modified: trunk/Source/WebKit/UIProcess/ios/forms/WKFileUploadPanel.mm (242368 => 242369)


--- trunk/Source/WebKit/UIProcess/ios/forms/WKFileUploadPanel.mm	2019-03-04 19:58:34 UTC (rev 242368)
+++ trunk/Source/WebKit/UIProcess/ios/forms/WKFileUploadPanel.mm	2019-03-04 20:20:59 UTC (rev 242369)
@@ -41,8 +41,12 @@
 #import "WebOpenPanelResultListenerProxy.h"
 #import "WebPageProxy.h"
 #import <MobileCoreServices/MobileCoreServices.h>
+#import <UIKit/UIDocumentPickerViewController.h>
 #import <WebCore/LocalizedStrings.h>
+#import <WebCore/MIMETypeRegistry.h>
+#import <WebCore/UTIUtilities.h>
 #import <wtf/RetainPtr.h>
+#import <wtf/text/StringView.h>
 
 using namespace WebKit;
 
@@ -53,6 +57,15 @@
     return mediaCaptureType == WebCore::MediaCaptureTypeUser ? UIImagePickerControllerCameraDeviceFront : UIImagePickerControllerCameraDeviceRear;
 }
 
+static bool arrayContainsUTIThatConformsTo(NSArray<NSString *> *typeIdentifiers, CFStringRef conformToUTI)
+{
+    for (NSString *uti in typeIdentifiers) {
+        if (UTTypeConformsTo((__bridge CFStringRef)uti, conformToUTI))
+            return true;
+    }
+    return false;
+}
+
 #pragma mark - Document picker icons
 
 static inline UIImage *photoLibraryIcon()
@@ -163,6 +176,7 @@
     RetainPtr<UIPopoverController> _presentationPopover; // iPad for action sheet and Photo Library.
     ALLOW_DEPRECATED_DECLARATIONS_END
     RetainPtr<UIDocumentMenuViewController> _documentMenuController;
+    RetainPtr<UIDocumentPickerViewController> _documentPickerController;
     WebCore::MediaCaptureType _mediaCaptureType;
 }
 
@@ -179,6 +193,7 @@
     [_imagePicker setDelegate:nil];
     [_presentationPopover setDelegate:nil];
     [_documentMenuController setDelegate:nil];
+    [_documentPickerController setDelegate:nil];
 
     [super dealloc];
 }
@@ -233,6 +248,14 @@
     NSMutableArray *mimeTypes = [NSMutableArray arrayWithCapacity:acceptMimeTypes->size()];
     for (auto mimeType : acceptMimeTypes->elementsOfType<API::String>())
         [mimeTypes addObject:mimeType->string()];
+
+    Ref<API::Array> acceptFileExtensions = parameters->acceptFileExtensions();
+    for (auto extension : acceptFileExtensions->elementsOfType<API::String>()) {
+        String mimeType = WebCore::MIMETypeRegistry::getMIMETypeForExtension(extension->stringView().substring(1).toString());
+        if (!mimeType.isEmpty())
+            [mimeTypes addObject:mimeType];
+    }
+
     _mimeTypes = adoptNS([mimeTypes copy]);
 
     _mediaCaptureType = WebCore::MediaCaptureTypeNone;
@@ -291,27 +314,14 @@
 
 #pragma mark - Media Types
 
-static bool stringHasPrefixCaseInsensitive(NSString *str, NSString *prefix)
-{
-    NSRange range = [str rangeOfString:prefix options:(NSCaseInsensitiveSearch | NSAnchoredSearch)];
-    return range.location != NSNotFound;
-}
-
 static NSArray *UTIsForMIMETypes(NSArray *mimeTypes)
 {
-    // The HTML5 spec mentions the literal "image/*" and "video/*" strings.
-    // We support these and go a step further, if the MIME type starts with
-    // "image/" or "video/" we adjust the picker's image or video filters.
-    // So, "image/jpeg" would make the picker display all images types.
     NSMutableSet *mediaTypes = [NSMutableSet set];
     for (NSString *mimeType in mimeTypes) {
-        // FIXME: We should support more MIME type -> UTI mappings. <http://webkit.org/b/142614>
-        if (stringHasPrefixCaseInsensitive(mimeType, @"image/"))
-            [mediaTypes addObject:(NSString *)kUTTypeImage];
-        else if (stringHasPrefixCaseInsensitive(mimeType, @"video/"))
-            [mediaTypes addObject:(NSString *)kUTTypeMovie];
+        auto uti = WebCore::UTIFromMIMEType(mimeType);
+        if (!uti.isEmpty())
+            [mediaTypes addObject:(__bridge NSString *)uti];
     }
-
     return mediaTypes.allObjects;
 }
 
@@ -325,16 +335,6 @@
     return [UIImagePickerController availableMediaTypesForSourceType:sourceType];
 }
 
-- (NSArray *)_documentPickerMenuMediaTypes
-{
-    NSArray *mediaTypes = UTIsForMIMETypes(_mimeTypes.get());
-    if (mediaTypes.count)
-        return mediaTypes;
-
-    // Fallback to every supported media type if there is no filter.
-    return @[@"public.item"];
-}
-
 #pragma mark - Source selection menu
 
 - (NSString *)_photoLibraryButtonLabel
@@ -342,20 +342,13 @@
     return WEB_UI_STRING_KEY("Photo Library", "Photo Library (file upload action sheet)", "File Upload alert sheet button string for choosing an existing media item from the Photo Library");
 }
 
-- (NSString *)_cameraButtonLabel
+- (NSString *)_cameraButtonLabelAllowingPhoto:(BOOL)allowPhoto allowingVideo:(BOOL)allowVideo
 {
-    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
-        return nil;
-
-    // Choose the appropriate string for the camera button.
-    NSArray *filteredMediaTypes = [self _mediaTypesForPickerSourceType:UIImagePickerControllerSourceTypeCamera];
-    BOOL containsImageMediaType = [filteredMediaTypes containsObject:(NSString *)kUTTypeImage];
-    BOOL containsVideoMediaType = [filteredMediaTypes containsObject:(NSString *)kUTTypeMovie];
-    ASSERT(containsImageMediaType || containsVideoMediaType);
-    if (containsImageMediaType && containsVideoMediaType)
+    ASSERT(allowPhoto || allowVideo);
+    if (allowPhoto && allowVideo)
         return WEB_UI_STRING_KEY("Take Photo or Video", "Take Photo or Video (file upload action sheet)", "File Upload alert sheet camera button string for taking photos or videos");
 
-    if (containsVideoMediaType)
+    if (allowVideo)
         return WEB_UI_STRING_KEY("Take Video", "Take Video (file upload action sheet)", "File Upload alert sheet camera button string for taking only videos");
 
     return WEB_UI_STRING_KEY("Take Photo", "Take Photo (file upload action sheet)", "File Upload alert sheet camera button string for taking only photos");
@@ -363,25 +356,40 @@
 
 - (void)_showDocumentPickerMenu
 {
-    // FIXME: Support multiple file selection when implemented. <rdar://17177981>
-    _documentMenuController = adoptNS([[UIDocumentMenuViewController alloc] _initIgnoringApplicationEntitlementForImportOfTypes:[self _documentPickerMenuMediaTypes]]);
-    [_documentMenuController setDelegate:self];
+    NSArray *mediaTypes = UTIsForMIMETypes(_mimeTypes.get());
 
-    [_documentMenuController addOptionWithTitle:[self _photoLibraryButtonLabel] image:photoLibraryIcon() order:UIDocumentMenuOrderFirst handler:^{
-        [self _showPhotoPickerWithSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
-    }];
+    BOOL containsImageMediaType = !mediaTypes.count || arrayContainsUTIThatConformsTo(mediaTypes, kUTTypeImage);
+    BOOL containsVideoMediaType = !mediaTypes.count || arrayContainsUTIThatConformsTo(mediaTypes, kUTTypeMovie);
 
-    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
-        if (NSString *cameraString = [self _cameraButtonLabel]) {
+    NSArray *documentTypes = mediaTypes.count ? mediaTypes : @[(__bridge NSString *)kUTTypeItem];
+    if (containsImageMediaType || containsVideoMediaType) {
+        // FIXME: UIDocumentMenuViewController is deprecated, we should use UIDocumentPickerViewController instead.
+        // FIXME: Support multiple file selection when implemented. <rdar://17177981>
+        _documentMenuController = adoptNS([[UIDocumentMenuViewController alloc] _initIgnoringApplicationEntitlementForImportOfTypes:documentTypes]);
+        [_documentMenuController setDelegate:self];
+
+        [_documentMenuController addOptionWithTitle:[self _photoLibraryButtonLabel] image:photoLibraryIcon() order:UIDocumentMenuOrderFirst handler:^{
+            [self _showPhotoPickerWithSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
+        }];
+
+        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
+            NSString *cameraString = [self _cameraButtonLabelAllowingPhoto:containsImageMediaType allowingVideo:containsVideoMediaType];
             [_documentMenuController addOptionWithTitle:cameraString image:cameraIcon() order:UIDocumentMenuOrderFirst handler:^{
                 _usingCamera = YES;
                 [self _showPhotoPickerWithSourceType:UIImagePickerControllerSourceTypeCamera];
             }];
         }
+
+        [self _presentMenuOptionForCurrentInterfaceIdiom:_documentMenuController.get()];
+    } else {
+        // Image and Video types are not accepted so bypass the menu and open the file picker directly.
+        // FIXME: Support multiple file selection when implemented. <rdar://17177981>
+        _documentPickerController = adoptNS([[UIDocumentPickerViewController alloc] initWithDocumentTypes:documentTypes inMode:UIDocumentPickerModeImport]);
+        [_documentPickerController setDelegate:self];
+        [self _presentFullscreenViewController:_documentPickerController.get() animated:YES];
     }
 
-    [self _presentMenuOptionForCurrentInterfaceIdiom:_documentMenuController.get()];
-    // Clear out the view controller we just presented. Don't save a reference to the UIDocumentMenuViewController as it is self dismissing.
+    // Clear out the view controller we just presented. Don't save a reference to the UIDocumentMenuViewController / UIDocumentPickerViewController as it is self dismissing.
     _presentationViewController = nil;
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to