blob: e2de522ff1534305a7d4d29a5bb9d9449a4a717b [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/css/media_query_evaluator.h"
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/media_list.h"
#include "third_party/blink/renderer/core/css/media_values_cached.h"
#include "third_party/blink/renderer/core/css/media_values_initial_viewport.h"
#include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
#include "third_party/blink/renderer/core/css/parser/media_query_parser.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/media_type_names.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
typedef struct {
const char* input;
const bool output;
} MediaQueryEvaluatorTestCase;
MediaQueryEvaluatorTestCase g_screen_test_cases[] = {
{"", 1},
{" ", 1},
{"screen", 1},
{"screen and (color)", 1},
{"not screen and (color)", 0},
{"screen and (device-aspect-ratio: 16/9)", 0},
{"screen and (device-aspect-ratio: 1/1)", 1},
{"all and (min-color: 2)", 1},
{"all and (min-color: 32)", 0},
{"all and (min-color-index: 0)", 1},
{"all and (min-color-index: 1)", 0},
{"all and (monochrome)", 0},
{"all and (min-monochrome: 0)", 1},
{"all and (grid: 0)", 1},
{"(resolution: 2dppx)", 1},
{"(resolution: 1dppx)", 0},
{"(orientation: portrait)", 1},
{"(orientation: landscape)", 0},
{"(orientation: url(portrait))", 0},
{"(orientation: #portrait)", 0},
{"(orientation: @portrait)", 0},
{"(orientation: 'portrait')", 0},
{"(orientation: @junk portrait)", 0},
{"screen and (orientation: @portrait) and (max-width: 1000px)", 0},
{"screen and (orientation: @portrait), (max-width: 1000px)", 1},
{"tv and (scan: progressive)", 0},
{"(pointer: coarse)", 0},
{"(pointer: fine)", 1},
{"(hover: hover)", 1},
{"(hover: on-demand)", 0},
{"(hover: none)", 0},
{"(display-mode)", 1},
{"(display-mode: fullscreen)", 0},
{"(display-mode: standalone)", 0},
{"(display-mode: minimal-ui)", 0},
{"(display-mode: browser)", 1},
{"(display-mode: min-browser)", 0},
{"(display-mode: url(browser))", 0},
{"(display-mode: #browser)", 0},
{"(display-mode: @browser)", 0},
{"(display-mode: 'browser')", 0},
{"(display-mode: @junk browser)", 0},
{"(shape: rect)", 1},
{"(shape: round)", 0},
{"(max-device-aspect-ratio: 4294967295/1)", 1},
{"(min-device-aspect-ratio: 1/4294967296)", 1},
{nullptr, 0} // Do not remove the terminator line.
};
MediaQueryEvaluatorTestCase g_monochrome_test_cases[] = {
{"(color)", 0},
{"(monochrome)", 1},
{nullptr, 0} // Do not remove the terminator line.
};
MediaQueryEvaluatorTestCase g_viewport_test_cases[] = {
{"all and (min-width: 500px)", 1},
{"(min-width: 500px)", 1},
{"(min-width: 501px)", 0},
{"(max-width: 500px)", 1},
{"(max-width: 499px)", 0},
{"(width: 500px)", 1},
{"(width: 501px)", 0},
{"(min-height: 500px)", 1},
{"(min-height: 501px)", 0},
{"(min-height: 500.02px)", 0},
{"(max-height: 500px)", 1},
{"(max-height: calc(500px))", 1},
{"(max-height: 499.98px)", 0},
{"(max-height: 499px)", 0},
{"(height: 500px)", 1},
{"(height: calc(500px))", 1},
{"(height: 500.001px)", 1},
{"(height: 499.999px)", 1},
{"(height: 500.02px)", 0},
{"(height: 499.98px)", 0},
{"(height: 501px)", 0},
{"(height)", 1},
{"(width)", 1},
{"(width: whatisthis)", 0},
{"screen and (min-width: 400px) and (max-width: 700px)", 1},
{"(max-aspect-ratio: 4294967296/1)", 1},
{"(max-aspect-ratio: calc(4294967296) / calc(1)", 1},
{"(min-aspect-ratio: 1/4294967295)", 1},
{nullptr, 0} // Do not remove the terminator line.
};
MediaQueryEvaluatorTestCase g_float_viewport_test_cases[] = {
{"all and (min-width: 600.5px)", 1},
{"(min-width: 600px)", 1},
{"(min-width: 600.5px)", 1},
{"(min-width: 601px)", 0},
{"(max-width: 600px)", 0},
{"(max-width: 600.5px)", 1},
{"(max-width: 601px)", 1},
{"(width: 600.5px)", 1},
{"(width: 601px)", 0},
{"(min-height: 700px)", 1},
{"(min-height: 700.125px)", 1},
{"(min-height: 701px)", 0},
{"(min-height: 700.141px)", 0},
{"(max-height: 701px)", 1},
{"(max-height: 700.125px)", 1},
{"(max-height: 700px)", 0},
{"(height: 700.125px)", 1},
{"(height: 700.141px)", 0},
{"(height: 700.109px)", 0},
{"(height: 701px)", 0},
{nullptr, 0} // Do not remove the terminator line.
};
MediaQueryEvaluatorTestCase g_float_non_friendly_viewport_test_cases[] = {
{"(min-width: 821px)", 1},
{"(max-width: 821px)", 1},
{"(width: 821px)", 1},
{"(min-height: 821px)", 1},
{"(max-height: 821px)", 1},
{"(height: 821px)", 1},
{"(width: 100vw)", 1},
{"(height: 100vh)", 1},
{nullptr, 0} // Do not remove the terminator line.
};
MediaQueryEvaluatorTestCase g_print_test_cases[] = {
{"print and (min-resolution: 1dppx)", 1},
{"print and (min-resolution: 118dpcm)", 1},
{"print and (min-resolution: 119dpcm)", 0},
{nullptr, 0} // Do not remove the terminator line.
};
MediaQueryEvaluatorTestCase g_non_immersive_test_cases[] = {
{"(immersive: 1)", 0},
{"(immersive: 0)", 1},
{nullptr, 0} // Do not remove the terminator line.
};
MediaQueryEvaluatorTestCase g_immersive_test_cases[] = {
{"(immersive: 1)", 1},
{"(immersive: 0)", 0},
{nullptr, 0} // Do not remove the terminator line.
};
MediaQueryEvaluatorTestCase g_non_ua_sheet_immersive_test_cases[] = {
{"(immersive: 1)", 0},
{"(immersive: 0)", 0},
{nullptr, 0} // Do not remove the terminator line.
};
void TestMQEvaluator(MediaQueryEvaluatorTestCase* test_cases,
const MediaQueryEvaluator& media_query_evaluator,
CSSParserMode mode) {
scoped_refptr<MediaQuerySet> query_set = nullptr;
for (unsigned i = 0; test_cases[i].input; ++i) {
if (String(test_cases[i].input).IsEmpty()) {
query_set = MediaQuerySet::Create();
} else {
query_set = MediaQueryParser::ParseMediaQuerySetInMode(
CSSParserTokenRange(
CSSTokenizer(test_cases[i].input).TokenizeToEOF()),
mode);
}
EXPECT_EQ(test_cases[i].output, media_query_evaluator.Eval(*query_set))
<< "Query: " << test_cases[i].input;
}
}
void TestMQEvaluator(MediaQueryEvaluatorTestCase* test_cases,
const MediaQueryEvaluator& media_query_evaluator) {
TestMQEvaluator(test_cases, media_query_evaluator, kHTMLStandardMode);
}
TEST(MediaQueryEvaluatorTest, Cached) {
MediaValuesCached::MediaValuesCachedData data;
data.viewport_width = 500;
data.viewport_height = 500;
data.device_width = 500;
data.device_height = 500;
data.device_pixel_ratio = 2.0;
data.color_bits_per_component = 24;
data.monochrome_bits_per_component = 0;
data.primary_pointer_type = kPointerTypeFine;
data.primary_hover_type = kHoverTypeHover;
data.default_font_size = 16;
data.three_d_enabled = true;
data.media_type = media_type_names::kScreen;
data.strict_mode = true;
data.display_mode = kWebDisplayModeBrowser;
data.display_shape = kDisplayShapeRect;
data.immersive_mode = false;
// Default values.
{
MediaValues* media_values = MediaValuesCached::Create(data);
MediaQueryEvaluator media_query_evaluator(*media_values);
TestMQEvaluator(g_screen_test_cases, media_query_evaluator);
TestMQEvaluator(g_viewport_test_cases, media_query_evaluator);
TestMQEvaluator(g_non_immersive_test_cases, media_query_evaluator,
kUASheetMode);
TestMQEvaluator(g_non_ua_sheet_immersive_test_cases, media_query_evaluator);
}
// Print values.
{
data.media_type = media_type_names::kPrint;
MediaValues* media_values = MediaValuesCached::Create(data);
MediaQueryEvaluator media_query_evaluator(*media_values);
TestMQEvaluator(g_print_test_cases, media_query_evaluator);
data.media_type = media_type_names::kScreen;
}
// Monochrome values.
{
data.color_bits_per_component = 0;
data.monochrome_bits_per_component = 8;
MediaValues* media_values = MediaValuesCached::Create(data);
MediaQueryEvaluator media_query_evaluator(*media_values);
TestMQEvaluator(g_monochrome_test_cases, media_query_evaluator);
data.color_bits_per_component = 24;
data.monochrome_bits_per_component = 0;
}
// Immersive values.
{
data.immersive_mode = true;
MediaValues* media_values = MediaValuesCached::Create(data);
MediaQueryEvaluator media_query_evaluator(*media_values);
TestMQEvaluator(g_immersive_test_cases, media_query_evaluator,
kUASheetMode);
TestMQEvaluator(g_non_ua_sheet_immersive_test_cases, media_query_evaluator);
data.immersive_mode = false;
}
}
TEST(MediaQueryEvaluatorTest, Dynamic) {
std::unique_ptr<DummyPageHolder> page_holder =
DummyPageHolder::Create(IntSize(500, 500));
page_holder->GetFrameView().SetMediaType(media_type_names::kScreen);
MediaQueryEvaluator media_query_evaluator(&page_holder->GetFrame());
TestMQEvaluator(g_viewport_test_cases, media_query_evaluator);
page_holder->GetFrameView().SetMediaType(media_type_names::kPrint);
TestMQEvaluator(g_print_test_cases, media_query_evaluator);
}
TEST(MediaQueryEvaluatorTest, DynamicNoView) {
std::unique_ptr<DummyPageHolder> page_holder =
DummyPageHolder::Create(IntSize(500, 500));
LocalFrame* frame = &page_holder->GetFrame();
page_holder.reset();
ASSERT_EQ(nullptr, frame->View());
MediaQueryEvaluator media_query_evaluator(frame);
scoped_refptr<MediaQuerySet> query_set = MediaQuerySet::Create("foobar");
EXPECT_FALSE(media_query_evaluator.Eval(*query_set));
}
TEST(MediaQueryEvaluatorTest, CachedFloatViewport) {
MediaValuesCached::MediaValuesCachedData data;
data.viewport_width = 600.5;
data.viewport_height = 700.125;
MediaValues* media_values = MediaValuesCached::Create(data);
MediaQueryEvaluator media_query_evaluator(*media_values);
TestMQEvaluator(g_float_viewport_test_cases, media_query_evaluator);
}
TEST(MediaQueryEvaluatorTest, CachedFloatViewportNonFloatFriendly) {
MediaValuesCached::MediaValuesCachedData data;
data.viewport_width = 821;
data.viewport_height = 821;
MediaValues* media_values = MediaValuesCached::Create(data);
MediaQueryEvaluator media_query_evaluator(*media_values);
TestMQEvaluator(g_float_non_friendly_viewport_test_cases,
media_query_evaluator);
}
TEST(MediaQueryEvaluatorTest, InitialViewport) {
std::unique_ptr<DummyPageHolder> page_holder =
DummyPageHolder::Create(IntSize(500, 500));
page_holder->GetFrameView().SetMediaType(media_type_names::kScreen);
page_holder->GetFrameView().SetLayoutSizeFixedToFrameSize(false);
page_holder->GetFrameView().SetInitialViewportSize(IntSize(500, 500));
page_holder->GetFrameView().SetLayoutSize(IntSize(800, 800));
page_holder->GetFrameView().SetFrameRect(IntRect(0, 0, 800, 800));
MediaQueryEvaluator media_query_evaluator(
MediaValuesInitialViewport::Create(page_holder->GetFrame()));
TestMQEvaluator(g_viewport_test_cases, media_query_evaluator);
}
TEST(MediaQueryEvaluatorTest, DynamicImmersive) {
std::unique_ptr<DummyPageHolder> page_holder =
DummyPageHolder::Create(IntSize(500, 500));
page_holder->GetFrameView().SetMediaType(media_type_names::kScreen);
MediaQueryEvaluator media_query_evaluator(&page_holder->GetFrame());
page_holder->GetDocument().GetSettings()->SetImmersiveModeEnabled(false);
TestMQEvaluator(g_non_immersive_test_cases, media_query_evaluator,
kUASheetMode);
page_holder->GetDocument().GetSettings()->SetImmersiveModeEnabled(true);
TestMQEvaluator(g_immersive_test_cases, media_query_evaluator, kUASheetMode);
}
} // namespace blink