989cd77fdac24ebe6c7407392f920e26381f90b9
[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)setEntireWindowVisibleForTesting:(BOOL)entireWindowVisible
442 {
443     _entireWindowVisibleForTesting = entireWindowVisible;
444 }
445
446 - (CGRect)_visibleRectRespectingMasksToBounds:(BOOL)respectsMasksToBounds
447 {
448     if (!CGRectIsNull(_frozenVisibleRect))
449         return _frozenVisibleRect;
450
451     CALayer* layer = _hostLayer;
452     CGRect bounds = [layer bounds];
453     if (_entireWindowVisibleForTesting)
454         return bounds;
455     CGRect rect = bounds;
456     CALayer* superlayer = [layer superlayer];
457
458     static Class windowClass = NSClassFromString(@"UIWindow");
459
460     while (superlayer && layer != _rootLayer && (!layer.delegate || ![layer.delegate isKindOfClass:windowClass])) {
461         CGRect rectInSuper = [superlayer convertRect:rect fromLayer:layer];
462         if ([superlayer masksToBounds] || !respectsMasksToBounds)
463             rect = CGRectIntersection([superlayer bounds], rectInSuper);
464         else
465             rect = rectInSuper;
466         layer = superlayer;
467         superlayer = [layer superlayer];
468     }
469     
470     if (layer != _hostLayer) {
471         rect = CGRectIntersection([layer bounds], rect);
472         rect = [_hostLayer convertRect:rect fromLayer:layer];
473     }
474     
475     return CGRectIntersection(bounds, rect);
476 }
477
478 - (CGRect)visibleRect
479 {
480     return [self _visibleRectRespectingMasksToBounds:NO];
481 }
482
483 - (CGRect)extendedVisibleRect
484 {
485     return [self _visibleRectRespectingMasksToBounds:YES];
486 }
487
488 - (void)removeAllNonVisibleTiles
489 {
490     if (!_tileCache)
491         return;
492     _tileCache->removeAllNonVisibleTiles();
493 }
494
495 - (void)removeAllTiles
496 {
497     if (!_tileCache)
498         return;
499     _tileCache->removeAllTiles();
500 }
501
502 - (void)removeForegroundTiles
503 {
504     if (!_tileCache)
505         return;
506     _tileCache->removeForegroundTiles();
507 }
508
509 - (void)setTilingMode:(WAKWindowTilingMode)mode
510 {
511     if (!_tileCache)
512         return;
513     _tileCache->setTilingMode((LegacyTileCache::TilingMode)mode);
514 }
515
516 - (WAKWindowTilingMode)tilingMode
517 {
518     if (!_tileCache)
519         return kWAKWindowTilingModeDisabled;
520     return (WAKWindowTilingMode)_tileCache->tilingMode();
521 }
522
523 - (void)setTilingDirection:(WAKTilingDirection)tilingDirection
524 {
525     if (!_tileCache)
526         return;
527     _tileCache->setTilingDirection((LegacyTileCache::TilingDirection)tilingDirection);
528 }
529
530 - (WAKTilingDirection)tilingDirection
531 {
532     if (!_tileCache)
533         return kWAKTilingDirectionDown;
534     return (WAKTilingDirection)_tileCache->tilingDirection();
535 }
536
537 - (void)setZoomedOutTileScale:(float)scale
538 {
539     if (!_tileCache)
540         return;
541     _tileCache->setZoomedOutScale(scale);
542 }
543
544 - (float)zoomedOutTileScale
545 {
546     if (!_tileCache)
547         return 1.0f;
548     return _tileCache->zoomedOutScale();
549 }
550
551 - (void)setCurrentTileScale:(float)scale
552 {
553     if (!_tileCache)
554         return;
555     _tileCache->setCurrentScale(scale);
556 }
557
558 - (float)currentTileScale
559 {
560     if (!_tileCache)
561         return 1.0f;
562     return _tileCache->currentScale();
563 }
564
565 - (void)setKeepsZoomedOutTiles:(BOOL)keepsZoomedOutTiles
566 {
567     if (!_tileCache)
568         return;
569     _tileCache->setKeepsZoomedOutTiles(keepsZoomedOutTiles);
570 }
571
572 - (BOOL)keepsZoomedOutTiles
573 {
574     if (!_tileCache)
575         return NO;
576     return _tileCache->keepsZoomedOutTiles();
577 }
578
579 - (LegacyTileCache*)tileCache
580 {
581     return _tileCache;
582 }
583
584 - (BOOL)hasPendingDraw
585 {
586     if (!_tileCache)
587         return NO;
588      return _tileCache->hasPendingDraw();
589 }
590
591 - (void)setContentReplacementImage:(CGImageRef)contentReplacementImage
592 {
593     if (!_tileCache)
594         return;
595     _tileCache->setContentReplacementImage(contentReplacementImage);
596 }
597
598 - (CGImageRef)contentReplacementImage
599 {
600     if (!_tileCache)
601         return NULL;
602     return _tileCache->contentReplacementImage().get();
603 }
604
605 - (void)displayRect:(NSRect)rect
606 {
607     [[self contentView] displayRect:rect];
608 }
609
610 - (void)willRotate
611 {
612     [self freezeVisibleRect];
613 }
614
615 - (void)didRotate
616 {
617     [self unfreezeVisibleRect];
618 }
619
620 - (void)freezeVisibleRect
621 {
622     _frozenVisibleRect = [self visibleRect];
623 }
624
625 - (void)unfreezeVisibleRect
626 {
627     _frozenVisibleRect = CGRectNull;
628 }
629
630 + (void)setOrientationProvider:(id)provider
631 {
632     // This is really the UIWebDocumentView class that calls into UIApplication to get the orientation.
633     gOrientationProvider = provider;
634 }
635
636 + (BOOL)hasLandscapeOrientation
637 {
638     // this should be perfectly thread safe
639     return [gOrientationProvider hasLandscapeOrientation];
640 }
641
642 - (CALayer*)hostLayer
643 {
644     return _hostLayer;
645 }
646
647 - (void)setTileBordersVisible:(BOOL)visible
648 {
649     if (!_tileCache)
650         return;
651
652     _tileCache->setTileBordersVisible(visible);
653 }
654
655 - (void)setTilePaintCountsVisible:(BOOL)visible
656 {
657     if (!_tileCache)
658         return;
659
660     _tileCache->setTilePaintCountersVisible(visible);
661 }
662
663 - (void)setAcceleratedDrawingEnabled:(BOOL)enabled
664 {
665     if (!_tileCache)
666         return;
667
668     _tileCache->setAcceleratedDrawingEnabled(enabled);
669 }
670
671 - (void)dumpTiles
672 {
673     CGRect savedFrozenVisibleRect = _frozenVisibleRect;
674     NSLog(@"=================");
675     if (!CGRectIsNull(_frozenVisibleRect)) {
676         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);
677         _frozenVisibleRect = CGRectNull;
678     }
679     CGRect visibleRect = [self visibleRect];
680     NSLog(@"visibleRect = [%6.1f %6.1f %6.1f %6.1f]", visibleRect.origin.x, visibleRect.origin.y, visibleRect.size.width, visibleRect.size.height);
681     _frozenVisibleRect = savedFrozenVisibleRect;
682     _tileCache->dumpTiles();
683 }
684
685 - (void)setTileControllerShouldUseLowScaleTiles:(BOOL)lowScaleTiles 
686
687     if (!_tileCache) 
688         return; 
689
690     _tileCache->setTileControllerShouldUseLowScaleTiles(lowScaleTiles); 
691
692
693 - (NSString *)description
694 {
695     NSMutableString *description = [NSMutableString stringWithFormat:@"<%@: WAK: %p; ", [self class], self];
696
697     CGRect frame = [self frame];
698     [description appendFormat:@"frame = (%g %g; %g %g); ", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height];
699
700     [description appendFormat:@"first responder = WK %p; ", _responderView];
701     [description appendFormat:@"next responder = WK %p; ", _nextResponder];
702
703     [description appendFormat:@"layer = %@>", [_hostLayer description]];
704
705     return description;
706 }
707
708 + (WebEvent *)currentEvent
709 {
710     return currentEvent;
711 }
712
713 - (NSString *)recursiveDescription
714 {
715     NSMutableString *info = [NSMutableString string];
716
717     [info appendString:[self description]];
718
719     [[self contentView] _appendDescriptionToString:info atLevel:1];
720
721     return info;
722 }
723
724 @end
725
726 #endif // PLATFORM(IOS)