OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/app/spotlight/base_spotlight_manager.h" | 5 #import "ios/chrome/app/spotlight/base_spotlight_manager.h" |
6 | 6 |
7 #import <CommonCrypto/CommonCrypto.h> | 7 #import <CommonCrypto/CommonCrypto.h> |
8 #import <MobileCoreServices/MobileCoreServices.h> | 8 #import <MobileCoreServices/MobileCoreServices.h> |
9 | 9 |
10 #include "base/ios/weak_nsobject.h" | |
11 #include "base/mac/bind_objc_block.h" | 10 #include "base/mac/bind_objc_block.h" |
12 #include "base/strings/sys_string_conversions.h" | 11 #include "base/strings/sys_string_conversions.h" |
13 #include "base/task/cancelable_task_tracker.h" | 12 #include "base/task/cancelable_task_tracker.h" |
14 #include "components/favicon/core/fallback_url_util.h" | 13 #include "components/favicon/core/fallback_url_util.h" |
15 #include "components/favicon/core/large_icon_service.h" | 14 #include "components/favicon/core/large_icon_service.h" |
16 #include "components/favicon_base/fallback_icon_style.h" | 15 #include "components/favicon_base/fallback_icon_style.h" |
17 #include "components/favicon_base/favicon_types.h" | 16 #include "components/favicon_base/favicon_types.h" |
18 #include "ios/chrome/grit/ios_strings.h" | 17 #include "ios/chrome/grit/ios_strings.h" |
19 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" | 18 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" |
20 #include "ios/public/provider/chrome/browser/spotlight/spotlight_provider.h" | 19 #include "ios/public/provider/chrome/browser/spotlight/spotlight_provider.h" |
21 #import "ios/third_party/material_components_ios/src/components/Typography/src/M
aterialTypography.h" | 20 #import "ios/third_party/material_components_ios/src/components/Typography/src/M
aterialTypography.h" |
22 #import "net/base/mac/url_conversions.h" | 21 #import "net/base/mac/url_conversions.h" |
23 #include "skia/ext/skia_utils_ios.h" | 22 #include "skia/ext/skia_utils_ios.h" |
24 #include "ui/base/l10n/l10n_util.h" | 23 #include "ui/base/l10n/l10n_util.h" |
25 | 24 |
| 25 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 26 #error "This file requires ARC support." |
| 27 #endif |
| 28 |
26 namespace { | 29 namespace { |
27 // Minimum size of the icon to be used in Spotlight. | 30 // Minimum size of the icon to be used in Spotlight. |
28 const NSInteger kMinIconSize = 32; | 31 const NSInteger kMinIconSize = 32; |
29 | 32 |
30 // Preferred size of the icon to be used in Spotlight. | 33 // Preferred size of the icon to be used in Spotlight. |
31 const NSInteger kIconSize = 64; | 34 const NSInteger kIconSize = 64; |
32 | 35 |
33 // Size of the fallback icon. | 36 // Size of the fallback icon. |
34 const CGFloat kFallbackIconSize = 180; | 37 const CGFloat kFallbackIconSize = 180; |
35 | 38 |
36 // Radius of the rounded corner of the fallback icon. | 39 // Radius of the rounded corner of the fallback icon. |
37 const CGFloat kFallbackRoundedCorner = 8; | 40 const CGFloat kFallbackRoundedCorner = 8; |
38 } | 41 } |
39 | 42 |
40 @interface BaseSpotlightManager () { | 43 @interface BaseSpotlightManager () { |
41 // Domain of the spotlight manager. | 44 // Domain of the spotlight manager. |
42 spotlight::Domain _spotlightDomain; | 45 spotlight::Domain _spotlightDomain; |
43 | 46 |
44 // Service to retrieve large favicon or colors for a fallback icon. | 47 // Service to retrieve large favicon or colors for a fallback icon. |
45 favicon::LargeIconService* _largeIconService; // weak | 48 favicon::LargeIconService* _largeIconService; // weak |
46 | 49 |
47 // Queue to query large icons. | 50 // Queue to query large icons. |
48 base::CancelableTaskTracker _largeIconTaskTracker; | 51 base::CancelableTaskTracker _largeIconTaskTracker; |
49 | 52 |
50 // Dictionary to track the tasks querying the large icons. | 53 // Dictionary to track the tasks querying the large icons. |
51 base::scoped_nsobject<NSMutableDictionary> _pendingTasks; | 54 NSMutableDictionary* _pendingTasks; |
52 } | 55 } |
53 | 56 |
54 // Compute a hash consisting of the first 8 bytes of the MD5 hash of a string | 57 // Compute a hash consisting of the first 8 bytes of the MD5 hash of a string |
55 // containing |URL| and |title|. | 58 // containing |URL| and |title|. |
56 - (int64_t)getHashForURL:(const GURL&)URL title:(NSString*)title; | 59 - (int64_t)getHashForURL:(const GURL&)URL title:(NSString*)title; |
57 | 60 |
58 // Create an image with a rounded square with color |backgroundColor| and | 61 // Create an image with a rounded square with color |backgroundColor| and |
59 // |string| centered in color |textColor|. | 62 // |string| centered in color |textColor|. |
60 UIImage* GetFallbackImageWithStringAndColor(NSString* string, | 63 UIImage* GetFallbackImageWithStringAndColor(NSString* string, |
61 UIColor* backgroundColor, | 64 UIColor* backgroundColor, |
62 UIColor* textColor); | 65 UIColor* textColor); |
63 | 66 |
64 // Returns an array of Keywords for Spotlight search. | 67 // Returns an array of Keywords for Spotlight search. |
65 - (NSArray*)keywordsForSpotlightItems; | 68 - (NSArray*)keywordsForSpotlightItems; |
66 | 69 |
67 @end | 70 @end |
68 | 71 |
69 @implementation BaseSpotlightManager | 72 @implementation BaseSpotlightManager |
70 | 73 |
71 - (instancetype)initWithLargeIconService: | 74 - (instancetype)initWithLargeIconService: |
72 (favicon::LargeIconService*)largeIconService | 75 (favicon::LargeIconService*)largeIconService |
73 domain:(spotlight::Domain)domain { | 76 domain:(spotlight::Domain)domain { |
74 self = [super init]; | 77 self = [super init]; |
75 if (self) { | 78 if (self) { |
76 _spotlightDomain = domain; | 79 _spotlightDomain = domain; |
77 _largeIconService = largeIconService; | 80 _largeIconService = largeIconService; |
78 _pendingTasks.reset([[NSMutableDictionary alloc] init]); | 81 _pendingTasks = [[NSMutableDictionary alloc] init]; |
79 } | 82 } |
80 return self; | 83 return self; |
81 } | 84 } |
82 | 85 |
83 - (instancetype)init { | 86 - (instancetype)init { |
84 NOTREACHED(); | 87 NOTREACHED(); |
85 return nil; | 88 return nil; |
86 } | 89 } |
87 | 90 |
88 - (int64_t)getHashForURL:(const GURL&)URL title:(NSString*)title { | 91 - (int64_t)getHashForURL:(const GURL&)URL title:(NSString*)title { |
(...skipping 21 matching lines...) Expand all Loading... |
110 } | 113 } |
111 | 114 |
112 - (void)clearAllSpotlightItems:(BlockWithError)callback { | 115 - (void)clearAllSpotlightItems:(BlockWithError)callback { |
113 [self cancelAllLargeIconPendingTasks]; | 116 [self cancelAllLargeIconPendingTasks]; |
114 spotlight::DeleteSearchableDomainItems(_spotlightDomain, callback); | 117 spotlight::DeleteSearchableDomainItems(_spotlightDomain, callback); |
115 } | 118 } |
116 | 119 |
117 - (CSSearchableItem*)spotlightItemWithItemID:(NSString*)itemID | 120 - (CSSearchableItem*)spotlightItemWithItemID:(NSString*)itemID |
118 attributeSet:(CSSearchableItemAttributeSet*) | 121 attributeSet:(CSSearchableItemAttributeSet*) |
119 attributeSet { | 122 attributeSet { |
120 CSCustomAttributeKey* key = [[[CSCustomAttributeKey alloc] | 123 CSCustomAttributeKey* key = [[CSCustomAttributeKey alloc] |
121 initWithKeyName:spotlight::GetSpotlightCustomAttributeItemID() | 124 initWithKeyName:spotlight::GetSpotlightCustomAttributeItemID() |
122 searchable:YES | 125 searchable:YES |
123 searchableByDefault:YES | 126 searchableByDefault:YES |
124 unique:YES | 127 unique:YES |
125 multiValued:NO] autorelease]; | 128 multiValued:NO]; |
126 [attributeSet setValue:itemID forCustomKey:key]; | 129 [attributeSet setValue:itemID forCustomKey:key]; |
127 attributeSet.keywords = [self keywordsForSpotlightItems]; | 130 attributeSet.keywords = [self keywordsForSpotlightItems]; |
128 | 131 |
129 NSString* domainID = spotlight::StringFromSpotlightDomain(_spotlightDomain); | 132 NSString* domainID = spotlight::StringFromSpotlightDomain(_spotlightDomain); |
130 | 133 |
131 return [[[CSSearchableItem alloc] initWithUniqueIdentifier:itemID | 134 return [[CSSearchableItem alloc] initWithUniqueIdentifier:itemID |
132 domainIdentifier:domainID | 135 domainIdentifier:domainID |
133 attributeSet:attributeSet] | 136 attributeSet:attributeSet]; |
134 autorelease]; | |
135 } | 137 } |
136 | 138 |
137 - (NSArray*)spotlightItemsWithURL:(const GURL&)indexedURL | 139 - (NSArray*)spotlightItemsWithURL:(const GURL&)indexedURL |
138 favicon:(UIImage*)favicon | 140 favicon:(UIImage*)favicon |
139 defaultTitle:(NSString*)defaultTitle { | 141 defaultTitle:(NSString*)defaultTitle { |
140 DCHECK(defaultTitle); | 142 DCHECK(defaultTitle); |
141 NSURL* nsURL = net::NSURLWithGURL(indexedURL); | 143 NSURL* nsURL = net::NSURLWithGURL(indexedURL); |
142 std::string description = indexedURL.SchemeIsCryptographic() | 144 std::string description = indexedURL.SchemeIsCryptographic() |
143 ? indexedURL.GetOrigin().spec() | 145 ? indexedURL.GetOrigin().spec() |
144 : indexedURL.spec(); | 146 : indexedURL.spec(); |
145 | 147 |
146 base::scoped_nsobject<CSSearchableItemAttributeSet> attributeSet( | 148 CSSearchableItemAttributeSet* attributeSet = |
147 [[CSSearchableItemAttributeSet alloc] | 149 [[CSSearchableItemAttributeSet alloc] |
148 initWithItemContentType:(NSString*)kUTTypeURL]); | 150 initWithItemContentType:(NSString*)kUTTypeURL]; |
149 [attributeSet setTitle:defaultTitle]; | 151 [attributeSet setTitle:defaultTitle]; |
150 [attributeSet setDisplayName:defaultTitle]; | 152 [attributeSet setDisplayName:defaultTitle]; |
151 [attributeSet setURL:nsURL]; | 153 [attributeSet setURL:nsURL]; |
152 [attributeSet setContentURL:nsURL]; | 154 [attributeSet setContentURL:nsURL]; |
153 [attributeSet setContentDescription:base::SysUTF8ToNSString(description)]; | 155 [attributeSet setContentDescription:base::SysUTF8ToNSString(description)]; |
154 [attributeSet setThumbnailData:UIImagePNGRepresentation(favicon)]; | 156 [attributeSet setThumbnailData:UIImagePNGRepresentation(favicon)]; |
155 | 157 |
156 NSString* itemID = [self spotlightIDForURL:indexedURL title:defaultTitle]; | 158 NSString* itemID = [self spotlightIDForURL:indexedURL title:defaultTitle]; |
157 return [NSArray arrayWithObject:[self spotlightItemWithItemID:itemID | 159 return [NSArray arrayWithObject:[self spotlightItemWithItemID:itemID |
158 attributeSet:attributeSet]]; | 160 attributeSet:attributeSet]]; |
159 } | 161 } |
160 | 162 |
161 UIImage* GetFallbackImageWithStringAndColor(NSString* string, | 163 UIImage* GetFallbackImageWithStringAndColor(NSString* string, |
162 UIColor* backgroundColor, | 164 UIColor* backgroundColor, |
163 UIColor* textColor) { | 165 UIColor* textColor) { |
164 CGRect rect = CGRectMake(0, 0, kFallbackIconSize, kFallbackIconSize); | 166 CGRect rect = CGRectMake(0, 0, kFallbackIconSize, kFallbackIconSize); |
165 UIGraphicsBeginImageContext(rect.size); | 167 UIGraphicsBeginImageContext(rect.size); |
166 CGContextRef context = UIGraphicsGetCurrentContext(); | 168 CGContextRef context = UIGraphicsGetCurrentContext(); |
167 CGContextSetFillColorWithColor(context, [backgroundColor CGColor]); | 169 CGContextSetFillColorWithColor(context, [backgroundColor CGColor]); |
168 CGContextSetStrokeColorWithColor(context, [textColor CGColor]); | 170 CGContextSetStrokeColorWithColor(context, [textColor CGColor]); |
169 UIBezierPath* rounded = | 171 UIBezierPath* rounded = |
170 [UIBezierPath bezierPathWithRoundedRect:rect | 172 [UIBezierPath bezierPathWithRoundedRect:rect |
171 cornerRadius:kFallbackRoundedCorner]; | 173 cornerRadius:kFallbackRoundedCorner]; |
172 [rounded fill]; | 174 [rounded fill]; |
173 UIFont* font = [MDCTypography headlineFont]; | 175 UIFont* font = [MDCTypography headlineFont]; |
174 font = [font fontWithSize:(kFallbackIconSize / 2)]; | 176 font = [font fontWithSize:(kFallbackIconSize / 2)]; |
175 CGRect textRect = CGRectMake(0, (kFallbackIconSize - [font lineHeight]) / 2, | 177 CGRect textRect = CGRectMake(0, (kFallbackIconSize - [font lineHeight]) / 2, |
176 kFallbackIconSize, [font lineHeight]); | 178 kFallbackIconSize, [font lineHeight]); |
177 base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( | 179 NSMutableParagraphStyle* paragraphStyle = |
178 [[NSMutableParagraphStyle alloc] init]); | 180 [[NSMutableParagraphStyle alloc] init]; |
179 [paragraphStyle setAlignment:NSTextAlignmentCenter]; | 181 [paragraphStyle setAlignment:NSTextAlignmentCenter]; |
180 base::scoped_nsobject<NSMutableDictionary> attributes( | 182 NSMutableDictionary* attributes = [[NSMutableDictionary alloc] init]; |
181 [[NSMutableDictionary alloc] init]); | |
182 [attributes setValue:font forKey:NSFontAttributeName]; | 183 [attributes setValue:font forKey:NSFontAttributeName]; |
183 [attributes setValue:textColor forKey:NSForegroundColorAttributeName]; | 184 [attributes setValue:textColor forKey:NSForegroundColorAttributeName]; |
184 [attributes setValue:paragraphStyle forKey:NSParagraphStyleAttributeName]; | 185 [attributes setValue:paragraphStyle forKey:NSParagraphStyleAttributeName]; |
185 | 186 |
186 [string drawInRect:textRect withAttributes:attributes]; | 187 [string drawInRect:textRect withAttributes:attributes]; |
187 UIImage* image = UIGraphicsGetImageFromCurrentImageContext(); | 188 UIImage* image = UIGraphicsGetImageFromCurrentImageContext(); |
188 UIGraphicsEndImageContext(); | 189 UIGraphicsEndImageContext(); |
189 return image; | 190 return image; |
190 } | 191 } |
191 | 192 |
192 - (void)refreshItemsWithURL:(const GURL&)URLToRefresh title:(NSString*)title { | 193 - (void)refreshItemsWithURL:(const GURL&)URLToRefresh title:(NSString*)title { |
193 NSURL* NSURL = net::NSURLWithGURL(URLToRefresh); | 194 NSURL* NSURL = net::NSURLWithGURL(URLToRefresh); |
194 | 195 |
195 if (!NSURL || [_pendingTasks objectForKey:NSURL]) { | 196 if (!NSURL || [_pendingTasks objectForKey:NSURL]) { |
196 return; | 197 return; |
197 } | 198 } |
198 | 199 |
199 base::WeakNSObject<BaseSpotlightManager> weakSelf(self); | 200 __weak BaseSpotlightManager* weakSelf = self; |
200 GURL URL = URLToRefresh; | 201 GURL URL = URLToRefresh; |
201 void (^faviconBlock)(const favicon_base::LargeIconResult&) = ^( | 202 void (^faviconBlock)(const favicon_base::LargeIconResult&) = ^( |
202 const favicon_base::LargeIconResult& result) { | 203 const favicon_base::LargeIconResult& result) { |
203 base::scoped_nsobject<BaseSpotlightManager> strongSelf([weakSelf retain]); | 204 BaseSpotlightManager* strongSelf = weakSelf; |
204 if (!strongSelf) { | 205 if (!strongSelf) { |
205 return; | 206 return; |
206 } | 207 } |
207 [strongSelf.get()->_pendingTasks removeObjectForKey:NSURL]; | 208 [strongSelf->_pendingTasks removeObjectForKey:NSURL]; |
208 UIImage* favicon; | 209 UIImage* favicon; |
209 if (result.bitmap.is_valid()) { | 210 if (result.bitmap.is_valid()) { |
210 scoped_refptr<base::RefCountedMemory> data = | 211 scoped_refptr<base::RefCountedMemory> data = |
211 result.bitmap.bitmap_data.get(); | 212 result.bitmap.bitmap_data.get(); |
212 favicon = [UIImage | 213 favicon = [UIImage |
213 imageWithData:[NSData dataWithBytes:data->front() length:data->size()] | 214 imageWithData:[NSData dataWithBytes:data->front() length:data->size()] |
214 scale:[UIScreen mainScreen].scale]; | 215 scale:[UIScreen mainScreen].scale]; |
215 } else { | 216 } else { |
216 NSString* iconText = | 217 NSString* iconText = |
217 base::SysUTF16ToNSString(favicon::GetFallbackIconText(URL)); | 218 base::SysUTF16ToNSString(favicon::GetFallbackIconText(URL)); |
(...skipping 12 matching lines...) Expand all Loading... |
230 [[CSSearchableIndex defaultSearchableIndex] | 231 [[CSSearchableIndex defaultSearchableIndex] |
231 indexSearchableItems:spotlightItems | 232 indexSearchableItems:spotlightItems |
232 completionHandler:nil]; | 233 completionHandler:nil]; |
233 } | 234 } |
234 }; | 235 }; |
235 | 236 |
236 base::CancelableTaskTracker::TaskId taskID = | 237 base::CancelableTaskTracker::TaskId taskID = |
237 _largeIconService->GetLargeIconOrFallbackStyle( | 238 _largeIconService->GetLargeIconOrFallbackStyle( |
238 URL, kMinIconSize * [UIScreen mainScreen].scale, | 239 URL, kMinIconSize * [UIScreen mainScreen].scale, |
239 kIconSize * [UIScreen mainScreen].scale, | 240 kIconSize * [UIScreen mainScreen].scale, |
240 base::BindBlock(faviconBlock), &_largeIconTaskTracker); | 241 base::BindBlockArc(faviconBlock), &_largeIconTaskTracker); |
241 [_pendingTasks setObject:[NSNumber numberWithLongLong:taskID] forKey:NSURL]; | 242 [_pendingTasks setObject:[NSNumber numberWithLongLong:taskID] forKey:NSURL]; |
242 } | 243 } |
243 | 244 |
244 - (NSUInteger)pendingLargeIconTasksCount { | 245 - (NSUInteger)pendingLargeIconTasksCount { |
245 return [_pendingTasks count]; | 246 return [_pendingTasks count]; |
246 } | 247 } |
247 | 248 |
248 #pragma mark private methods | 249 #pragma mark private methods |
249 | 250 |
250 - (NSArray*)keywordsForSpotlightItems { | 251 - (NSArray*)keywordsForSpotlightItems { |
(...skipping 12 matching lines...) Expand all Loading... |
263 NSArray* additionalArray = ios::GetChromeBrowserProvider() | 264 NSArray* additionalArray = ios::GetChromeBrowserProvider() |
264 ->GetSpotlightProvider() | 265 ->GetSpotlightProvider() |
265 ->GetAdditionalKeywords(); | 266 ->GetAdditionalKeywords(); |
266 if (additionalArray) { | 267 if (additionalArray) { |
267 [keywordsArray addObjectsFromArray:additionalArray]; | 268 [keywordsArray addObjectsFromArray:additionalArray]; |
268 } | 269 } |
269 return keywordsArray; | 270 return keywordsArray; |
270 } | 271 } |
271 | 272 |
272 @end | 273 @end |
OLD | NEW |