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 "config.h"
27#import "WKFormPopover.h"
28
29#if PLATFORM(IOS)
30
31#import "WKContentView.h"
32#import "WKContentViewInteraction.h"
33#import "WebPageProxy.h"
34#import <UIKit/UIPeripheralHost.h>
35#import <UIKit/UIWindow_Private.h>
36#import <wtf/RetainPtr.h>
37
38using namespace WebKit;
39
40@implementation WKFormRotatingAccessoryPopover {
41    WKContentView *_view;
42}
43
44- (id)initWithView:(WKContentView *)view
45{
46    if (!(self = [super initWithView:view]))
47        return nil;
48    _view = view;
49    self.dismissionDelegate = self;
50    return self;
51}
52
53- (void)accessoryDone
54{
55    [_view accessoryDone];
56}
57
58- (UIPopoverArrowDirection)popoverArrowDirections
59{
60    UIPopoverArrowDirection directions = UIPopoverArrowDirectionUp | UIPopoverArrowDirectionDown;
61    if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) && [[UIPeripheralHost sharedInstance] isOnScreen])
62        directions = UIPopoverArrowDirectionLeft | UIPopoverArrowDirectionRight;
63    return directions;
64}
65
66- (void)popoverWasDismissed:(WKRotatingPopover *)popover
67{
68    [self accessoryDone];
69}
70
71@end
72
73@interface WKRotatingPopover () <UIPopoverControllerDelegate>
74@end
75
76@implementation WKRotatingPopover {
77    WKContentView *_view;
78
79    BOOL _isRotating;
80    CGPoint _presentationPoint;
81    RetainPtr<UIPopoverController> _popoverController;
82    id <WKRotatingPopoverDelegate> _dismissionDelegate;
83}
84
85- (id)initWithView:(WKContentView *)view
86{
87    if (!(self = [super init]))
88        return nil;
89
90    _view = view;
91    self.presentationPoint = CGPointZero;
92
93    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
94    [center addObserver:self selector:@selector(willRotate:) name:UIWindowWillRotateNotification object:nil];
95    [center addObserver:self selector:@selector(didRotate:) name:UIWindowDidRotateNotification object:nil];
96
97    return self;
98}
99
100- (void)dealloc
101{
102    _view = nil;
103
104    [_popoverController dismissPopoverAnimated:YES];
105    [_popoverController setDelegate:nil];
106    self.popoverController = nil;
107
108    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
109    [center removeObserver:self name:UIWindowWillRotateNotification object:nil];
110    [center removeObserver:self name:UIWindowDidRotateNotification object:nil];
111
112    [super dealloc];
113}
114
115- (UIPopoverController *)popoverController
116{
117    return _popoverController.get();
118}
119
120- (void)setPopoverController:(UIPopoverController *)popoverController
121{
122    if (_popoverController == popoverController)
123        return;
124
125    [_popoverController setDelegate:nil];
126    _popoverController = popoverController;
127    [_popoverController setDelegate:self];
128}
129
130- (UIPopoverArrowDirection)popoverArrowDirections
131{
132    return UIPopoverArrowDirectionAny;
133}
134
135- (void)presentPopoverAnimated:(BOOL)animated
136{
137    UIPopoverArrowDirection directions = [self popoverArrowDirections];
138
139    BOOL presentWithPoint = !CGPointEqualToPoint(self.presentationPoint, CGPointZero);
140    if (presentWithPoint) {
141        CGFloat scale = [_view page]->pageScaleFactor();
142        [_popoverController presentPopoverFromRect:CGRectIntegral(CGRectMake(self.presentationPoint.x * scale, self.presentationPoint.y * scale, 1, 1))
143                                            inView:_view
144                          permittedArrowDirections:directions
145                                          animated:animated];
146    } else {
147        CGRect boundingBoxOfDOMNode = _view.assistedNodeInformation.elementRect;
148        [_popoverController presentPopoverFromRect:CGRectIntegral(boundingBoxOfDOMNode)
149                                            inView:_view
150                          permittedArrowDirections:directions
151                                          animated:animated];
152    }
153}
154
155- (void)dismissPopoverAnimated:(BOOL)animated
156{
157    [_popoverController dismissPopoverAnimated:animated];
158}
159
160- (void)willRotate:(NSNotification *)notification
161{
162    _isRotating = YES;
163    [_popoverController dismissPopoverAnimated:NO];
164}
165
166- (void)didRotate:(NSNotification *)notification
167{
168    _isRotating = NO;
169    [self presentPopoverAnimated:NO];
170}
171
172- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
173{
174    if (_isRotating)
175        return;
176
177    [_dismissionDelegate popoverWasDismissed:self];
178}
179
180@end
181
182#endif // PLATFORM(IOS)
183