Modified: trunk/Source/WebKit2/ChangeLog (185356 => 185357)
--- trunk/Source/WebKit2/ChangeLog 2015-06-09 07:45:12 UTC (rev 185356)
+++ trunk/Source/WebKit2/ChangeLog 2015-06-09 08:18:31 UTC (rev 185357)
@@ -1,3 +1,44 @@
+2015-06-02 Jon Honeycutt <[email protected]>
+
+ [iOS] UI process memory spike, hang when uploading a very large JPEG
+
+ <https://bugs.webkit.org/show_bug.cgi?id=145567>
+ <rdar://problem/21206699>
+
+ When uploading an image, we generate a thumbnail to use for an icon
+ that sits next to the control. To do this, we load the image and draw
+ it into a thumbnail-sized canvas. This can be very expensive for large
+ images.
+
+ To fix this, we'll use CGImageSource API, which will allow us to get
+ any existing thumbnail that exists in the source file.
+
+ Reviewed by Darin Adler.
+
+ * UIProcess/ios/forms/WKFileUploadPanel.mm:
+ (squareCropRectForSize):
+ Use std::round, based on Darin's review feedback that a) rintf is
+ incorrect in 64-bit systems where CGFloat is a double, b) rintf uses a
+ variable rounding mode, which is undesirable.
+ (squareImage):
+ Changed to take a CGImageRef.
+ Use RetainPtr and +[UIImage imageWithCGImage:] to match other code in
+ this file.
+ (thumbnailSizedImageForImage):
+ Changed to take a CGImageRef and to use iconSideLength.
+ (iconForImageFile):
+ Create an image source for the file, then use CGImageSource API to
+ generate a thumbnail.
+ (-[_WKImageFileUploadItem initWithFileURL:originalImage:]): Deleted.
+ (-[_WKImageFileUploadItem displayImage]):
+ Use iconForImageFile() rather than trying to generate an icon from the
+ UIImage.
+ (-[WKFileUploadPanel _uploadItemForImageData:imageName:successBlock:failureBlock:]):
+ Removed originalImage parameter; _WKImageFileUploadItem no longer uses
+ it.
+ (-[WKFileUploadPanel _uploadItemForJPEGRepresentationOfImage:successBlock:failureBlock:]):
+ (-[WKFileUploadPanel _uploadItemForImage:withAssetURL:successBlock:failureBlock:]):
+
2015-06-08 Dan Bernstein <[email protected]>
[Cocoa] Use generics in framework headers
Modified: trunk/Source/WebKit2/UIProcess/ios/forms/WKFileUploadPanel.mm (185356 => 185357)
--- trunk/Source/WebKit2/UIProcess/ios/forms/WKFileUploadPanel.mm 2015-06-09 07:45:12 UTC (rev 185356)
+++ trunk/Source/WebKit2/UIProcess/ios/forms/WKFileUploadPanel.mm 2015-06-09 08:18:31 UTC (rev 185357)
@@ -90,43 +90,42 @@
#pragma mark - Icon generation
+static const CGFloat iconSideLength = 100;
+
static CGRect squareCropRectForSize(CGSize size)
{
CGFloat smallerSide = MIN(size.width, size.height);
CGRect cropRect = CGRectMake(0, 0, smallerSide, smallerSide);
if (size.width < size.height)
- cropRect.origin.y = rintf((size.height - smallerSide) / 2);
+ cropRect.origin.y = std::round((size.height - smallerSide) / 2);
else
- cropRect.origin.x = rintf((size.width - smallerSide) / 2);
+ cropRect.origin.x = std::round((size.width - smallerSide) / 2);
return cropRect;
}
-static UIImage *squareImage(UIImage *image)
+static UIImage *squareImage(CGImageRef image)
{
if (!image)
return nil;
- CGImageRef imageRef = [image CGImage];
- CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
+ CGSize imageSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
if (imageSize.width == imageSize.height)
- return image;
+ return [UIImage imageWithCGImage:image];
CGRect squareCropRect = squareCropRectForSize(imageSize);
- CGImageRef squareImageRef = CGImageCreateWithImageInRect(imageRef, squareCropRect);
- UIImage *squareImage = [[UIImage alloc] initWithCGImage:squareImageRef imageOrientation:[image imageOrientation]];
- CGImageRelease(squareImageRef);
- return [squareImage autorelease];
+ RetainPtr<CGImageRef> squareImage = adoptCF(CGImageCreateWithImageInRect(image, squareCropRect));
+ return [UIImage imageWithCGImage:squareImage.get()];
}
-static UIImage *thumbnailSizedImageForImage(UIImage *image)
+static UIImage *thumbnailSizedImageForImage(CGImageRef image)
{
UIImage *squaredImage = squareImage(image);
if (!squaredImage)
return nil;
- CGRect destRect = CGRectMake(0, 0, 100, 100);
+ CGRect destRect = CGRectMake(0, 0, iconSideLength, iconSideLength);
UIGraphicsBeginImageContext(destRect.size);
CGContextSetInterpolationQuality(UIGraphicsGetCurrentContext(), kCGInterpolationHigh);
[squaredImage drawInRect:destRect];
@@ -140,18 +139,26 @@
ASSERT_ARG(file, [file isFileURL]);
UIDocumentInteractionController *interactionController = [UIDocumentInteractionController interactionControllerWithURL:file];
- return thumbnailSizedImageForImage(interactionController.icons[0]);
+ return thumbnailSizedImageForImage(interactionController.icons[0].CGImage);
}
static UIImage* iconForImageFile(NSURL *file)
{
ASSERT_ARG(file, [file isFileURL]);
- if (UIImage *image = [UIImage imageWithContentsOfFile:file.path])
- return thumbnailSizedImageForImage(image);
+ NSDictionary *options = @{
+ (id)kCGImageSourceCreateThumbnailFromImageIfAbsent: @YES,
+ (id)kCGImageSourceThumbnailMaxPixelSize: @(iconSideLength),
+ (id)kCGImageSourceCreateThumbnailWithTransform: @YES,
+ };
+ RetainPtr<CGImageSource> imageSource = adoptCF(CGImageSourceCreateWithURL((CFURLRef)file, 0));
+ RetainPtr<CGImageRef> thumbnail = adoptCF(CGImageSourceCreateThumbnailAtIndex(imageSource.get(), 0, (CFDictionaryRef)options));
+ if (!thumbnail) {
+ LOG_ERROR("WKFileUploadPanel: Error creating thumbnail image for image: %@", file);
+ return fallbackIconForFile(file);
+ }
- LOG_ERROR("WKFileUploadPanel: Error creating thumbnail image for image: %@", file);
- return fallbackIconForFile(file);
+ return thumbnailSizedImageForImage(thumbnail.get());
}
static UIImage* iconForVideoFile(NSURL *file)
@@ -169,8 +176,7 @@
return fallbackIconForFile(file);
}
- RetainPtr<UIImage> image = adoptNS([[UIImage alloc] initWithCGImage:imageRef.get()]);
- return thumbnailSizedImageForImage(image.get());
+ return thumbnailSizedImageForImage(imageRef.get());
}
static UIImage* iconForFile(NSURL *file)
@@ -238,22 +244,10 @@
@interface _WKImageFileUploadItem : _WKFileUploadItem
-- (instancetype)initWithFileURL:(NSURL *)fileURL originalImage:(UIImage *)originalImage;
@end
-@implementation _WKImageFileUploadItem {
- RetainPtr<UIImage> _originalImage;
-}
+@implementation _WKImageFileUploadItem
-- (instancetype)initWithFileURL:(NSURL *)fileURL originalImage:(UIImage *)originalImage
-{
- if (!(self = [super initWithFileURL:fileURL]))
- return nil;
-
- _originalImage = originalImage;
- return self;
-}
-
- (BOOL)isVideo
{
return NO;
@@ -261,7 +255,7 @@
- (UIImage *)displayImage
{
- return thumbnailSizedImageForImage(_originalImage.get());
+ return iconForImageFile(self.fileURL);
}
@end
@@ -735,10 +729,9 @@
[self _uploadItemFromMediaInfo:info successBlock:uploadItemSuccessBlock failureBlock:failureBlock];
}
-- (void)_uploadItemForImageData:(NSData *)imageData originalImage:(UIImage *)originalImage imageName:(NSString *)imageName successBlock:(void (^)(_WKFileUploadItem *))successBlock failureBlock:(void (^)(void))failureBlock
+- (void)_uploadItemForImageData:(NSData *)imageData imageName:(NSString *)imageName successBlock:(void (^)(_WKFileUploadItem *))successBlock failureBlock:(void (^)(void))failureBlock
{
ASSERT_ARG(imageData, imageData);
- ASSERT_ARG(originalImage, originalImage);
ASSERT(!isMainThread());
NSString * const kTemporaryDirectoryName = @"WKWebFileUpload";
@@ -762,7 +755,7 @@
return;
}
- successBlock(adoptNS([[_WKImageFileUploadItem alloc] initWithFileURL:[NSURL fileURLWithPath:filePath] originalImage:originalImage]).get());
+ successBlock(adoptNS([[_WKImageFileUploadItem alloc] initWithFileURL:[NSURL fileURLWithPath:filePath]]).get());
}
- (void)_uploadItemForJPEGRepresentationOfImage:(UIImage *)image successBlock:(void (^)(_WKFileUploadItem *))successBlock failureBlock:(void (^)(void))failureBlock
@@ -785,7 +778,7 @@
// naming each of the individual uploads image.jpg? This won't work for photos taken with
// the camera, but would work for photos picked from the library.
NSString * const kUploadImageName = @"image.jpg";
- [self _uploadItemForImageData:jpeg originalImage:image imageName:kUploadImageName successBlock:successBlock failureBlock:failureBlock];
+ [self _uploadItemForImageData:jpeg imageName:kUploadImageName successBlock:successBlock failureBlock:failureBlock];
});
}
@@ -817,7 +810,7 @@
RetainPtr<CFStringRef> extension = adoptCF(UTTypeCopyPreferredTagWithClass((CFStringRef)dataUTI, kUTTagClassFilenameExtension));
NSString *imageName = [@"image." stringByAppendingString:(extension ? (id)extension.get() : @"jpg")];
- [self _uploadItemForImageData:imageData originalImage:image imageName:imageName successBlock:successBlock failureBlock:failureBlock];
+ [self _uploadItemForImageData:imageData imageName:imageName successBlock:successBlock failureBlock:failureBlock];
}];
});
}