Update service picker API usage.
[WebKit-https.git] / Source / WebKit / mac / Misc / WebSharingServicePickerController.mm
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "WebSharingServicePickerController.h"
27
28 #if ENABLE(SERVICE_CONTROLS)
29
30 #import "WebContextMenuClient.h"
31 #import "WebViewInternal.h"
32 #import <AppKit/NSSharingService.h>
33 #import <WebCore/BitmapImage.h>
34 #import <WebCore/Editor.h>
35 #import <WebCore/FocusController.h>
36 #import <WebCore/Frame.h>
37 #import <WebCore/FrameSelection.h>
38 #import <WebCore/ContextMenuController.h>
39 #import <WebCore/Page.h>
40
41 #if __has_include(<AppKit/NSSharingService_Private.h>)
42 #import <AppKit/NSSharingService_Private.h>
43 #else
44 typedef enum {
45     NSSharingServicePickerStyleRollover = 1
46 } NSSharingServicePickerStyle;
47
48 @interface NSSharingServicePicker (Private)
49 @property NSSharingServicePickerStyle style;
50 - (NSMenu *)menu;
51 @end
52 #endif
53
54 #if __has_include(<AppKit/NSItemProvider.h>)
55 #import <AppKit/NSItemProvider.h>
56 #else
57 @interface NSItemProvider : NSObject
58 @property (copy, readonly) NSArray *registeredTypeIdentifiers;
59 - (instancetype)initWithItem:(id <NSSecureCoding>)item typeIdentifier:(NSString *)typeIdentifier;
60 - (void)loadItemForTypeIdentifier:(NSString *)typeIdentifier options:(NSDictionary *)options completionHandler:(void (^)(id <NSSecureCoding> item, NSError *error))completionHandler;
61 @end
62 #endif
63
64 static NSString *serviceControlsPasteboardName = @"WebKitServiceControlsPasteboard";
65
66 using namespace WebCore;
67
68 @implementation WebSharingServicePickerController
69
70 - (instancetype)initWithData:(NSData *)data includeEditorServices:(BOOL)includeEditorServices menuClient:(WebContextMenuClient*)menuClient
71 {
72     if (!(self = [super init]))
73         return nil;
74
75     RetainPtr<NSItemProvider> itemProvider = adoptNS([[NSItemProvider alloc] initWithItem:data typeIdentifier:@"public.data"]);
76
77     _picker = adoptNS([[NSSharingServicePicker alloc] initWithItems:@[ itemProvider.get() ]]);
78     [_picker setStyle:NSSharingServicePickerStyleRollover];
79     [_picker setDelegate:self];
80
81     _includeEditorServices = includeEditorServices;
82     _menuClient = menuClient;
83
84     return self;
85 }
86
87 - (void)clear
88 {
89     _menuClient->clearSharingServicePickerController();
90
91     _picker = nullptr;
92     _menuClient = nullptr;
93 }
94
95 - (NSMenu *)menu
96 {
97     return [_picker menu];
98 }
99
100 - (void)didShareImageData:(NSData *)data confirmDataIsValidTIFFData:(BOOL)confirmData
101 {
102     Page* page = [_menuClient->webView() page];
103     if (!page)
104         return;
105
106     if (confirmData) {
107         RetainPtr<NSImage> nsImage = adoptNS([[NSImage alloc] initWithData:data]);
108         if (!nsImage) {
109             LOG_ERROR("Shared image data cannot create a valid NSImage");
110             return;
111         }
112
113         data = [nsImage TIFFRepresentation];
114     }
115
116     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:serviceControlsPasteboardName];
117     [pasteboard declareTypes:@[ NSPasteboardTypeTIFF ] owner:nil];
118     [pasteboard setData:data forType:NSPasteboardTypeTIFF];
119
120     Frame& frame = page->focusController().focusedOrMainFrame();
121     if (!frame.selection().isNone())
122         frame.editor().readSelectionFromPasteboard(serviceControlsPasteboardName);
123
124     [self clear];
125 }
126
127 #pragma mark NSSharingServicePickerDelegate methods
128
129 - (NSArray *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items mask:(NSSharingServiceMask)mask proposedSharingServices:(NSArray *)proposedServices
130 {
131     if (_includeEditorServices)
132         return proposedServices;
133         
134     NSMutableArray *services = [[NSMutableArray alloc] initWithCapacity:[proposedServices count]];
135     
136     for (NSSharingService *service in proposedServices) {
137         if (service.type != NSSharingServiceTypeEditor)
138             [services addObject:service];
139     }
140     
141     return services;
142 }
143
144 - (id <NSSharingServiceDelegate>)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker delegateForSharingService:(NSSharingService *)sharingService
145 {
146     return self;
147 }
148
149 - (void)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker didChooseSharingService:(NSSharingService *)service
150 {
151     if (!service)
152         _menuClient->clearSharingServicePickerController();
153 }
154
155 #pragma mark NSSharingServiceDelegate methods
156
157 - (void)sharingService:(NSSharingService *)sharingService didShareItems:(NSArray *)items
158 {
159     // We only send one item, so we should only get one item back.
160     if ([items count] != 1)
161         return;
162
163     id item = [items objectAtIndex:0];
164
165     if ([item isKindOfClass:[NSImage class]])
166         [self didShareImageData:[item TIFFRepresentation] confirmDataIsValidTIFFData:NO];
167     else if ([item isKindOfClass:[NSItemProvider class]]) {
168         NSItemProvider *itemProvider = (NSItemProvider *)item;
169         NSString *itemUTI = itemProvider.registeredTypeIdentifiers.firstObject;
170         
171         [itemProvider loadItemForTypeIdentifier:itemUTI options:nil completionHandler:^(id receivedData, NSError *dataError) {
172             if (!receivedData) {
173                 LOG_ERROR("Did not receive data from NSItemProvider");
174                 return;
175             }
176
177             if (![receivedData isKindOfClass:[NSData class]]) {
178                 LOG_ERROR("Data received from NSItemProvider is not of type NSData");
179                 return;
180             }
181
182             [[NSOperationQueue mainQueue] addOperationWithBlock:^{
183                 [self didShareImageData:receivedData confirmDataIsValidTIFFData:YES];
184             }];
185
186         }];
187     } else
188         LOG_ERROR("sharingService:didShareItems: - Unknown item type returned");
189 }
190
191 - (void)sharingService:(NSSharingService *)sharingService didFailToShareItems:(NSArray *)items error:(NSError *)error
192 {
193     [self clear];
194 }
195
196 - (NSWindow *)sharingService:(NSSharingService *)sharingService sourceWindowForShareItems:(NSArray *)items sharingContentScope:(NSSharingContentScope *)sharingContentScope
197 {
198     return [_menuClient->webView() window];
199 }
200
201 @end
202
203 #endif