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