blob: da892f9cf4fb0e3017ee2170a17456c567be7e4f [file] [log] [blame]
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "public/web/WebFrame.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "bindings/core/v8/SerializedScriptValueFactory.h"
#include "bindings/core/v8/V8Node.h"
#include "core/clipboard/DataTransfer.h"
#include "core/css/StyleSheetContents.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/css/resolver/ViewportStyleResolver.h"
#include "core/dom/Document.h"
#include "core/dom/Fullscreen.h"
#include "core/dom/NodeComputedStyle.h"
#include "core/dom/Range.h"
#include "core/editing/Editor.h"
#include "core/editing/EphemeralRange.h"
#include "core/editing/FrameSelection.h"
#include "core/editing/VisiblePosition.h"
#include "core/editing/markers/DocumentMarkerController.h"
#include "core/editing/spellcheck/SpellChecker.h"
#include "core/events/MouseEvent.h"
#include "core/fetch/FetchRequest.h"
#include "core/fetch/MemoryCache.h"
#include "core/fetch/ResourceFetcher.h"
#include "core/frame/FrameHost.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/RemoteFrame.h"
#include "core/frame/Settings.h"
#include "core/frame/VisualViewport.h"
#include "core/html/HTMLBodyElement.h"
#include "core/html/HTMLFormElement.h"
#include "core/html/HTMLMediaElement.h"
#include "core/html/ImageDocument.h"
#include "core/input/EventHandler.h"
#include "core/layout/HitTestResult.h"
#include "core/layout/LayoutFullScreen.h"
#include "core/layout/api/LayoutViewItem.h"
#include "core/layout/compositing/PaintLayerCompositor.h"
#include "core/loader/DocumentLoader.h"
#include "core/loader/DocumentThreadableLoader.h"
#include "core/loader/DocumentThreadableLoaderClient.h"
#include "core/loader/FrameLoadRequest.h"
#include "core/loader/ThreadableLoader.h"
#include "core/page/Page.h"
#include "core/page/ScopedPageLoadDeferrer.h"
#include "core/paint/PaintLayer.h"
#include "core/testing/NullExecutionContext.h"
#include "modules/mediastream/MediaStream.h"
#include "modules/mediastream/MediaStreamRegistry.h"
#include "platform/DragImage.h"
#include "platform/PlatformResourceLoader.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/UserGestureIndicator.h"
#include "platform/geometry/FloatRect.h"
#include "platform/network/ResourceError.h"
#include "platform/scroll/ScrollbarTheme.h"
#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
#include "platform/testing/URLTestHelpers.h"
#include "platform/testing/UnitTestHelpers.h"
#include "platform/weborigin/KURLHash.h"
#include "platform/weborigin/SchemeRegistry.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "public/platform/Platform.h"
#include "public/platform/WebCachePolicy.h"
#include "public/platform/WebClipboard.h"
#include "public/platform/WebFloatRect.h"
#include "public/platform/WebMockClipboard.h"
#include "public/platform/WebSecurityOrigin.h"
#include "public/platform/WebThread.h"
#include "public/platform/WebURL.h"
#include "public/platform/WebURLLoaderClient.h"
#include "public/platform/WebURLLoaderMockFactory.h"
#include "public/platform/WebURLResponse.h"
#include "public/web/WebCache.h"
#include "public/web/WebConsoleMessage.h"
#include "public/web/WebDataSource.h"
#include "public/web/WebDeviceEmulationParams.h"
#include "public/web/WebDocument.h"
#include "public/web/WebFindOptions.h"
#include "public/web/WebFormElement.h"
#include "public/web/WebFrameClient.h"
#include "public/web/WebFrameContentDumper.h"
#include "public/web/WebFrameWidget.h"
#include "public/web/WebHistoryItem.h"
#include "public/web/WebPrintParams.h"
#include "public/web/WebRange.h"
#include "public/web/WebRemoteFrame.h"
#include "public/web/WebScriptExecutionCallback.h"
#include "public/web/WebScriptSource.h"
#include "public/web/WebSearchableFormData.h"
#include "public/web/WebSecurityPolicy.h"
#include "public/web/WebSelection.h"
#include "public/web/WebSettings.h"
#include "public/web/WebSpellCheckClient.h"
#include "public/web/WebTextCheckingCompletion.h"
#include "public/web/WebTextCheckingResult.h"
#include "public/web/WebViewClient.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "web/TextFinder.h"
#include "web/WebLocalFrameImpl.h"
#include "web/WebRemoteFrameImpl.h"
#include "web/WebViewImpl.h"
#include "web/tests/FrameTestHelpers.h"
#include "wtf/Forward.h"
#include "wtf/PtrUtil.h"
#include "wtf/dtoa/utils.h"
#include <map>
#include <memory>
#include <stdarg.h>
#include <v8.h>
using blink::URLTestHelpers::toKURL;
using blink::testing::runPendingTasks;
using testing::ElementsAre;
using testing::Mock;
using testing::_;
namespace blink {
::std::ostream& operator<<(::std::ostream& os, const WebFloatSize& size) {
return os << "WebFloatSize: [" << size.width << ", " << size.height << "]";
}
::std::ostream& operator<<(::std::ostream& os, const WebFloatPoint& point) {
return os << "WebFloatPoint: [" << point.x << ", " << point.y << "]";
}
const int touchPointPadding = 32;
#define EXPECT_RECT_EQ(expected, actual) \
do { \
EXPECT_EQ(expected.x(), actual.x()); \
EXPECT_EQ(expected.y(), actual.y()); \
EXPECT_EQ(expected.width(), actual.width()); \
EXPECT_EQ(expected.height(), actual.height()); \
} while (false)
#define EXPECT_SIZE_EQ(expected, actual) \
do { \
EXPECT_EQ(expected.width(), actual.width()); \
EXPECT_EQ(expected.height(), actual.height()); \
} while (false)
#define EXPECT_FLOAT_POINT_EQ(expected, actual) \
do { \
EXPECT_FLOAT_EQ(expected.x(), actual.x()); \
EXPECT_FLOAT_EQ(expected.y(), actual.y()); \
} while (false)
class WebFrameTest : public ::testing::Test {
protected:
WebFrameTest()
: m_baseURL("http://internal.test/"),
m_notBaseURL("http://external.test/"),
m_chromeURL("chrome://") {}
~WebFrameTest() override {
Platform::current()->getURLLoaderMockFactory()->unregisterAllURLs();
WebCache::clear();
}
void registerMockedHttpURLLoad(const std::string& fileName) {
URLTestHelpers::registerMockedURLFromBaseURL(
WebString::fromUTF8(m_baseURL.c_str()),
WebString::fromUTF8(fileName.c_str()));
}
void registerMockedChromeURLLoad(const std::string& fileName) {
URLTestHelpers::registerMockedURLFromBaseURL(
WebString::fromUTF8(m_chromeURL.c_str()),
WebString::fromUTF8(fileName.c_str()));
}
void registerMockedHttpURLLoadWithCSP(const std::string& fileName,
const std::string& csp,
bool reportOnly = false) {
WebURLResponse response;
response.setMIMEType("text/html");
response.addHTTPHeaderField(
reportOnly ? WebString("Content-Security-Policy-Report-Only")
: WebString("Content-Security-Policy"),
WebString::fromUTF8(csp));
std::string fullString = m_baseURL + fileName;
URLTestHelpers::registerMockedURLLoadWithCustomResponse(
toKURL(fullString.c_str()), WebString::fromUTF8(fileName.c_str()),
WebString::fromUTF8(""), response);
}
void registerMockedHttpURLLoadWithMimeType(const std::string& fileName,
const std::string& mimeType) {
URLTestHelpers::registerMockedURLFromBaseURL(
WebString::fromUTF8(m_baseURL.c_str()),
WebString::fromUTF8(fileName.c_str()), WebString::fromUTF8(mimeType));
}
void applyViewportStyleOverride(
FrameTestHelpers::WebViewHelper* webViewHelper) {
webViewHelper->webView()->settings()->setViewportStyle(
WebViewportStyle::Mobile);
}
static void configureCompositingWebView(WebSettings* settings) {
settings->setAcceleratedCompositingEnabled(true);
settings->setPreferCompositingToLCDTextEnabled(true);
}
static void configureAndroid(WebSettings* settings) {
settings->setViewportMetaEnabled(true);
settings->setViewportEnabled(true);
settings->setMainFrameResizesAreOrientationChanges(true);
settings->setShrinksViewportContentToFit(true);
}
static void configureLoadsImagesAutomatically(WebSettings* settings) {
settings->setLoadsImagesAutomatically(true);
}
void initializeTextSelectionWebView(
const std::string& url,
FrameTestHelpers::WebViewHelper* webViewHelper) {
webViewHelper->initializeAndLoad(url, true);
webViewHelper->webView()->settings()->setDefaultFontSize(12);
webViewHelper->resize(WebSize(640, 480));
}
std::unique_ptr<DragImage> nodeImageTestSetup(
FrameTestHelpers::WebViewHelper* webViewHelper,
const std::string& testcase) {
registerMockedHttpURLLoad("nodeimage.html");
webViewHelper->initializeAndLoad(m_baseURL + "nodeimage.html");
webViewHelper->resize(WebSize(640, 480));
LocalFrame* frame =
toLocalFrame(webViewHelper->webView()->page()->mainFrame());
DCHECK(frame);
Element* element = frame->document()->getElementById(testcase.c_str());
return frame->nodeImage(*element);
}
void removeElementById(WebLocalFrameImpl* frame, const AtomicString& id) {
Element* element = frame->frame()->document()->getElementById(id);
DCHECK(element);
element->remove();
}
std::string m_baseURL;
std::string m_notBaseURL;
std::string m_chromeURL;
};
typedef bool TestParamRootLayerScrolling;
class ParameterizedWebFrameTest
: public ::testing::WithParamInterface<TestParamRootLayerScrolling>,
private ScopedRootLayerScrollingForTest,
public WebFrameTest {
public:
ParameterizedWebFrameTest() : ScopedRootLayerScrollingForTest(GetParam()) {}
};
INSTANTIATE_TEST_CASE_P(All, ParameterizedWebFrameTest, ::testing::Bool());
TEST_P(ParameterizedWebFrameTest, ContentText) {
registerMockedHttpURLLoad("iframes_test.html");
registerMockedHttpURLLoad("visible_iframe.html");
registerMockedHttpURLLoad("invisible_iframe.html");
registerMockedHttpURLLoad("zero_sized_iframe.html");
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html");
// Now retrieve the frames text and test it only includes visible elements.
std::string content =
WebFrameContentDumper::dumpWebViewAsText(webViewHelper.webView(), 1024)
.utf8();
EXPECT_NE(std::string::npos, content.find(" visible paragraph"));
EXPECT_NE(std::string::npos, content.find(" visible iframe"));
EXPECT_EQ(std::string::npos, content.find(" invisible pararaph"));
EXPECT_EQ(std::string::npos, content.find(" invisible iframe"));
EXPECT_EQ(std::string::npos, content.find("iframe with zero size"));
}
TEST_P(ParameterizedWebFrameTest, FrameForEnteredContext) {
registerMockedHttpURLLoad("iframes_test.html");
registerMockedHttpURLLoad("visible_iframe.html");
registerMockedHttpURLLoad("invisible_iframe.html");
registerMockedHttpURLLoad("zero_sized_iframe.html");
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "iframes_test.html", true);
v8::HandleScope scope(v8::Isolate::GetCurrent());
EXPECT_EQ(
webViewHelper.webView()->mainFrame(),
WebLocalFrame::frameForContext(
webViewHelper.webView()->mainFrame()->mainWorldScriptContext()));
EXPECT_EQ(webViewHelper.webView()->mainFrame()->firstChild(),
WebLocalFrame::frameForContext(webViewHelper.webView()
->mainFrame()
->firstChild()
->mainWorldScriptContext()));
}
class ScriptExecutionCallbackHelper : public WebScriptExecutionCallback {
public:
explicit ScriptExecutionCallbackHelper(v8::Local<v8::Context> context)
: m_didComplete(false), m_context(context) {}
~ScriptExecutionCallbackHelper() {}
bool didComplete() const { return m_didComplete; }
const String& stringValue() const { return m_stringValue; }
private:
void completed(const WebVector<v8::Local<v8::Value>>& values) override {
m_didComplete = true;
if (!values.isEmpty() && values[0]->IsString()) {
m_stringValue =
toCoreString(values[0]->ToString(m_context).ToLocalChecked());
}
}
bool m_didComplete;
String m_stringValue;
v8::Local<v8::Context> m_context;
};
TEST_P(ParameterizedWebFrameTest, RequestExecuteScript) {
registerMockedHttpURLLoad("foo.html");
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "foo.html", true);
v8::HandleScope scope(v8::Isolate::GetCurrent());
ScriptExecutionCallbackHelper callbackHelper(
webViewHelper.webView()->mainFrame()->mainWorldScriptContext());
webViewHelper.webView()
->mainFrame()
->toWebLocalFrame()
->requestExecuteScriptAndReturnValue(
WebScriptSource(WebString("'hello';")), false, &callbackHelper);
runPendingTasks();
EXPECT_TRUE(callbackHelper.didComplete());
EXPECT_EQ("hello", callbackHelper.stringValue());
}
TEST_P(ParameterizedWebFrameTest, SuspendedRequestExecuteScript) {
registerMockedHttpURLLoad("foo.html");
registerMockedHttpURLLoad("bar.html");
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "foo.html", true);
v8::HandleScope scope(v8::Isolate::GetCurrent());
ScriptExecutionCallbackHelper callbackHelper(
webViewHelper.webView()->mainFrame()->mainWorldScriptContext());
// Suspend scheduled tasks so the script doesn't run.
webViewHelper.webView()
->mainFrameImpl()
->frame()
->document()
->suspendScheduledTasks();
webViewHelper.webView()->mainFrameImpl()->requestExecuteScriptAndReturnValue(
WebScriptSource(WebString("'hello';")), false, &callbackHelper);
runPendingTasks();
EXPECT_FALSE(callbackHelper.didComplete());
// If the frame navigates, pending scripts should be removed, but the callback
// should always be ran.
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "bar.html");
EXPECT_TRUE(callbackHelper.didComplete());
EXPECT_EQ(String(), callbackHelper.stringValue());
}
TEST_P(ParameterizedWebFrameTest, IframeScriptRemovesSelf) {
registerMockedHttpURLLoad("single_iframe.html");
registerMockedHttpURLLoad("visible_iframe.html");
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "single_iframe.html", true);
v8::HandleScope scope(v8::Isolate::GetCurrent());
ScriptExecutionCallbackHelper callbackHelper(
webViewHelper.webView()->mainFrame()->mainWorldScriptContext());
webViewHelper.webView()
->mainFrame()
->firstChild()
->toWebLocalFrame()
->requestExecuteScriptAndReturnValue(
WebScriptSource(WebString(
"var iframe = "
"window.top.document.getElementsByTagName('iframe')[0]; "
"window.top.document.body.removeChild(iframe); 'hello';")),
false, &callbackHelper);
runPendingTasks();
EXPECT_TRUE(callbackHelper.didComplete());
EXPECT_EQ(String(), callbackHelper.stringValue());
}
TEST_P(ParameterizedWebFrameTest, FormWithNullFrame) {
registerMockedHttpURLLoad("form.html");
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "form.html");
WebVector<WebFormElement> forms;
webViewHelper.webView()->mainFrame()->document().forms(forms);
webViewHelper.reset();
EXPECT_EQ(forms.size(), 1U);
// This test passes if this doesn't crash.
WebSearchableFormData searchableDataForm(forms[0]);
}
TEST_P(ParameterizedWebFrameTest, ChromePageJavascript) {
registerMockedChromeURLLoad("history.html");
// Pass true to enable JavaScript.
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true);
// Try to run JS against the chrome-style URL.
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
"javascript:document.body.appendChild(document."
"createTextNode('Clobbered'))");
// Now retrieve the frame's text and ensure it was modified by running
// javascript.
std::string content =
WebFrameContentDumper::dumpWebViewAsText(webViewHelper.webView(), 1024)
.utf8();
EXPECT_NE(std::string::npos, content.find("Clobbered"));
}
TEST_P(ParameterizedWebFrameTest, ChromePageNoJavascript) {
registerMockedChromeURLLoad("history.html");
/// Pass true to enable JavaScript.
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_chromeURL + "history.html", true);
// Try to run JS against the chrome-style URL after prohibiting it.
WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs("chrome");
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
"javascript:document.body.appendChild(document."
"createTextNode('Clobbered'))");
// Now retrieve the frame's text and ensure it wasn't modified by running
// javascript.
std::string content =
WebFrameContentDumper::dumpWebViewAsText(webViewHelper.webView(), 1024)
.utf8();
EXPECT_EQ(std::string::npos, content.find("Clobbered"));
}
TEST_P(ParameterizedWebFrameTest, LocationSetHostWithMissingPort) {
std::string fileName = "print-location-href.html";
registerMockedHttpURLLoad(fileName);
URLTestHelpers::registerMockedURLLoad(
toKURL("http://internal.test:0/" + fileName),
WebString::fromUTF8(fileName));
FrameTestHelpers::WebViewHelper webViewHelper;
/// Pass true to enable JavaScript.
webViewHelper.initializeAndLoad(m_baseURL + fileName, true);
// Setting host to "hostname:" should be treated as "hostname:0".
FrameTestHelpers::loadFrame(
webViewHelper.webView()->mainFrame(),
"javascript:location.host = 'internal.test:'; void 0;");
FrameTestHelpers::loadFrame(
webViewHelper.webView()->mainFrame(),
"javascript:document.body.textContent = location.href; void 0;");
std::string content =
WebFrameContentDumper::dumpWebViewAsText(webViewHelper.webView(), 1024)
.utf8();
EXPECT_EQ("http://internal.test:0/" + fileName, content);
}
TEST_P(ParameterizedWebFrameTest, LocationSetEmptyPort) {
std::string fileName = "print-location-href.html";
registerMockedHttpURLLoad(fileName);
URLTestHelpers::registerMockedURLLoad(
toKURL("http://internal.test:0/" + fileName),
WebString::fromUTF8(fileName));
FrameTestHelpers::WebViewHelper webViewHelper;
/// Pass true to enable JavaScript.
webViewHelper.initializeAndLoad(m_baseURL + fileName, true);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
"javascript:location.port = ''; void 0;");
FrameTestHelpers::loadFrame(
webViewHelper.webView()->mainFrame(),
"javascript:document.body.textContent = location.href; void 0;");
std::string content =
WebFrameContentDumper::dumpWebViewAsText(webViewHelper.webView(), 1024)
.utf8();
EXPECT_EQ("http://internal.test:0/" + fileName, content);
}
class EvaluateOnLoadWebFrameClient
: public FrameTestHelpers::TestWebFrameClient {
public:
EvaluateOnLoadWebFrameClient() : m_executing(false), m_wasExecuted(false) {}
void didClearWindowObject(WebLocalFrame* frame) override {
EXPECT_FALSE(m_executing);
m_wasExecuted = true;
m_executing = true;
v8::HandleScope handleScope(v8::Isolate::GetCurrent());
frame->executeScriptAndReturnValue(
WebScriptSource(WebString("window.someProperty = 42;")));
m_executing = false;
}
bool m_executing;
bool m_wasExecuted;
};
TEST_P(ParameterizedWebFrameTest, DidClearWindowObjectIsNotRecursive) {
EvaluateOnLoadWebFrameClient webFrameClient;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad("about:blank", true, &webFrameClient);
EXPECT_TRUE(webFrameClient.m_wasExecuted);
}
class CSSCallbackWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
public:
CSSCallbackWebFrameClient() : m_updateCount(0) {}
void didMatchCSS(
WebLocalFrame*,
const WebVector<WebString>& newlyMatchingSelectors,
const WebVector<WebString>& stoppedMatchingSelectors) override;
std::map<WebLocalFrame*, std::set<std::string>> m_matchedSelectors;
int m_updateCount;
};
void CSSCallbackWebFrameClient::didMatchCSS(
WebLocalFrame* frame,
const WebVector<WebString>& newlyMatchingSelectors,
const WebVector<WebString>& stoppedMatchingSelectors) {
++m_updateCount;
std::set<std::string>& frameSelectors = m_matchedSelectors[frame];
for (size_t i = 0; i < newlyMatchingSelectors.size(); ++i) {
std::string selector = newlyMatchingSelectors[i].utf8();
EXPECT_EQ(0U, frameSelectors.count(selector)) << selector;
frameSelectors.insert(selector);
}
for (size_t i = 0; i < stoppedMatchingSelectors.size(); ++i) {
std::string selector = stoppedMatchingSelectors[i].utf8();
EXPECT_EQ(1U, frameSelectors.count(selector)) << selector;
frameSelectors.erase(selector);
}
}
class WebFrameCSSCallbackTest : public ::testing::Test {
protected:
WebFrameCSSCallbackTest() {
m_frame = m_helper.initializeAndLoad("about:blank", true, &m_client)
->mainFrame()
->toWebLocalFrame();
}
~WebFrameCSSCallbackTest() {
EXPECT_EQ(1U, m_client.m_matchedSelectors.size());
}
WebDocument doc() const { return m_frame->document(); }
int updateCount() const { return m_client.m_updateCount; }
const std::set<std::string>& matchedSelectors() {
return m_client.m_matchedSelectors[m_frame];
}
void loadHTML(const std::string& html) {
FrameTestHelpers::loadHTMLString(m_frame, html, toKURL("about:blank"));
}
void executeScript(const WebString& code) {
m_frame->executeScript(WebScriptSource(code));
m_frame->view()->updateAllLifecyclePhases();
runPendingTasks();
}
CSSCallbackWebFrameClient m_client;
FrameTestHelpers::WebViewHelper m_helper;
WebLocalFrame* m_frame;
};
TEST_F(WebFrameCSSCallbackTest, AuthorStyleSheet) {
loadHTML(
"<style>"
// This stylesheet checks that the internal property and value can't be
// set by a stylesheet, only WebDocument::watchCSSSelectors().
"div.initial_on { -internal-callback: none; }"
"div.initial_off { -internal-callback: -internal-presence; }"
"</style>"
"<div class=\"initial_on\"></div>"
"<div class=\"initial_off\"></div>");
Vector<WebString> selectors;
selectors.append(WebString::fromUTF8("div.initial_on"));
m_frame->document().watchCSSSelectors(WebVector<WebString>(selectors));
m_frame->view()->updateAllLifecyclePhases();
runPendingTasks();
EXPECT_EQ(1, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre("div.initial_on"));
// Check that adding a watched selector calls back for already-present nodes.
selectors.append(WebString::fromUTF8("div.initial_off"));
doc().watchCSSSelectors(WebVector<WebString>(selectors));
m_frame->view()->updateAllLifecyclePhases();
runPendingTasks();
EXPECT_EQ(2, updateCount());
EXPECT_THAT(matchedSelectors(),
ElementsAre("div.initial_off", "div.initial_on"));
// Check that we can turn off callbacks for certain selectors.
doc().watchCSSSelectors(WebVector<WebString>());
m_frame->view()->updateAllLifecyclePhases();
runPendingTasks();
EXPECT_EQ(3, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre());
}
TEST_F(WebFrameCSSCallbackTest, SharedComputedStyle) {
// Check that adding an element calls back when it matches an existing rule.
Vector<WebString> selectors;
selectors.append(WebString::fromUTF8("span"));
doc().watchCSSSelectors(WebVector<WebString>(selectors));
executeScript(
"i1 = document.createElement('span');"
"i1.id = 'first_span';"
"document.body.appendChild(i1)");
EXPECT_EQ(1, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
// Adding a second element that shares a ComputedStyle shouldn't call back.
// We use <span>s to avoid default style rules that can set
// ComputedStyle::unique().
executeScript(
"i2 = document.createElement('span');"
"i2.id = 'second_span';"
"i1 = document.getElementById('first_span');"
"i1.parentNode.insertBefore(i2, i1.nextSibling);");
EXPECT_EQ(1, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
// Removing the first element shouldn't call back.
executeScript(
"i1 = document.getElementById('first_span');"
"i1.parentNode.removeChild(i1);");
EXPECT_EQ(1, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
// But removing the second element *should* call back.
executeScript(
"i2 = document.getElementById('second_span');"
"i2.parentNode.removeChild(i2);");
EXPECT_EQ(2, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre());
}
TEST_F(WebFrameCSSCallbackTest, CatchesAttributeChange) {
loadHTML("<span></span>");
Vector<WebString> selectors;
selectors.append(WebString::fromUTF8("span[attr=\"value\"]"));
doc().watchCSSSelectors(WebVector<WebString>(selectors));
runPendingTasks();
EXPECT_EQ(0, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre());
executeScript(
"document.querySelector('span').setAttribute('attr', 'value');");
EXPECT_EQ(1, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre("span[attr=\"value\"]"));
}
TEST_F(WebFrameCSSCallbackTest, DisplayNone) {
loadHTML("<div style='display:none'><span></span></div>");
Vector<WebString> selectors;
selectors.append(WebString::fromUTF8("span"));
doc().watchCSSSelectors(WebVector<WebString>(selectors));
runPendingTasks();
EXPECT_EQ(0, updateCount()) << "Don't match elements in display:none trees.";
executeScript(
"d = document.querySelector('div');"
"d.style.display = 'block';");
EXPECT_EQ(1, updateCount()) << "Match elements when they become displayed.";
EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
executeScript(
"d = document.querySelector('div');"
"d.style.display = 'none';");
EXPECT_EQ(2, updateCount())
<< "Unmatch elements when they become undisplayed.";
EXPECT_THAT(matchedSelectors(), ElementsAre());
executeScript(
"s = document.querySelector('span');"
"s.style.display = 'none';");
EXPECT_EQ(2, updateCount())
<< "No effect from no-display'ing a span that's already undisplayed.";
executeScript(
"d = document.querySelector('div');"
"d.style.display = 'block';");
EXPECT_EQ(2, updateCount())
<< "No effect from displaying a div whose span is display:none.";
executeScript(
"s = document.querySelector('span');"
"s.style.display = 'inline';");
EXPECT_EQ(3, updateCount())
<< "Now the span is visible and produces a callback.";
EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
executeScript(
"s = document.querySelector('span');"
"s.style.display = 'none';");
EXPECT_EQ(4, updateCount())
<< "Undisplaying the span directly should produce another callback.";
EXPECT_THAT(matchedSelectors(), ElementsAre());
}
TEST_F(WebFrameCSSCallbackTest, Reparenting) {
loadHTML(
"<div id='d1'><span></span></div>"
"<div id='d2'></div>");
Vector<WebString> selectors;
selectors.append(WebString::fromUTF8("span"));
doc().watchCSSSelectors(WebVector<WebString>(selectors));
m_frame->view()->updateAllLifecyclePhases();
runPendingTasks();
EXPECT_EQ(1, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
executeScript(
"s = document.querySelector('span');"
"d2 = document.getElementById('d2');"
"d2.appendChild(s);");
EXPECT_EQ(1, updateCount()) << "Just moving an element that continues to "
"match shouldn't send a spurious callback.";
EXPECT_THAT(matchedSelectors(), ElementsAre("span"));
}
TEST_F(WebFrameCSSCallbackTest, MultiSelector) {
loadHTML("<span></span>");
// Check that selector lists match as the whole list, not as each element
// independently.
Vector<WebString> selectors;
selectors.append(WebString::fromUTF8("span"));
selectors.append(WebString::fromUTF8("span,p"));
doc().watchCSSSelectors(WebVector<WebString>(selectors));
m_frame->view()->updateAllLifecyclePhases();
runPendingTasks();
EXPECT_EQ(1, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre("span", "span, p"));
}
TEST_F(WebFrameCSSCallbackTest, InvalidSelector) {
loadHTML("<p><span></span></p>");
// Build a list with one valid selector and one invalid.
Vector<WebString> selectors;
selectors.append(WebString::fromUTF8("span"));
selectors.append(WebString::fromUTF8("[")); // Invalid.
selectors.append(WebString::fromUTF8("p span")); // Not compound.
doc().watchCSSSelectors(WebVector<WebString>(selectors));
m_frame->view()->updateAllLifecyclePhases();
runPendingTasks();
EXPECT_EQ(1, updateCount());
EXPECT_THAT(matchedSelectors(), ElementsAre("span"))
<< "An invalid selector shouldn't prevent other selectors from matching.";
}
TEST_P(ParameterizedWebFrameTest, DispatchMessageEventWithOriginCheck) {
registerMockedHttpURLLoad("postmessage_test.html");
// Pass true to enable JavaScript.
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "postmessage_test.html", true);
// Send a message with the correct origin.
WebSecurityOrigin correctOrigin(WebSecurityOrigin::create(toKURL(m_baseURL)));
WebDocument document = webViewHelper.webView()->mainFrame()->document();
WebSerializedScriptValue data(WebSerializedScriptValue::fromString("foo"));
WebDOMMessageEvent message(data, "http://origin.com");
webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(
correctOrigin, message);
// Send another message with incorrect origin.
WebSecurityOrigin incorrectOrigin(
WebSecurityOrigin::create(toKURL(m_chromeURL)));
webViewHelper.webView()->mainFrame()->dispatchMessageEventWithOriginCheck(
incorrectOrigin, message);
// Verify that only the first addition is in the body of the page.
std::string content =
WebFrameContentDumper::dumpWebViewAsText(webViewHelper.webView(), 1024)
.utf8();
EXPECT_NE(std::string::npos, content.find("Message 1."));
EXPECT_EQ(std::string::npos, content.find("Message 2."));
}
TEST_P(ParameterizedWebFrameTest, PostMessageThenDetach) {
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad("about:blank");
LocalFrame* frame =
toLocalFrame(webViewHelper.webView()->page()->mainFrame());
NonThrowableExceptionState exceptionState;
MessagePortArray messagePorts;
frame->domWindow()->postMessage(SerializedScriptValue::serialize("message"),
messagePorts, "*", frame->localDOMWindow(),
exceptionState);
webViewHelper.reset();
EXPECT_FALSE(exceptionState.hadException());
// Success is not crashing.
runPendingTasks();
}
namespace {
class FixedLayoutTestWebViewClient
: public FrameTestHelpers::TestWebViewClient {
public:
WebScreenInfo screenInfo() override { return m_screenInfo; }
WebScreenInfo m_screenInfo;
};
class FakeCompositingWebViewClient : public FixedLayoutTestWebViewClient {};
// Viewport settings need to be set before the page gets loaded
void enableViewportSettings(WebSettings* settings) {
settings->setViewportMetaEnabled(true);
settings->setViewportEnabled(true);
settings->setMainFrameResizesAreOrientationChanges(true);
settings->setShrinksViewportContentToFit(true);
}
// Helper function to set autosizing multipliers on a document.
bool setTextAutosizingMultiplier(Document* document, float multiplier) {
bool multiplierSet = false;
for (LayoutItem layoutItem = document->layoutViewItem(); !layoutItem.isNull();
layoutItem = layoutItem.nextInPreOrder()) {
if (layoutItem.style()) {
layoutItem.mutableStyleRef().setTextAutosizingMultiplier(multiplier);
EXPECT_EQ(multiplier, layoutItem.style()->textAutosizingMultiplier());
multiplierSet = true;
}
}
return multiplierSet;
}
// Helper function to check autosizing multipliers on a document.
bool checkTextAutosizingMultiplier(Document* document, float multiplier) {
bool multiplierChecked = false;
for (LayoutItem layoutItem = document->layoutViewItem(); !layoutItem.isNull();
layoutItem = layoutItem.nextInPreOrder()) {
if (layoutItem.style() && layoutItem.isText()) {
EXPECT_EQ(multiplier, layoutItem.style()->textAutosizingMultiplier());
multiplierChecked = true;
}
}
return multiplierChecked;
}
} // anonymous namespace
TEST_P(ParameterizedWebFrameTest,
ChangeInFixedLayoutResetsTextAutosizingMultipliers) {
registerMockedHttpURLLoad("fixed_layout.html");
FixedLayoutTestWebViewClient client;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
Document* document =
toLocalFrame(webViewHelper.webView()->page()->mainFrame())->document();
document->settings()->setTextAutosizingEnabled(true);
EXPECT_TRUE(document->settings()->textAutosizingEnabled());
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_TRUE(setTextAutosizingMultiplier(document, 2));
ViewportDescription description = document->viewportDescription();
// Choose a width that's not going match the viewport width of the loaded
// document.
description.minWidth = Length(100, blink::Fixed);
description.maxWidth = Length(100, blink::Fixed);
webViewHelper.webView()->updatePageDefinedViewportConstraints(description);
EXPECT_TRUE(checkTextAutosizingMultiplier(document, 1));
}
TEST_P(ParameterizedWebFrameTest,
WorkingTextAutosizingMultipliers_VirtualViewport) {
const std::string htmlFile = "fixed_layout.html";
registerMockedHttpURLLoad(htmlFile);
FixedLayoutTestWebViewClient client;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + htmlFile, true, nullptr, &client,
nullptr, configureAndroid);
Document* document =
toLocalFrame(webViewHelper.webView()->page()->mainFrame())->document();
document->settings()->setTextAutosizingEnabled(true);
EXPECT_TRUE(document->settings()->textAutosizingEnabled());
webViewHelper.resize(WebSize(490, 800));
// Multiplier: 980 / 490 = 2.0
EXPECT_TRUE(checkTextAutosizingMultiplier(document, 2.0));
}
TEST_P(ParameterizedWebFrameTest,
VisualViewportSetSizeInvalidatesTextAutosizingMultipliers) {
registerMockedHttpURLLoad("iframe_reload.html");
registerMockedHttpURLLoad("visible_iframe.html");
FixedLayoutTestWebViewClient client;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "iframe_reload.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
LocalFrame* mainFrame =
toLocalFrame(webViewHelper.webView()->page()->mainFrame());
Document* document = mainFrame->document();
FrameView* frameView = webViewHelper.webView()->mainFrameImpl()->frameView();
document->settings()->setTextAutosizingEnabled(true);
EXPECT_TRUE(document->settings()->textAutosizingEnabled());
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
if (!frame->isLocalFrame())
continue;
EXPECT_TRUE(
setTextAutosizingMultiplier(toLocalFrame(frame)->document(), 2));
for (LayoutItem layoutItem =
toLocalFrame(frame)->document()->layoutViewItem();
!layoutItem.isNull(); layoutItem = layoutItem.nextInPreOrder()) {
if (layoutItem.isText())
EXPECT_FALSE(layoutItem.needsLayout());
}
}
frameView->page()->frameHost().visualViewport().setSize(IntSize(200, 200));
for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
if (!frame->isLocalFrame())
continue;
for (LayoutItem layoutItem =
toLocalFrame(frame)->document()->layoutViewItem();
!layoutItem.isNull(); layoutItem = layoutItem.nextInPreOrder()) {
if (layoutItem.isText())
EXPECT_TRUE(layoutItem.needsLayout());
}
}
}
TEST_P(ParameterizedWebFrameTest, ZeroHeightPositiveWidthNotIgnored) {
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 1280;
int viewportHeight = 0;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
}
TEST_P(ParameterizedWebFrameTest,
DeviceScaleFactorUsesDefaultWithoutViewportTag) {
registerMockedHttpURLLoad("no_viewport_tag.html");
int viewportWidth = 640;
int viewportHeight = 480;
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 2;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(2, webViewHelper.webView()->page()->deviceScaleFactor());
// Device scale factor should be independent of page scale.
webViewHelper.webView()->setDefaultPageScaleLimits(1, 2);
webViewHelper.webView()->setPageScaleFactor(0.5);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
// Force the layout to happen before leaving the test.
webViewHelper.webView()->updateAllLifecyclePhases();
}
TEST_P(ParameterizedWebFrameTest, FixedLayoutInitializeAtMinimumScale) {
registerMockedHttpURLLoad("fixed_layout.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
// Make sure we initialize to minimum scale, even if the window size
// only becomes available after the load begins.
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "fixed_layout.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
int defaultFixedLayoutWidth = 980;
float minimumPageScaleFactor = viewportWidth / (float)defaultFixedLayoutWidth;
EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
EXPECT_EQ(minimumPageScaleFactor,
webViewHelper.webView()->minimumPageScaleFactor());
// Assume the user has pinch zoomed to page scale factor 2.
float userPinchPageScaleFactor = 2;
webViewHelper.webView()->setPageScaleFactor(userPinchPageScaleFactor);
webViewHelper.webView()->updateAllLifecyclePhases();
// Make sure we don't reset to initial scale if the page continues to load.
webViewHelper.webView()->didCommitLoad(false, false);
webViewHelper.webView()->didChangeContentsSize();
EXPECT_EQ(userPinchPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
// Make sure we don't reset to initial scale if the viewport size changes.
webViewHelper.resize(WebSize(viewportWidth, viewportHeight + 100));
EXPECT_EQ(userPinchPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, WideDocumentInitializeAtMinimumScale) {
registerMockedHttpURLLoad("wide_document.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
// Make sure we initialize to minimum scale, even if the window size
// only becomes available after the load begins.
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "wide_document.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
int wideDocumentWidth = 1500;
float minimumPageScaleFactor = viewportWidth / (float)wideDocumentWidth;
EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
EXPECT_EQ(minimumPageScaleFactor,
webViewHelper.webView()->minimumPageScaleFactor());
// Assume the user has pinch zoomed to page scale factor 2.
float userPinchPageScaleFactor = 2;
webViewHelper.webView()->setPageScaleFactor(userPinchPageScaleFactor);
webViewHelper.webView()->updateAllLifecyclePhases();
// Make sure we don't reset to initial scale if the page continues to load.
webViewHelper.webView()->didCommitLoad(false, false);
webViewHelper.webView()->didChangeContentsSize();
EXPECT_EQ(userPinchPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
// Make sure we don't reset to initial scale if the viewport size changes.
webViewHelper.resize(WebSize(viewportWidth, viewportHeight + 100));
EXPECT_EQ(userPinchPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, DelayedViewportInitialScale) {
registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-auto-initial-scale.html", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(0.25f, webViewHelper.webView()->pageScaleFactor());
Document* document =
toLocalFrame(webViewHelper.webView()->page()->mainFrame())->document();
ViewportDescription description = document->viewportDescription();
description.zoom = 2;
document->setViewportDescription(description);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(2, webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, setLoadWithOverviewModeToFalse) {
registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-auto-initial-scale.html", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
// The page must be displayed at 100% zoom.
EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest,
SetLoadWithOverviewModeToFalseAndNoWideViewport) {
registerMockedHttpURLLoad("large-div.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
// The page must be displayed at 100% zoom, despite that it hosts a wide div
// element.
EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, NoWideViewportIgnoresPageViewportWidth) {
registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-auto-initial-scale.html", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
// The page sets viewport width to 3000, but with UseWideViewport == false is
// must be ignored.
EXPECT_EQ(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.width());
EXPECT_EQ(viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.height());
}
TEST_P(ParameterizedWebFrameTest,
NoWideViewportIgnoresPageViewportWidthButAccountsScale) {
registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-wide-2x-initial-scale.html", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
// The page sets viewport width to 3000, but with UseWideViewport == false it
// must be ignored while the initial scale specified by the page must be
// accounted.
EXPECT_EQ(viewportWidth / 2, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.width());
EXPECT_EQ(viewportHeight / 2, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.height());
}
TEST_P(ParameterizedWebFrameTest, WideViewportSetsTo980WithoutViewportTag) {
registerMockedHttpURLLoad("no_viewport_tag.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "no_viewport_tag.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
applyViewportStyleOverride(&webViewHelper);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(980, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.width());
EXPECT_EQ(980.0 / viewportWidth * viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.height());
}
TEST_P(ParameterizedWebFrameTest, WideViewportSetsTo980WithXhtmlMp) {
registerMockedHttpURLLoad("viewport/viewport-legacy-xhtmlmp.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr,
enableViewportSettings);
applyViewportStyleOverride(&webViewHelper);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(true);
FrameTestHelpers::loadFrame(
webViewHelper.webView()->mainFrame(),
m_baseURL + "viewport/viewport-legacy-xhtmlmp.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.width());
EXPECT_EQ(viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.height());
}
TEST_P(ParameterizedWebFrameTest, NoWideViewportAndHeightInMeta) {
registerMockedHttpURLLoad("viewport-height-1000.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "viewport-height-1000.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.width());
}
TEST_P(ParameterizedWebFrameTest, WideViewportSetsTo980WithAutoWidth) {
registerMockedHttpURLLoad("viewport-2x-initial-scale.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "viewport-2x-initial-scale.html",
true, nullptr, &client, nullptr,
enableViewportSettings);
applyViewportStyleOverride(&webViewHelper);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(980, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.width());
EXPECT_EQ(980.0 / viewportWidth * viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.height());
}
TEST_P(ParameterizedWebFrameTest,
PageViewportInitialScaleOverridesLoadWithOverviewMode) {
registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-wide-2x-initial-scale.html", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
// The page must be displayed at 200% zoom, as specified in its viewport meta
// tag.
EXPECT_EQ(2.0f, webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, setInitialPageScaleFactorPermanently) {
registerMockedHttpURLLoad("fixed_layout.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
float enforcedPageScaleFactor = 2.0f;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
applyViewportStyleOverride(&webViewHelper);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(enforcedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
int viewportWidth = 640;
int viewportHeight = 480;
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(enforcedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
webViewHelper.webView()->setInitialPageScaleOverride(-1);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(1.0, webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest,
PermanentInitialPageScaleFactorOverridesLoadWithOverviewMode) {
registerMockedHttpURLLoad("viewport-auto-initial-scale.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
float enforcedPageScaleFactor = 0.5f;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-auto-initial-scale.html", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(enforcedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest,
PermanentInitialPageScaleFactorOverridesPageViewportInitialScale) {
registerMockedHttpURLLoad("viewport-wide-2x-initial-scale.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
float enforcedPageScaleFactor = 0.5f;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-wide-2x-initial-scale.html", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(enforcedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest,
SmallPermanentInitialPageScaleFactorIsClobbered) {
const char* pages[] = {
// These pages trigger the clobbering condition. There must be a matching
// item in "pageScaleFactors" array.
"viewport-device-0.5x-initial-scale.html",
"viewport-initial-scale-1.html",
// These ones do not.
"viewport-auto-initial-scale.html",
"viewport-target-densitydpi-device-and-fixed-width.html"};
float pageScaleFactors[] = {0.5f, 1.0f};
for (size_t i = 0; i < WTF_ARRAY_LENGTH(pages); ++i)
registerMockedHttpURLLoad(pages[i]);
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 400;
int viewportHeight = 300;
float enforcedPageScaleFactor = 0.75f;
for (size_t i = 0; i < WTF_ARRAY_LENGTH(pages); ++i) {
for (int quirkEnabled = 0; quirkEnabled <= 1; ++quirkEnabled) {
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + pages[i], true, nullptr,
&client, nullptr, enableViewportSettings);
applyViewportStyleOverride(&webViewHelper);
webViewHelper.webView()->settings()->setClobberUserAgentInitialScaleQuirk(
quirkEnabled);
webViewHelper.webView()->setInitialPageScaleOverride(
enforcedPageScaleFactor);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
float expectedPageScaleFactor =
quirkEnabled && i < WTF_ARRAY_LENGTH(pageScaleFactors)
? pageScaleFactors[i]
: enforcedPageScaleFactor;
EXPECT_EQ(expectedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
}
}
}
TEST_P(ParameterizedWebFrameTest,
PermanentInitialPageScaleFactorAffectsLayoutWidth) {
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
float enforcedPageScaleFactor = 0.5;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad("about:blank", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.webView()->settings()->setLoadWithOverviewMode(false);
webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(viewportWidth / enforcedPageScaleFactor, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.width());
EXPECT_EQ(enforcedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest,
DocumentElementClientHeightWorksWithWrapContentMode) {
registerMockedHttpURLLoad("0-by-0.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "0-by-0.html", true, nullptr,
&client, nullptr, configureAndroid);
webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
LocalFrame* frame = webViewHelper.webView()->mainFrameImpl()->frame();
Document* document = frame->document();
EXPECT_EQ(viewportHeight, document->documentElement()->clientHeight());
EXPECT_EQ(viewportWidth, document->documentElement()->clientWidth());
}
TEST_P(ParameterizedWebFrameTest,
SetForceZeroLayoutHeightWorksWithWrapContentMode) {
registerMockedHttpURLLoad("0-by-0.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "0-by-0.html", true, nullptr,
&client, nullptr, configureAndroid);
webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
PaintLayerCompositor* compositor = webViewHelper.webView()->compositor();
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
EXPECT_EQ(0.0, compositor->containerLayer()->size().width());
EXPECT_EQ(0.0, compositor->containerLayer()->size().height());
webViewHelper.resize(WebSize(viewportWidth, 0));
EXPECT_EQ(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
EXPECT_EQ(viewportWidth, compositor->containerLayer()->size().width());
EXPECT_EQ(0.0, compositor->containerLayer()->size().height());
// The flag ForceZeroLayoutHeight will cause the following resize of viewport
// height to be ignored by the outer viewport (the container layer of
// LayerCompositor). The height of the visualViewport, however, is not
// affected.
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_FALSE(
webViewHelper.webView()->mainFrameImpl()->frameView()->needsLayout());
EXPECT_EQ(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
EXPECT_EQ(viewportWidth, compositor->containerLayer()->size().width());
EXPECT_EQ(viewportHeight, compositor->containerLayer()->size().height());
LocalFrame* frame = webViewHelper.webView()->mainFrameImpl()->frame();
VisualViewport& visualViewport = frame->page()->frameHost().visualViewport();
EXPECT_EQ(viewportHeight, visualViewport.containerLayer()->size().height());
EXPECT_TRUE(
visualViewport.containerLayer()->platformLayer()->masksToBounds());
EXPECT_FALSE(compositor->containerLayer()->platformLayer()->masksToBounds());
}
TEST_P(ParameterizedWebFrameTest, SetForceZeroLayoutHeight) {
registerMockedHttpURLLoad("200-by-300.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_LE(viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
EXPECT_TRUE(
webViewHelper.webView()->mainFrameImpl()->frameView()->needsLayout());
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
webViewHelper.resize(WebSize(viewportWidth, viewportHeight * 2));
EXPECT_FALSE(
webViewHelper.webView()->mainFrameImpl()->frameView()->needsLayout());
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
webViewHelper.resize(WebSize(viewportWidth * 2, viewportHeight));
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
webViewHelper.webView()->settings()->setForceZeroLayoutHeight(false);
EXPECT_LE(viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
}
TEST_F(WebFrameTest, ToggleViewportMetaOnOff) {
registerMockedHttpURLLoad("viewport-device-width.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "viewport-device-width.html",
true, 0, &client);
WebSettings* settings = webViewHelper.webView()->settings();
settings->setViewportMetaEnabled(false);
settings->setViewportEnabled(true);
settings->setMainFrameResizesAreOrientationChanges(true);
settings->setShrinksViewportContentToFit(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
Document* document =
toLocalFrame(webViewHelper.webView()->page()->mainFrame())->document();
EXPECT_FALSE(document->viewportDescription().isLegacyViewportType());
settings->setViewportMetaEnabled(true);
EXPECT_TRUE(document->viewportDescription().isLegacyViewportType());
settings->setViewportMetaEnabled(false);
EXPECT_FALSE(document->viewportDescription().isLegacyViewportType());
}
TEST_F(WebFrameTest,
SetForceZeroLayoutHeightWorksWithRelayoutsWhenHeightChanged) {
// this unit test is an attempt to target a real world case where an app could
// 1. call resize(width, 0) and setForceZeroLayoutHeight(true)
// 2. load content (hoping that the viewport height would increase
// as more content is added)
// 3. fail to register touch events aimed at the loaded content
// because the layout is only updated if either width or height is changed
registerMockedHttpURLLoad("button.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "button.html", true, nullptr,
&client, nullptr, configureAndroid);
// set view height to zero so that if the height of the view is not
// successfully updated during later resizes touch events will fail
// (as in not hit content included in the view)
webViewHelper.resize(WebSize(viewportWidth, 0));
webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
IntPoint hitPoint = IntPoint(30, 30); // button size is 100x100
WebLocalFrameImpl* frame = webViewHelper.webView()->mainFrameImpl();
Document* document = frame->frame()->document();
Element* element = document->getElementById("tap_button");
ASSERT_NE(nullptr, element);
EXPECT_EQ(String("oldValue"), element->innerText());
PlatformGestureEvent gestureEvent(
PlatformEvent::EventType::GestureTap, hitPoint, hitPoint, IntSize(0, 0),
0, PlatformEvent::NoModifiers, PlatformGestureSourceTouchscreen);
webViewHelper.webView()
->mainFrameImpl()
->frame()
->eventHandler()
.handleGestureEvent(gestureEvent);
// when pressed, the button changes its own text to "updatedValue"
EXPECT_EQ(String("updatedValue"), element->innerText());
}
TEST_F(WebFrameTest, FrameOwnerPropertiesMargin) {
FrameTestHelpers::TestWebViewClient viewClient;
FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
WebView* view = WebView::create(&viewClient, WebPageVisibilityStateVisible);
view->settings()->setJavaScriptEnabled(true);
view->setMainFrame(remoteClient.frame());
WebRemoteFrame* root = view->mainFrame()->toWebRemoteFrame();
root->setReplicatedOrigin(SecurityOrigin::createUnique());
WebFrameOwnerProperties properties;
properties.marginWidth = 11;
properties.marginHeight = 22;
WebLocalFrameImpl* localFrame = FrameTestHelpers::createLocalChild(
root, "frameName", nullptr, nullptr, nullptr, properties);
registerMockedHttpURLLoad("frame_owner_properties.html");
FrameTestHelpers::loadFrame(localFrame,
m_baseURL + "frame_owner_properties.html");
// Check if the LocalFrame has seen the marginwidth and marginheight
// properties.
Document* childDocument = localFrame->frame()->document();
EXPECT_EQ(11, childDocument->firstBodyElement()->getIntegralAttribute(
HTMLNames::marginwidthAttr));
EXPECT_EQ(22, childDocument->firstBodyElement()->getIntegralAttribute(
HTMLNames::marginheightAttr));
FrameView* frameView = localFrame->frameView();
// Expect scrollbars to be enabled by default.
EXPECT_NE(nullptr, frameView->horizontalScrollbar());
EXPECT_NE(nullptr, frameView->verticalScrollbar());
view->close();
}
TEST_F(WebFrameTest, FrameOwnerPropertiesScrolling) {
FrameTestHelpers::TestWebViewClient viewClient;
FrameTestHelpers::TestWebRemoteFrameClient remoteClient;
WebView* view = WebView::create(&viewClient, WebPageVisibilityStateVisible);
view->settings()->setJavaScriptEnabled(true);
view->setMainFrame(remoteClient.frame());
WebRemoteFrame* root = view->mainFrame()->toWebRemoteFrame();
root->setReplicatedOrigin(SecurityOrigin::createUnique());
WebFrameOwnerProperties properties;
// Turn off scrolling in the subframe.
properties.scrollingMode = WebFrameOwnerProperties::ScrollingMode::AlwaysOff;
WebLocalFrameImpl* localFrame = FrameTestHelpers::createLocalChild(
root, "frameName", nullptr, nullptr, nullptr, properties);
registerMockedHttpURLLoad("frame_owner_properties.html");
FrameTestHelpers::loadFrame(localFrame,
m_baseURL + "frame_owner_properties.html");
Document* childDocument = localFrame->frame()->document();
EXPECT_EQ(0, childDocument->firstBodyElement()->getIntegralAttribute(
HTMLNames::marginwidthAttr));
EXPECT_EQ(0, childDocument->firstBodyElement()->getIntegralAttribute(
HTMLNames::marginheightAttr));
FrameView* frameView =
static_cast<WebLocalFrameImpl*>(localFrame)->frameView();
EXPECT_EQ(nullptr, frameView->horizontalScrollbar());
EXPECT_EQ(nullptr, frameView->verticalScrollbar());
view->close();
}
TEST_P(ParameterizedWebFrameTest,
SetForceZeroLayoutHeightWorksAcrossNavigations) {
registerMockedHttpURLLoad("200-by-300.html");
registerMockedHttpURLLoad("large-div.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "large-div.html");
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
}
TEST_P(ParameterizedWebFrameTest,
SetForceZeroLayoutHeightWithWideViewportQuirk) {
registerMockedHttpURLLoad("200-by-300.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "200-by-300.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(true);
webViewHelper.webView()->settings()->setForceZeroLayoutHeight(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(0, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
}
TEST_P(ParameterizedWebFrameTest, WideViewportAndWideContentWithInitialScale) {
registerMockedHttpURLLoad("wide_document_width_viewport.html");
registerMockedHttpURLLoad("white-1x1.png");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 600;
int viewportHeight = 800;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad("about:blank", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(true);
webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "wide_document_width_viewport.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
int wideDocumentWidth = 800;
float minimumPageScaleFactor = viewportWidth / (float)wideDocumentWidth;
EXPECT_EQ(minimumPageScaleFactor, webViewHelper.webView()->pageScaleFactor());
EXPECT_EQ(minimumPageScaleFactor,
webViewHelper.webView()->minimumPageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, WideViewportQuirkClobbersHeight) {
registerMockedHttpURLLoad("viewport-height-1000.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 600;
int viewportHeight = 800;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad("about:blank", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "viewport-height-1000.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(800, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, LayoutSize320Quirk) {
registerMockedHttpURLLoad("viewport/viewport-30.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 600;
int viewportHeight = 800;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad("about:blank", true, nullptr, &client,
nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(true);
webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "viewport/viewport-30.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(600, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(800, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
EXPECT_EQ(1, webViewHelper.webView()->pageScaleFactor());
// The magic number to snap to device-width is 320, so test that 321 is
// respected.
Document* document =
toLocalFrame(webViewHelper.webView()->page()->mainFrame())->document();
ViewportDescription description = document->viewportDescription();
description.minWidth = Length(321, blink::Fixed);
description.maxWidth = Length(321, blink::Fixed);
document->setViewportDescription(description);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(321, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
description.minWidth = Length(320, blink::Fixed);
description.maxWidth = Length(320, blink::Fixed);
document->setViewportDescription(description);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(600, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
description = document->viewportDescription();
description.maxHeight = Length(1000, blink::Fixed);
document->setViewportDescription(description);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(1000, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
description.maxHeight = Length(320, blink::Fixed);
document->setViewportDescription(description);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(800, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height());
}
TEST_P(ParameterizedWebFrameTest, ZeroValuesQuirk) {
registerMockedHttpURLLoad("viewport-zero-values.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setViewportMetaLayoutSizeQuirk(true);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "viewport-zero-values.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
webViewHelper.webView()->settings()->setUseWideViewport(true);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(1.0f, webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, OverflowHiddenDisablesScrolling) {
registerMockedHttpURLLoad("body-overflow-hidden.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "body-overflow-hidden.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
FrameView* view = webViewHelper.webView()->mainFrameImpl()->frameView();
EXPECT_FALSE(view->userInputScrollable(VerticalScrollbar));
EXPECT_FALSE(view->userInputScrollable(HorizontalScrollbar));
}
TEST_P(ParameterizedWebFrameTest,
OverflowHiddenDisablesScrollingWithSetCanHaveScrollbars) {
registerMockedHttpURLLoad("body-overflow-hidden-short.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "body-overflow-hidden-short.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
FrameView* view = webViewHelper.webView()->mainFrameImpl()->frameView();
EXPECT_FALSE(view->userInputScrollable(VerticalScrollbar));
EXPECT_FALSE(view->userInputScrollable(HorizontalScrollbar));
webViewHelper.webView()->mainFrameImpl()->setCanHaveScrollbars(true);
EXPECT_FALSE(view->userInputScrollable(VerticalScrollbar));
EXPECT_FALSE(view->userInputScrollable(HorizontalScrollbar));
}
TEST_F(WebFrameTest, IgnoreOverflowHiddenQuirk) {
registerMockedHttpURLLoad("body-overflow-hidden.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr);
webViewHelper.webView()->settings()->setIgnoreMainFrameOverflowHiddenQuirk(
true);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "body-overflow-hidden.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
FrameView* view = webViewHelper.webView()->mainFrameImpl()->frameView();
EXPECT_TRUE(view->userInputScrollable(VerticalScrollbar));
}
TEST_P(ParameterizedWebFrameTest, NonZeroValuesNoQuirk) {
registerMockedHttpURLLoad("viewport-nonzero-values.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
float expectedPageScaleFactor = 0.5f;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.webView()->settings()->setViewportMetaZeroValuesQuirk(true);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "viewport-nonzero-values.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(expectedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
webViewHelper.webView()->settings()->setUseWideViewport(true);
webViewHelper.webView()->updateAllLifecyclePhases();
EXPECT_EQ(viewportWidth / expectedPageScaleFactor, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width());
EXPECT_EQ(expectedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, setPageScaleFactorDoesNotLayout) {
registerMockedHttpURLLoad("fixed_layout.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
// Small viewport to ensure there are always scrollbars.
int viewportWidth = 64;
int viewportHeight = 48;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
int prevLayoutCount =
webViewHelper.webView()->mainFrameImpl()->frameView()->layoutCount();
webViewHelper.webView()->setPageScaleFactor(3);
EXPECT_FALSE(
webViewHelper.webView()->mainFrameImpl()->frameView()->needsLayout());
EXPECT_EQ(
prevLayoutCount,
webViewHelper.webView()->mainFrameImpl()->frameView()->layoutCount());
}
TEST_P(ParameterizedWebFrameTest,
setPageScaleFactorWithOverlayScrollbarsDoesNotLayout) {
registerMockedHttpURLLoad("fixed_layout.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
int prevLayoutCount =
webViewHelper.webView()->mainFrameImpl()->frameView()->layoutCount();
webViewHelper.webView()->setPageScaleFactor(30);
EXPECT_FALSE(
webViewHelper.webView()->mainFrameImpl()->frameView()->needsLayout());
EXPECT_EQ(
prevLayoutCount,
webViewHelper.webView()->mainFrameImpl()->frameView()->layoutCount());
}
TEST_P(ParameterizedWebFrameTest, pageScaleFactorWrittenToHistoryItem) {
registerMockedHttpURLLoad("fixed_layout.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
webViewHelper.webView()->setPageScaleFactor(3);
EXPECT_EQ(3, toLocalFrame(webViewHelper.webView()->page()->mainFrame())
->loader()
.currentItem()
->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, initialScaleWrittenToHistoryItem) {
registerMockedHttpURLLoad("fixed_layout.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initialize(true, nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
FrameTestHelpers::loadFrame(webViewHelper.webView()->mainFrame(),
m_baseURL + "fixed_layout.html");
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
int defaultFixedLayoutWidth = 980;
float minimumPageScaleFactor = viewportWidth / (float)defaultFixedLayoutWidth;
EXPECT_EQ(minimumPageScaleFactor,
toLocalFrame(webViewHelper.webView()->page()->mainFrame())
->loader()
.currentItem()
->pageScaleFactor());
}
TEST_P(ParameterizedWebFrameTest, pageScaleFactorDoesntShrinkFrameView) {
registerMockedHttpURLLoad("large-div.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
// Small viewport to ensure there are always scrollbars.
int viewportWidth = 64;
int viewportHeight = 48;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
FrameView* view = webViewHelper.webView()->mainFrameImpl()->frameView();
int viewportWidthMinusScrollbar = viewportWidth;
int viewportHeightMinusScrollbar = viewportHeight;
if (view->verticalScrollbar() &&
!view->verticalScrollbar()->isOverlayScrollbar())
viewportWidthMinusScrollbar -= 15;
if (view->horizontalScrollbar() &&
!view->horizontalScrollbar()->isOverlayScrollbar())
viewportHeightMinusScrollbar -= 15;
webViewHelper.webView()->setPageScaleFactor(2);
IntSize unscaledSize = view->visibleContentSize(IncludeScrollbars);
EXPECT_EQ(viewportWidth, unscaledSize.width());
EXPECT_EQ(viewportHeight, unscaledSize.height());
IntSize unscaledSizeMinusScrollbar =
view->visibleContentSize(ExcludeScrollbars);
EXPECT_EQ(viewportWidthMinusScrollbar, unscaledSizeMinusScrollbar.width());
EXPECT_EQ(viewportHeightMinusScrollbar, unscaledSizeMinusScrollbar.height());
IntSize frameViewSize = view->visibleContentRect().size();
EXPECT_EQ(viewportWidthMinusScrollbar, frameViewSize.width());
EXPECT_EQ(viewportHeightMinusScrollbar, frameViewSize.height());
}
TEST_P(ParameterizedWebFrameTest, pageScaleFactorDoesNotApplyCssTransform) {
registerMockedHttpURLLoad("fixed_layout.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "fixed_layout.html", true,
nullptr, &client, nullptr,
enableViewportSettings);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
webViewHelper.webView()->setPageScaleFactor(2);
EXPECT_EQ(980, toLocalFrame(webViewHelper.webView()->page()->mainFrame())
->contentLayoutItem()
.documentRect()
.width());
EXPECT_EQ(980, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->contentsSize()
.width());
}
TEST_P(ParameterizedWebFrameTest, targetDensityDpiHigh) {
registerMockedHttpURLLoad("viewport-target-densitydpi-high.html");
FixedLayoutTestWebViewClient client;
// high-dpi = 240
float targetDpi = 240.0f;
float deviceScaleFactors[] = {1.0f, 4.0f / 3.0f, 2.0f};
int viewportWidth = 640;
int viewportHeight = 480;
for (size_t i = 0; i < WTF_ARRAY_LENGTH(deviceScaleFactors); ++i) {
float deviceScaleFactor = deviceScaleFactors[i];
float deviceDpi = deviceScaleFactor * 160.0f;
client.m_screenInfo.deviceScaleFactor = deviceScaleFactor;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-target-densitydpi-high.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(
true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
// We need to account for the fact that logical pixels are unconditionally
// multiplied by deviceScaleFactor to produce physical pixels.
float densityDpiScaleRatio = deviceScaleFactor * targetDpi / deviceDpi;
EXPECT_NEAR(viewportWidth * densityDpiScaleRatio, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width(),
1.0f);
EXPECT_NEAR(viewportHeight * densityDpiScaleRatio, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height(),
1.0f);
EXPECT_NEAR(1.0f / densityDpiScaleRatio,
webViewHelper.webView()->pageScaleFactor(), 0.01f);
}
}
TEST_P(ParameterizedWebFrameTest, targetDensityDpiDevice) {
registerMockedHttpURLLoad("viewport-target-densitydpi-device.html");
float deviceScaleFactors[] = {1.0f, 4.0f / 3.0f, 2.0f};
FixedLayoutTestWebViewClient client;
int viewportWidth = 640;
int viewportHeight = 480;
for (size_t i = 0; i < WTF_ARRAY_LENGTH(deviceScaleFactors); ++i) {
client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i];
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-target-densitydpi-device.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(
true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor,
webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width(),
1.0f);
EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor,
webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height(),
1.0f);
EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor,
webViewHelper.webView()->pageScaleFactor(), 0.01f);
}
}
TEST_P(ParameterizedWebFrameTest, targetDensityDpiDeviceAndFixedWidth) {
registerMockedHttpURLLoad(
"viewport-target-densitydpi-device-and-fixed-width.html");
float deviceScaleFactors[] = {1.0f, 4.0f / 3.0f, 2.0f};
FixedLayoutTestWebViewClient client;
int viewportWidth = 640;
int viewportHeight = 480;
for (size_t i = 0; i < WTF_ARRAY_LENGTH(deviceScaleFactors); ++i) {
client.m_screenInfo.deviceScaleFactor = deviceScaleFactors[i];
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-target-densitydpi-device-and-fixed-width.html",
true, nullptr, &client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(
true);
webViewHelper.webView()->settings()->setUseWideViewport(true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_NEAR(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width(),
1.0f);
EXPECT_NEAR(viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height(),
1.0f);
EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
}
}
TEST_P(ParameterizedWebFrameTest, NoWideViewportAndScaleLessThanOne) {
registerMockedHttpURLLoad("viewport-initial-scale-less-than-1.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1.33f;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-initial-scale-less-than-1.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(
true);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor,
webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width(),
1.0f);
EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor,
webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height(),
1.0f);
EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor,
webViewHelper.webView()->pageScaleFactor(), 0.01f);
}
TEST_P(ParameterizedWebFrameTest,
NoWideViewportAndScaleLessThanOneWithDeviceWidth) {
registerMockedHttpURLLoad(
"viewport-initial-scale-less-than-1-device-width.html");
FixedLayoutTestWebViewClient client;
client.m_screenInfo.deviceScaleFactor = 1.33f;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-initial-scale-less-than-1-device-width.html", true,
nullptr, &client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setSupportDeprecatedTargetDensityDPI(
true);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
const float pageZoom = 0.25f;
EXPECT_NEAR(viewportWidth * client.m_screenInfo.deviceScaleFactor / pageZoom,
webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width(),
1.0f);
EXPECT_NEAR(viewportHeight * client.m_screenInfo.deviceScaleFactor / pageZoom,
webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height(),
1.0f);
EXPECT_NEAR(1.0f / client.m_screenInfo.deviceScaleFactor,
webViewHelper.webView()->pageScaleFactor(), 0.01f);
}
TEST_P(ParameterizedWebFrameTest,
NoWideViewportAndNoViewportWithInitialPageScaleOverride) {
registerMockedHttpURLLoad("large-div.html");
FixedLayoutTestWebViewClient client;
int viewportWidth = 640;
int viewportHeight = 480;
float enforcedPageScaleFactor = 5.0f;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(m_baseURL + "large-div.html", true, nullptr,
&client, nullptr, enableViewportSettings);
webViewHelper.webView()->setDefaultPageScaleLimits(0.25f, 5);
webViewHelper.webView()->settings()->setWideViewportQuirkEnabled(true);
webViewHelper.webView()->settings()->setUseWideViewport(false);
webViewHelper.webView()->setInitialPageScaleOverride(enforcedPageScaleFactor);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_NEAR(viewportWidth / enforcedPageScaleFactor, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width(),
1.0f);
EXPECT_NEAR(viewportHeight / enforcedPageScaleFactor, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height(),
1.0f);
EXPECT_NEAR(enforcedPageScaleFactor,
webViewHelper.webView()->pageScaleFactor(), 0.01f);
}
TEST_P(ParameterizedWebFrameTest, NoUserScalableQuirkIgnoresViewportScale) {
registerMockedHttpURLLoad("viewport-initial-scale-and-user-scalable-no.html");
FixedLayoutTestWebViewClient client;
int viewportWidth = 640;
int viewportHeight = 480;
FrameTestHelpers::WebViewHelper webViewHelper;
webViewHelper.initializeAndLoad(
m_baseURL + "viewport-initial-scale-and-user-scalable-no.html", true,
nullptr, &client, nullptr, enableViewportSettings);
webViewHelper.webView()->settings()->setViewportMetaNonUserScalableQuirk(
true);
webViewHelper.resize(WebSize(viewportWidth, viewportHeight));
EXPECT_NEAR(viewportWidth, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.width(),
1.0f);
EXPECT_NEAR(viewportHeight, webViewHelper.webView()
->mainFrameImpl()
->frameView()
->layoutSize()
.height(),
1.0f);
EXPECT_NEAR(1.0f, webViewHelper.webView()->pageScaleFactor(), 0.01f);
}