BigInt should store its data in the primitive gigacage.
[WebKit-https.git] / Source / WebKit / UIProcess / ios / WKDrawingView.mm
index 8af4c0b..6bed103 100644 (file)
 
 #if HAVE(PENCILKIT)
 
-#import "PencilKitSPI.h"
+#import "EditableImageController.h"
+#import "WKContentViewInteraction.h"
+#import "WKDrawingCoordinator.h"
+#import <wtf/OSObjectPtr.h>
 #import <wtf/RetainPtr.h>
 
-SOFT_LINK_PRIVATE_FRAMEWORK(PencilKit);
-SOFT_LINK_CLASS(PencilKit, PKCanvasView);
+#import "PencilKitSoftLink.h"
+
+@interface WKDrawingView () <PKCanvasViewDelegate>
+@end
 
 @implementation WKDrawingView {
     RetainPtr<PKCanvasView> _pencilView;
+
+#if !PLATFORM(IOS_FAMILY_SIMULATOR)
+    OSObjectPtr<dispatch_queue_t> _renderQueue;
+    RetainPtr<PKImageRenderer> _renderer;
+#endif
+
+    __weak WKContentView *_contentView;
 }
 
-- (id)init
+- (instancetype)initWithEmbeddedViewID:(WebCore::GraphicsLayer::EmbeddedViewID)embeddedViewID contentView:(WKContentView *)contentView
 {
-    self = [super init];
+    self = [super initWithEmbeddedViewID:embeddedViewID];
     if (!self)
         return nil;
 
-    _pencilView = adoptNS([allocPKCanvasViewInstance() initWithFrame:CGRectZero]);
+    _contentView = contentView;
+
+    _pencilView = adoptNS([WebKit::allocPKCanvasViewInstance() initWithFrame:CGRectZero]);
 
+    [_pencilView setFingerDrawingEnabled:NO];
     [_pencilView setUserInteractionEnabled:YES];
     [_pencilView setOpaque:NO];
+    [_pencilView setDelegate:self];
+    [_pencilView setRulerHostingDelegate:_contentView._drawingCoordinator];
 
     [self addSubview:_pencilView.get()];
 
@@ -56,7 +73,128 @@ SOFT_LINK_CLASS(PencilKit, PKCanvasView);
 
 - (void)layoutSubviews
 {
-    [_pencilView setFrame:self.bounds];
+    if (!CGRectEqualToRect([_pencilView frame], self.bounds)) {
+        [_pencilView setFrame:self.bounds];
+
+#if !PLATFORM(IOS_FAMILY_SIMULATOR)
+        // The renderer is instantiated for a particular size output; if
+        // the size changes, we need to re-create the renderer.
+        _renderer = nil;
+#endif
+
+        [self invalidateAttachment];
+    }
+}
+
+static UIImage *emptyImage()
+{
+    UIGraphicsBeginImageContext(CGSizeMake(1, 1));
+    CGContextClearRect(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, 1, 1));
+    UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+
+    return resultImage;
+}
+
+- (UIImage *)renderedDrawing
+{
+#if PLATFORM(IOS_FAMILY_SIMULATOR)
+    // PKImageRenderer currently doesn't work in the simulator. In order to
+    // allow strokes to persist regardless (mostly for testing), we'll
+    // synthesize an empty 1x1 image.
+    return emptyImage();
+#else
+    if (!self.bounds.size.width || !self.bounds.size.height || !self.window.screen.scale)
+        return emptyImage();
+
+    if (!_renderQueue)
+        _renderQueue = adoptOSObject(dispatch_queue_create("com.apple.WebKit.WKDrawingView.Rendering", DISPATCH_QUEUE_SERIAL));
+
+    if (!_renderer)
+        _renderer = adoptNS([WebKit::allocPKImageRendererInstance() initWithSize:self.bounds.size scale:self.window.screen.scale renderQueue:_renderQueue.get()]);
+
+    __block RetainPtr<UIImage> resultImage;
+
+    [_renderer renderDrawing:[_pencilView nonNullDrawing] completion:^(UIImage *image) {
+        resultImage = image;
+    }];
+
+    // FIXME: Ideally we would not synchronously wait for this rendering,
+    // but NSFileWrapper requires data synchronously, and our clients expect
+    // an NSFileWrapper to be available synchronously.
+    dispatch_sync(_renderQueue.get(), ^{ });
+
+    return resultImage.autorelease();
+#endif
+}
+
+- (NSData *)PNGRepresentation
+{
+    RetainPtr<UIImage> image = [self renderedDrawing];
+    RetainPtr<NSMutableData> PNGData = adoptNS([[NSMutableData alloc] init]);
+    RetainPtr<CGImageDestinationRef> imageDestination = adoptCF(CGImageDestinationCreateWithData((__bridge CFMutableDataRef)PNGData.get(), kUTTypePNG, 1, nil));
+    NSString *base64Drawing = [[[_pencilView nonNullDrawing] serialize] base64EncodedStringWithOptions:0];
+    NSDictionary *properties = nil;
+    if (base64Drawing) {
+        // FIXME: We should put this somewhere less user-facing than the EXIF User Comment field.
+        properties = @{
+            (__bridge NSString *)kCGImagePropertyExifDictionary : @{
+                (__bridge NSString *)kCGImagePropertyExifUserComment : base64Drawing
+            }
+        };
+    }
+    CGImageDestinationSetProperties(imageDestination.get(), (__bridge CFDictionaryRef)properties);
+    CGImageDestinationAddImage(imageDestination.get(), [image CGImage], (__bridge CFDictionaryRef)properties);
+    CGImageDestinationFinalize(imageDestination.get());
+
+    return PNGData.autorelease();
+}
+
+- (void)loadDrawingFromPNGRepresentation:(NSData *)PNGData
+{
+    RetainPtr<CGImageSourceRef> imageSource = adoptCF(CGImageSourceCreateWithData((__bridge CFDataRef)PNGData, nullptr));
+    if (!imageSource)
+        return;
+    RetainPtr<NSDictionary> properties = adoptNS((__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource.get(), 0, nil));
+    NSString *base64Drawing = [[properties objectForKey:(NSString *)kCGImagePropertyExifDictionary] objectForKey:(NSString *)kCGImagePropertyExifUserComment];
+    if (!base64Drawing)
+        return;
+    RetainPtr<NSData> drawingData = adoptNS([[NSData alloc] initWithBase64EncodedString:base64Drawing options:0]);
+    RetainPtr<PKDrawing> drawing = adoptNS([WebKit::allocPKDrawingInstance() initWithData:drawingData.get() error:nil]);
+    [_pencilView setNonNullDrawing:drawing.get()];
+}
+
+- (void)canvasViewDrawingDidChange:(PKCanvasView *)canvasView
+{
+    [self invalidateAttachment];
+}
+
+- (void)_canvasViewWillBeginDrawing:(PKCanvasView *)canvasView
+{
+ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+    [_pencilView setInk:_contentView._drawingCoordinator.currentInk];
+ALLOW_DEPRECATED_DECLARATIONS_END
+}
+
+- (void)invalidateAttachment
+{
+    if (!_contentView.page)
+        return;
+    auto& page = *_contentView.page;
+
+    page.editableImageController().invalidateAttachmentForEditableImage(self.embeddedViewID);
+}
+
+- (void)didChangeRulerState:(BOOL)rulerEnabled
+{
+    [_pencilView setRulerEnabled:rulerEnabled];
+}
+
+- (void)didChangeInk:(PKInk *)ink
+{
+ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+    [_pencilView setInk:ink];
+ALLOW_DEPRECATED_DECLARATIONS_END
 }
 
 @end