Regression (r244291): Broken API Test AutoLayoutRenderingProgressRelativeOrdering
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / AutoLayoutIntegration.mm
1 /*
2  * Copyright (C) 2015 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 #include "config.h"
27
28 #import "PlatformUtilities.h"
29 #import "TestNavigationDelegate.h"
30 #import <WebKit/WKWebViewPrivate.h>
31 #import <wtf/RetainPtr.h>
32
33 #if PLATFORM(MAC)
34
35 static bool didInvalidateIntrinsicContentSize;
36 static bool didEvaluateJavaScript;
37
38 @interface AutoLayoutWKWebView : WKWebView
39 @property (nonatomic) BOOL expectingIntrinsicContentSizeChange;
40 @property (nonatomic) NSSize expectedIntrinsicContentSize;
41 @end
42
43 @implementation AutoLayoutWKWebView
44
45 - (instancetype)initWithFrame:(NSRect)frame configuration:(WKWebViewConfiguration *)configuration
46 {
47     self = [super initWithFrame:frame configuration:configuration];
48     if (!self)
49         return nil;
50
51     return self;
52 }
53
54 - (void)load:(NSString *)HTMLString withWidth:(CGFloat)width expectingContentSize:(NSSize)size
55 {
56     [self load:HTMLString withWidth:width expectingContentSize:size resettingWidth:YES];
57 }
58
59 - (void)load:(NSString *)HTMLString withWidth:(CGFloat)width expectingContentSize:(NSSize)size resettingWidth:(BOOL)resetAfter
60 {
61     EXPECT_FALSE(_expectingIntrinsicContentSizeChange);
62
63     NSString *baseHTML = @"<style>"
64     "body, html { margin: 0; padding: 0; }"
65     "div { background-color: green; }"
66     ".small { width: 10px; height: 10px; }"
67     ".large { width: 100px; height: 100px; }"
68     ".veryWide { width: 100px; height: 10px; }"
69     ".inline { display: inline-block; }"
70     ".viewportUnit { height: 50vh; }"
71     "</style>";
72
73     [self loadHTMLString:[baseHTML stringByAppendingString:HTMLString] baseURL:nil];
74     [self _test_waitForDidStartProvisionalNavigation];
75     [self beginLayoutAtMinimumWidth:width andExpectContentSizeChange:size];
76     [self _test_waitForDidFinishNavigation];
77
78     [self waitForContentSizeChangeResettingWidth:resetAfter];
79 }
80
81 - (void)beginLayoutAtMinimumWidth:(CGFloat)width andExpectContentSizeChange:(NSSize)size
82 {
83     [self _setMinimumLayoutWidth:width];
84
85     // NOTE: Each adjacent expected result must be different, or we'll early return and not call invalidateIntrinsicContentSize!
86     EXPECT_FALSE(NSEqualSizes(size, self.intrinsicContentSize));
87
88     _expectingIntrinsicContentSizeChange = YES;
89     _expectedIntrinsicContentSize = size;
90     didInvalidateIntrinsicContentSize = false;
91 }
92
93 - (void)waitForContentSizeChangeResettingWidth:(BOOL)resetAfter
94 {
95     TestWebKitAPI::Util::run(&didInvalidateIntrinsicContentSize);
96
97     NSSize intrinsicContentSize = self.intrinsicContentSize;
98     EXPECT_EQ(_expectedIntrinsicContentSize.width, intrinsicContentSize.width);
99     EXPECT_EQ(_expectedIntrinsicContentSize.height, intrinsicContentSize.height);
100
101     if (resetAfter)
102         [self _setMinimumLayoutWidth:0];
103 }
104
105 - (void)layoutAtMinimumWidth:(CGFloat)width andExpectContentSizeChange:(NSSize)size resettingWidth:(BOOL)resetAfter
106 {
107     [self beginLayoutAtMinimumWidth:width andExpectContentSizeChange:size];
108     [self waitForContentSizeChangeResettingWidth:resetAfter];
109 }
110
111 - (void)invalidateIntrinsicContentSize
112 {
113     if (!_expectingIntrinsicContentSizeChange)
114         return;
115
116     _expectingIntrinsicContentSizeChange = NO;
117     didInvalidateIntrinsicContentSize = true;
118 }
119
120 @end
121
122 TEST(WebKit, AutoLayoutIntegration)
123 {
124     RetainPtr<AutoLayoutWKWebView> webView = adoptNS([[AutoLayoutWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 1000, 1000)]);
125
126     // 10x10 rect with the constraint (width >= 50) -> 50x10
127     [webView load:@"<div class='small'></div>" withWidth:50 expectingContentSize:NSMakeSize(50, 10)];
128
129     // 100x100 rect with the constraint (width >= 50) -> 100x100
130     [webView load:@"<div class='large'></div>" withWidth:50 expectingContentSize:NSMakeSize(100, 100)];
131
132     // 100x10 rect with the constraint (width >= 50) -> 100x10
133     [webView load:@"<div class='veryWide'></div>" withWidth:50 expectingContentSize:NSMakeSize(100, 10)];
134
135     // 100px height + 50vh -> 150px
136     [webView _setViewportSizeForCSSViewportUnits:CGSizeMake(100, 100)];
137     [webView load:@"<div class='viewportUnit'></div><div class='large'></div>" withWidth:100 expectingContentSize:NSMakeSize(100, 150)];
138
139     // Ten 10x10 rects, inline, should result in two rows of five; with the constraint (width >= 50) -> 50x20
140     [webView load:@"<div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div>" withWidth:50 expectingContentSize:NSMakeSize(50, 20)];
141
142     // Changing the width to 10 should result in ten rows of one; with the constraint (width >= 10) -> 10x100
143     [webView layoutAtMinimumWidth:10 andExpectContentSizeChange:NSMakeSize(10, 100) resettingWidth:YES];
144
145     // Changing the width to 100 should result in one rows of ten; with the constraint (width >= 100) -> 100x10
146     [webView layoutAtMinimumWidth:100 andExpectContentSizeChange:NSMakeSize(100, 10) resettingWidth:YES];
147
148     // One 100x100 rect and ten 10x10 rects, inline; with the constraint (width >= 20) -> 100x150
149     [webView load:@"<div class='large'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div><div class='small inline'></div>" withWidth:20 expectingContentSize:NSMakeSize(100, 150)];
150
151     // With _shouldExpandContentToViewHeightForAutoLayout off (the default), the page should lay out to the intrinsic height
152     // of the content.
153     [webView load:@"<div class='small'></div>" withWidth:50 expectingContentSize:NSMakeSize(50, 10) resettingWidth:NO];
154     [webView evaluateJavaScript:@"window.innerHeight" completionHandler:^(id value, NSError *error) {
155         EXPECT_TRUE([value isKindOfClass:[NSNumber class]]);
156         EXPECT_EQ(10, [value integerValue]);
157         didEvaluateJavaScript = true;
158     }];
159     TestWebKitAPI::Util::run(&didEvaluateJavaScript);
160     didEvaluateJavaScript = false;
161
162     // Enabling _shouldExpandContentToViewHeightForAutoLayout should make the page lay out to the view height, regardless
163     // of the intrinsic height of the content. We have to load differently-sized content so that we can wait for
164     // the intrinsic size change callback.
165     [webView _setShouldExpandContentToViewHeightForAutoLayout:YES];
166     [webView load:@"<div class='large'></div>" withWidth:50 expectingContentSize:NSMakeSize(100, 1000) resettingWidth:NO];
167     [webView evaluateJavaScript:@"window.innerHeight" completionHandler:^(id value, NSError *error) {
168         EXPECT_TRUE([value isKindOfClass:[NSNumber class]]);
169         EXPECT_EQ(1000, [value integerValue]);
170         didEvaluateJavaScript = true;
171     }];
172     TestWebKitAPI::Util::run(&didEvaluateJavaScript);
173     didEvaluateJavaScript = false;
174     [webView _setShouldExpandContentToViewHeightForAutoLayout:NO];
175 }
176
177 TEST(WebKit, AutoLayoutRenderingProgressRelativeOrdering)
178 {
179     RetainPtr<AutoLayoutWKWebView> webView = adoptNS([[AutoLayoutWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 1000, 1000)]);
180
181     auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]);
182
183     __block bool didFinishNavigation = false;
184     [navigationDelegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) {
185         didFinishNavigation = true;
186     }];
187     __block bool didFirstLayout = false;
188     [navigationDelegate setRenderingProgressDidChange:^(WKWebView *, _WKRenderingProgressEvents progressEvents) {
189         if (progressEvents & _WKRenderingProgressEventFirstLayout) {
190             didFirstLayout = true;
191             EXPECT_TRUE(didInvalidateIntrinsicContentSize);
192         }
193     }];
194     [webView setNavigationDelegate:navigationDelegate.get()];
195
196     [webView _setMinimumLayoutWidth:100];
197     didInvalidateIntrinsicContentSize = false;
198     [webView setExpectingIntrinsicContentSizeChange:YES];
199     [webView setExpectedIntrinsicContentSize:NSMakeSize(100, 400)];
200     [webView loadHTMLString:@"<body style='margin: 0; height: 400px;'></body>" baseURL:nil];
201     TestWebKitAPI::Util::run(&didInvalidateIntrinsicContentSize);
202     TestWebKitAPI::Util::run(&didFirstLayout);
203     TestWebKitAPI::Util::run(&didFinishNavigation);
204     [webView setNavigationDelegate:nil];
205 }
206
207 #endif