026982c9a417bb7807bbaf1fdbbdf97dd2282b56
[WebKit-https.git] / Source / WebCore / platform / ios / wak / WAKWindow.mm
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 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 "WAKWindow.h"
28
29 #if PLATFORM(IOS)
30
31 #import "LegacyTileCache.h"
32 #import "PlatformScreen.h"
33 #import "WAKViewInternal.h"
34 #import "WebCoreSystemInterface.h"
35 #import "WebCoreThreadRun.h"
36 #import "WebEvent.h"
37 #import "WKContentObservation.h"
38 #import "WKViewPrivate.h"
39 #import <QuartzCore/QuartzCore.h>
40 #import <wtf/Lock.h>
41
42 WEBCORE_EXPORT NSString * const WAKWindowScreenScaleDidChangeNotification = @"WAKWindowScreenScaleDidChangeNotification";
43 WEBCORE_EXPORT NSString * const WAKWindowVisibilityDidChangeNotification = @"WAKWindowVisibilityDidChangeNotification";
44
45 using namespace WebCore;
46
47 @protocol OrientationProvider
48 - (BOOL)hasLandscapeOrientation;
49 @end
50
51 static WAKWindow *_WAKKeyWindow = nil;        // weak
52 static WebEvent *currentEvent = nil;
53 static id<OrientationProvider> gOrientationProvider;
54
55 @implementation WAKWindow {
56     Lock _exposedScrollViewRectLock;
57     CGRect _exposedScrollViewRect;
58 }
59
60 @synthesize useOrientationDependentFontAntialiasing = _useOrientationDependentFontAntialiasing;
61
62 - (id)initWithLayer:(CALayer *)layer
63 {
64     self = [super init];
65     if (!self)
66         return nil;
67
68     _hostLayer = [layer retain];
69
70     _frame = [_hostLayer frame];
71     _screenScale = screenScaleFactor();
72     
73     _tileCache = new LegacyTileCache(self);
74
75     _frozenVisibleRect = CGRectNull;
76
77     _exposedScrollViewRect = CGRectNull;
78
79     return self;
80 }
81
82 // This is used for WebViews that are not backed by the tile cache. Their content must be painted manually.
83 - (id)initWithFrame:(CGRect)frame
84 {
85     self = [super init];
86     if (!self)
87         return nil;
88
89     _frame = frame;
90     _screenScale = screenScaleFactor();
91
92     _exposedScrollViewRect = CGRectNull;
93
94     return self;
95 }
96
97 - (void)dealloc
98 {
99     delete _tileCache;
100     [_hostLayer release];
101     
102     [super dealloc];
103 }
104
105 - (void)setContentView:(WAKView *)aView
106 {
107     [aView retain];
108     [_contentView release];
109
110     if (aView)
111         _WKViewSetWindow([aView _viewRef], self);
112     _contentView = aView;
113 }
114
115 - (WAKView *)contentView
116 {
117     return _contentView;
118 }
119
120 - (void)close
121 {
122     if (_contentView) {
123         _WKViewSetWindow([_contentView _viewRef], nil);
124         [_contentView release];
125         _contentView = nil;
126     }
127
128     [_responderView release];
129     _responderView = nil;
130 }
131
132 - (WAKView *)firstResponder
133 {
134     return _responderView;
135 }
136
137 - (WAKView *)_newFirstResponderAfterResigning
138 {
139     return _nextResponder;
140 }
141
142 - (NSPoint)convertBaseToScreen:(NSPoint)aPoint
143 {
144     CALayer* rootLayer = _hostLayer;
145     while (rootLayer.superlayer)
146         rootLayer = rootLayer.superlayer;
147     
148     return [_hostLayer convertPoint:aPoint toLayer:rootLayer];
149 }
150
151 - (NSPoint)convertScreenToBase:(NSPoint)aPoint
152 {
153     CALayer* rootLayer = _hostLayer;
154     while (rootLayer.superlayer)
155         rootLayer = rootLayer.superlayer;
156     
157     return [_hostLayer convertPoint:aPoint fromLayer:rootLayer];
158 }
159
160 - (NSRect)convertRectToScreen:(NSRect)windowRect
161 {
162     CALayer* rootLayer = _hostLayer;
163     while (rootLayer.superlayer)
164         rootLayer = rootLayer.superlayer;
165
166     return [_hostLayer convertRect:windowRect toLayer:rootLayer];
167 }
168
169 - (NSRect)convertRectFromScreen:(NSRect)screenRect
170 {
171     CALayer* rootLayer = _hostLayer;
172     while (rootLayer.superlayer)
173         rootLayer = rootLayer.superlayer;
174
175     return [_hostLayer convertRect:screenRect fromLayer:rootLayer];
176 }
177
178 - (BOOL)isKeyWindow
179 {
180     return YES || self == _WAKKeyWindow; 
181 }
182
183 - (void)makeKeyWindow
184 {
185     if ([self isKeyWindow])
186         return;
187     
188     _WAKKeyWindow = self;
189 }
190
191 - (BOOL)isVisible
192 {
193     return _visible;
194 }
195
196 - (void)setVisible:(BOOL)visible
197 {
198     if (_visible == visible)
199         return;
200
201     _visible = visible;
202
203     WebThreadRun(^{
204         [[NSNotificationCenter defaultCenter] postNotificationName:WAKWindowVisibilityDidChangeNotification object:self userInfo:nil];
205     });
206 }
207
208 - (NSSelectionDirection)keyViewSelectionDirection
209 {
210     return (NSSelectionDirection)0;
211 }
212
213 - (BOOL)makeFirstResponder:(NSResponder *)aResponder
214 {
215     if (![aResponder isKindOfClass:[WAKView class]])
216         return NO;
217
218     WAKView *view = static_cast<WAKView*>(aResponder);
219     BOOL result = YES;
220     if (view != _responderView) {
221         // We need to handle the case of the view not accepting to be a first responder,
222         // where we don't need to resign as first responder.
223         BOOL acceptsFirstResponder = view ? WKViewAcceptsFirstResponder([view _viewRef]) : YES;
224         if (acceptsFirstResponder && _responderView) {
225             _nextResponder = view;
226             if (WKViewResignFirstResponder([_responderView _viewRef])) {
227                 _nextResponder = nil;
228                 [_responderView release];
229                 _responderView = nil;
230             }  else {
231                 _nextResponder = nil;
232                 result = NO;
233             }
234         }
235
236         if (result && view) {
237             if (acceptsFirstResponder && WKViewBecomeFirstResponder([view _viewRef]))
238                 _responderView = [view retain];
239             else
240                 result = NO;
241         }
242     }
243
244     return result;
245 }
246
247 // FIXME: This method can lead to incorrect state. Remove if possible.
248 - (void)setFrame:(NSRect)frameRect display:(BOOL)flag
249 {
250     UNUSED_PARAM(flag);
251     _frame = frameRect;
252 }
253
254 // FIXME: the correct value if there is a host layer is likely to return [_hostLayer frame].
255 - (CGRect)frame
256 {
257     return _frame;
258 }
259
260 - (void)setContentRect:(CGRect)rect
261 {
262     if (CGRectEqualToRect(rect, _frame))
263         return;
264     _frame = rect;
265
266     // FIXME: Size of the host layer is directly available so there is no real reason to save it here.
267     // However we currently use this call to catch changes to the host layer size.
268     if (_tileCache)
269         _tileCache->hostLayerSizeChanged();
270 }
271
272 - (void)setScreenSize:(CGSize)size
273 {
274     _screenSize = size;
275 }
276
277 - (CGSize)screenSize
278 {
279     return _screenSize;
280 }
281
282 - (void)setAvailableScreenSize:(CGSize)size
283 {
284     _availableScreenSize = size;
285 }
286
287 - (CGSize)availableScreenSize
288 {
289     return _availableScreenSize;
290 }
291
292 - (void)setScreenScale:(CGFloat)scale
293 {
294     _screenScale = scale;
295
296     WebThreadRun(^{
297         [[NSNotificationCenter defaultCenter] postNotificationName:WAKWindowScreenScaleDidChangeNotification object:self userInfo:nil];
298     });
299 }
300
301 - (CGFloat)screenScale
302 {
303     return _screenScale;
304 }
305
306 - (void)setRootLayer:(CALayer *)layer
307 {
308     _rootLayer = layer;
309 }
310
311 - (CALayer *)rootLayer
312 {
313     return _rootLayer;
314 }
315
316 - (void)sendEvent:(WebEvent *)anEvent
317 {
318     ASSERT(anEvent);
319     WebThreadRun(^{
320         [self sendEventSynchronously:anEvent];
321     });
322 }
323
324 - (void)sendEventSynchronously:(WebEvent *)anEvent
325 {
326     ASSERT(anEvent);
327     ASSERT(WebThreadIsLockedOrDisabled());
328     WebEvent *lastEvent = currentEvent;
329     currentEvent = [anEvent retain];
330
331     switch (anEvent.type) {
332         case WebEventMouseMoved:
333         case WebEventScrollWheel:
334             if (WAKView *hitView = [_contentView hitTest:(anEvent.locationInWindow)])
335                 [hitView handleEvent:anEvent];
336             break;
337
338         case WebEventMouseUp:
339         case WebEventKeyDown:
340         case WebEventKeyUp:
341         case WebEventTouchChange:
342             [_responderView handleEvent:anEvent];
343             break;
344
345         case WebEventMouseDown:
346         case WebEventTouchBegin:
347         case WebEventTouchEnd:
348         case WebEventTouchCancel:
349             if (WAKView *hitView = [_contentView hitTest:(anEvent.locationInWindow)]) {
350                 [self makeFirstResponder:hitView];
351                 [hitView handleEvent:anEvent];
352             }
353             break;
354
355         default:
356             ASSERT_NOT_REACHED();
357             break;
358     }
359
360     [currentEvent release];
361     currentEvent = lastEvent;
362 }
363
364 - (void)sendMouseMoveEvent:(WebEvent *)anEvent contentChange:(WKContentChange *)aContentChange
365 {
366     WebThreadRun(^{
367         [self sendEvent:anEvent];
368
369         if (aContentChange)
370             *aContentChange = WKObservedContentChange();
371     });
372 }
373
374 - (void)setExposedScrollViewRect:(CGRect)exposedScrollViewRect
375 {
376     LockHolder locker(&_exposedScrollViewRectLock);
377     _exposedScrollViewRect = exposedScrollViewRect;
378 }
379
380 - (CGRect)exposedScrollViewRect
381 {
382     {
383         LockHolder locker(&_exposedScrollViewRectLock);
384         if (!CGRectIsNull(_exposedScrollViewRect))
385             return _exposedScrollViewRect;
386     }
387     return [self visibleRect];
388 }
389
390 // Tiling
391
392 - (void)layoutTiles
393 {
394     if (!_tileCache)
395         return;    
396     _tileCache->layoutTiles();
397 }
398
399 - (void)layoutTilesNow
400 {
401     if (!_tileCache)
402         return;
403     _tileCache->layoutTilesNow();
404 }
405
406 - (void)layoutTilesNowForRect:(CGRect)rect
407 {
408     if (!_tileCache)
409         return;
410     _tileCache->layoutTilesNowForRect(enclosingIntRect(rect));
411 }
412
413 - (void)setNeedsDisplay
414 {
415     if (!_tileCache)
416         return;
417     _tileCache->setNeedsDisplay();
418 }
419
420 - (void)setNeedsDisplayInRect:(CGRect)rect
421 {
422     if (!_tileCache)
423         return;
424     _tileCache->setNeedsDisplayInRect(enclosingIntRect(rect));
425 }
426
427 - (BOOL)tilesOpaque
428 {
429     if (!_tileCache)
430         return NO;
431     return _tileCache->tilesOpaque();
432 }
433
434 - (void)setTilesOpaque:(BOOL)opaque
435 {
436     if (!_tileCache)
437         return;
438     _tileCache->setTilesOpaque(opaque);
439 }
440
441 - (void)setIsInSnapshottingPaint:(BOOL)isInSnapshottingPaint
442 {
443     _isInSnapshottingPaint = isInSnapshottingPaint;
444 }
445
446 - (BOOL)isInSnapshottingPaint
447 {
448     return _isInSnapshottingPaint;
449 }
450
451 - (void)setEntireWindowVisibleForTesting:(BOOL)entireWindowVisible
452 {
453     _entireWindowVisibleForTesting = entireWindowVisible;
454 }
455
456 - (CGRect)_visibleRectRespectingMasksToBounds:(BOOL)respectsMasksToBounds
457 {
458     if (!CGRectIsNull(_frozenVisibleRect))
459         return _frozenVisibleRect;
460
461     CALayer* layer = _hostLayer;
462     CGRect bounds = [layer bounds];
463     if (_entireWindowVisibleForTesting)
464         return bounds;
465     CGRect rect = bounds;
466     CALayer* superlayer = [layer superlayer];
467
468     static Class windowClass = NSClassFromString(@"UIWindow");
469
470     while (superlayer && layer != _rootLayer && (!layer.delegate || ![layer.delegate isKindOfClass:windowClass])) {
471         CGRect rectInSuper = [superlayer convertRect:rect fromLayer:layer];
472         if ([superlayer masksToBounds] || !respectsMasksToBounds)
473             rect = CGRectIntersection([superlayer bounds], rectInSuper);
474         else
475             rect = rectInSuper;
476         layer = superlayer;
477         superlayer = [layer superlayer];
478     }
479     
480     if (layer != _hostLayer) {
481         rect = CGRectIntersection([layer bounds], rect);
482         rect = [_hostLayer convertRect:rect fromLayer:layer];
483     }
484     
485     return CGRectIntersection(bounds, rect);
486 }
487
488 - (CGRect)visibleRect
489 {
490     return [self _visibleRectRespectingMasksToBounds:NO];
491 }
492
493 - (CGRect)extendedVisibleRect
494 {
495     return [self _visibleRectRespectingMasksToBounds:YES];
496 }
497
498 - (void)removeAllNonVisibleTiles
499 {
500     if (!_tileCache)
501         return;
502     _tileCache->removeAllNonVisibleTiles();
503 }
504
505 - (void)removeAllTiles
506 {
507     if (!_tileCache)
508         return;
509     _tileCache->removeAllTiles();
510 }
511
512 - (void)removeForegroundTiles
513 {
514     if (!_tileCache)
515         return;
516     _tileCache->removeForegroundTiles();
517 }
518
519 - (void)setTilingMode:(WAKWindowTilingMode)mode
520 {
521     if (!_tileCache)
522         return;
523     _tileCache->setTilingMode((LegacyTileCache::TilingMode)mode);
524 }
525
526 - (WAKWindowTilingMode)tilingMode
527 {
528     if (!_tileCache)
529         return kWAKWindowTilingModeDisabled;
530     return (WAKWindowTilingMode)_tileCache->tilingMode();
531 }
532
533 - (void)setTilingDirection:(WAKTilingDirection)tilingDirection
534 {
535     if (!_tileCache)
536         return;
537     _tileCache->setTilingDirection((LegacyTileCache::TilingDirection)tilingDirection);
538 }
539
540 - (WAKTilingDirection)tilingDirection
541 {
542     if (!_tileCache)
543         return kWAKTilingDirectionDown;
544     return (WAKTilingDirection)_tileCache->tilingDirection();
545 }
546
547 - (void)setZoomedOutTileScale:(float)scale
548 {
549     if (!_tileCache)
550         return;
551     _tileCache->setZoomedOutScale(scale);
552 }
553
554 - (float)zoomedOutTileScale
555 {
556     if (!_tileCache)
557         return 1.0f;
558     return _tileCache->zoomedOutScale();
559 }
560
561 - (void)setCurrentTileScale:(float)scale
562 {
563     if (!_tileCache)
564         return;
565     _tileCache->setCurrentScale(scale);
566 }
567
568 - (float)currentTileScale
569 {
570     if (!_tileCache)
571         return 1.0f;
572     return _tileCache->currentScale();
573 }
574
575 - (void)setKeepsZoomedOutTiles:(BOOL)keepsZoomedOutTiles
576 {
577     if (!_tileCache)
578         return;
579     _tileCache->setKeepsZoomedOutTiles(keepsZoomedOutTiles);
580 }
581
582 - (BOOL)keepsZoomedOutTiles
583 {
584     if (!_tileCache)
585         return NO;
586     return _tileCache->keepsZoomedOutTiles();
587 }
588
589 - (LegacyTileCache*)tileCache
590 {
591     return _tileCache;
592 }
593
594 - (BOOL)hasPendingDraw
595 {
596     if (!_tileCache)
597         return NO;
598      return _tileCache->hasPendingDraw();
599 }
600
601 - (void)setContentReplacementImage:(CGImageRef)contentReplacementImage
602 {
603     if (!_tileCache)
604         return;
605     _tileCache->setContentReplacementImage(contentReplacementImage);
606 }
607
608 - (CGImageRef)contentReplacementImage
609 {
610     if (!_tileCache)
611         return NULL;
612     return _tileCache->contentReplacementImage().get();
613 }
614
615 - (void)displayRect:(NSRect)rect
616 {
617     [[self contentView] displayRect:rect];
618 }
619
620 - (void)willRotate
621 {
622     [self freezeVisibleRect];
623 }
624
625 - (void)didRotate
626 {
627     [self unfreezeVisibleRect];
628 }
629
630 - (void)freezeVisibleRect
631 {
632     _frozenVisibleRect = [self visibleRect];
633 }
634
635 - (void)unfreezeVisibleRect
636 {
637     _frozenVisibleRect = CGRectNull;
638 }
639
640 + (void)setOrientationProvider:(id)provider
641 {
642     // This is really the UIWebDocumentView class that calls into UIApplication to get the orientation.
643     gOrientationProvider = provider;
644 }
645
646 + (BOOL)hasLandscapeOrientation
647 {
648     // this should be perfectly thread safe
649     return [gOrientationProvider hasLandscapeOrientation];
650 }
651
652 - (CALayer*)hostLayer
653 {
654     return _hostLayer;
655 }
656
657 - (void)setTileBordersVisible:(BOOL)visible
658 {
659     if (!_tileCache)
660         return;
661
662     _tileCache->setTileBordersVisible(visible);
663 }
664
665 - (void)setTilePaintCountsVisible:(BOOL)visible
666 {
667     if (!_tileCache)
668         return;
669
670     _tileCache->setTilePaintCountersVisible(visible);
671 }
672
673 - (void)setAcceleratedDrawingEnabled:(BOOL)enabled
674 {
675     if (!_tileCache)
676         return;
677
678     _tileCache->setAcceleratedDrawingEnabled(enabled);
679 }
680
681 - (void)dumpTiles
682 {
683     CGRect savedFrozenVisibleRect = _frozenVisibleRect;
684     NSLog(@"=================");
685     if (!CGRectIsNull(_frozenVisibleRect)) {
686         NSLog(@"VISIBLE RECT IS CACHED: [%6.1f %6.1f %6.1f %6.1f]", _frozenVisibleRect.origin.x, _frozenVisibleRect.origin.y, _frozenVisibleRect.size.width, _frozenVisibleRect.size.height);
687         _frozenVisibleRect = CGRectNull;
688     }
689     CGRect visibleRect = [self visibleRect];
690     NSLog(@"visibleRect = [%6.1f %6.1f %6.1f %6.1f]", visibleRect.origin.x, visibleRect.origin.y, visibleRect.size.width, visibleRect.size.height);
691     _frozenVisibleRect = savedFrozenVisibleRect;
692     _tileCache->dumpTiles();
693 }
694
695 - (void)setTileControllerShouldUseLowScaleTiles:(BOOL)lowScaleTiles 
696
697     if (!_tileCache) 
698         return; 
699
700     _tileCache->setTileControllerShouldUseLowScaleTiles(lowScaleTiles); 
701
702
703 - (NSString *)description
704 {
705     NSMutableString *description = [NSMutableString stringWithFormat:@"<%@: WAK: %p; ", [self class], self];
706
707     CGRect frame = [self frame];
708     [description appendFormat:@"frame = (%g %g; %g %g); ", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height];
709
710     [description appendFormat:@"first responder = WK %p; ", _responderView];
711     [description appendFormat:@"next responder = WK %p; ", _nextResponder];
712
713     [description appendFormat:@"layer = %@>", [_hostLayer description]];
714
715     return description;
716 }
717
718 + (WebEvent *)currentEvent
719 {
720     return currentEvent;
721 }
722
723 - (NSString *)recursiveDescription
724 {
725     NSMutableString *info = [NSMutableString string];
726
727     [info appendString:[self description]];
728
729     [[self contentView] _appendDescriptionToString:info atLevel:1];
730
731     return info;
732 }
733
734 @end
735
736 #endif // PLATFORM(IOS)