1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/views/examples/examples_main_proc.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "base/base_switches.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/feature_list.h"
14 #include "base/files/file_path.h"
15 #include "base/i18n/icu_util.h"
16 #include "base/lazy_instance.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/path_service.h"
19 #include "base/power_monitor/power_monitor.h"
20 #include "base/power_monitor/power_monitor_device_source.h"
21 #include "base/run_loop.h"
22 #include "base/test/scoped_run_loop_timeout.h"
23 #include "base/test/task_environment.h"
24 #include "base/test/test_discardable_memory_allocator.h"
25 #include "base/test/test_timeouts.h"
26 #include "build/build_config.h"
27 #include "components/viz/common/features.h"
28 #include "components/viz/host/host_frame_sink_manager.h"
29 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
30 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
31 #include "mojo/core/embedder/embedder.h"
32 #include "ui/base/ime/init/input_method_initializer.h"
33 #include "ui/base/resource/resource_bundle.h"
34 #include "ui/base/ui_base_paths.h"
35 #include "ui/compositor/compositor_switches.h"
36 #include "ui/compositor/test/in_process_context_factory.h"
37 #include "ui/compositor/test/test_context_factories.h"
38 #include "ui/display/screen.h"
39 #include "ui/gfx/font_util.h"
40 #include "ui/gfx/image/image.h"
41 #include "ui/gl/gl_switches.h"
42 #include "ui/gl/init/gl_factory.h"
43 #include "ui/views/buildflags.h"
44 #include "ui/views/examples/example_base.h"
45 #include "ui/views/examples/examples_window.h"
46 #include "ui/views/test/desktop_test_views_delegate.h"
47 #include "ui/views/widget/any_widget_observer.h"
48 #include "ui/views/widget/widget.h"
49 
50 #if defined(USE_AURA)
51 #include "ui/aura/env.h"
52 #include "ui/wm/core/wm_state.h"
53 #endif
54 
55 #if defined(OS_CHROMEOS)
56 #include "ui/views/examples/examples_views_delegate_chromeos.h"
57 #endif
58 
59 #if BUILDFLAG(ENABLE_DESKTOP_AURA)
60 #include "ui/views/widget/desktop_aura/desktop_screen.h"
61 #endif
62 
63 #if defined(OS_WIN)
64 #include "ui/base/win/scoped_ole_initializer.h"
65 #include "ui/views/examples/examples_skia_gold_pixel_diff.h"
66 #endif
67 
68 #if defined(USE_OZONE)
69 #include "ui/base/ui_base_features.h"
70 #include "ui/ozone/public/ozone_platform.h"
71 #endif
72 
73 namespace views {
74 namespace examples {
75 
76 base::LazyInstance<base::TestDiscardableMemoryAllocator>::DestructorAtExit
77     g_discardable_memory_allocator = LAZY_INSTANCE_INITIALIZER;
78 
ExamplesMainProc(bool under_test)79 ExamplesExitCode ExamplesMainProc(bool under_test) {
80 #if defined(OS_WIN)
81   ui::ScopedOleInitializer ole_initializer;
82 #endif
83 
84   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
85 
86   // Disabling Direct Composition works around the limitation that
87   // InProcessContextFactory doesn't work with Direct Composition, causing the
88   // window to not render. See http://crbug.com/936249.
89   command_line->AppendSwitch(switches::kDisableDirectComposition);
90 
91   // Disable skia renderer to use GL instead.
92   std::string disabled =
93       command_line->GetSwitchValueASCII(switches::kDisableFeatures);
94   if (!disabled.empty())
95     disabled += ",";
96   disabled += features::kUseSkiaRenderer.name;
97   command_line->AppendSwitchASCII(switches::kDisableFeatures, disabled);
98 
99   base::FeatureList::InitializeInstance(
100       command_line->GetSwitchValueASCII(switches::kEnableFeatures),
101       command_line->GetSwitchValueASCII(switches::kDisableFeatures));
102 
103   if (under_test)
104     command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
105 
106   mojo::core::Init();
107 
108 #if defined(USE_OZONE)
109   if (features::IsUsingOzonePlatform()) {
110     ui::OzonePlatform::InitParams params;
111     params.single_process = true;
112     ui::OzonePlatform::InitializeForGPU(params);
113   }
114 #endif
115 
116   gl::init::InitializeGLOneOff();
117 
118   // Viz depends on the task environment to correctly tear down.
119   base::test::TaskEnvironment task_environment(
120       base::test::TaskEnvironment::MainThreadType::UI);
121 
122   // The ContextFactory must exist before any Compositors are created.
123   auto context_factories =
124       std::make_unique<ui::TestContextFactories>(under_test);
125   context_factories->SetUseTestSurface(false);
126 
127   base::i18n::InitializeICU();
128 
129   ui::RegisterPathProvider();
130 
131   base::FilePath ui_test_pak_path;
132   CHECK(base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
133   ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
134 
135   base::FilePath views_examples_resources_pak_path;
136   CHECK(base::PathService::Get(base::DIR_MODULE,
137                                &views_examples_resources_pak_path));
138   ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
139       views_examples_resources_pak_path.AppendASCII(
140           "views_examples_resources.pak"),
141       ui::SCALE_FACTOR_100P);
142 
143   base::DiscardableMemoryAllocator::SetInstance(
144       g_discardable_memory_allocator.Pointer());
145 
146   base::PowerMonitor::Initialize(
147       std::make_unique<base::PowerMonitorDeviceSource>());
148 
149   gfx::InitializeFonts();
150 
151 #if defined(USE_AURA)
152   std::unique_ptr<aura::Env> env = aura::Env::CreateInstance();
153   aura::Env::GetInstance()->set_context_factory(
154       context_factories->GetContextFactory());
155 #endif
156   ui::InitializeInputMethodForTesting();
157 
158   ExamplesExitCode compare_result = ExamplesExitCode::kSucceeded;
159 
160   {
161 #if defined(OS_CHROMEOS)
162     ExamplesViewsDelegateChromeOS views_delegate;
163 #else
164     views::DesktopTestViewsDelegate views_delegate;
165 #if defined(USE_AURA)
166     wm::WMState wm_state;
167 #endif
168 #endif
169 #if BUILDFLAG(ENABLE_DESKTOP_AURA)
170     std::unique_ptr<display::Screen> desktop_screen =
171         base::WrapUnique(views::CreateDesktopScreen());
172 #endif
173 
174     base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
175 
176 #if defined(OS_WIN)
177     ExamplesSkiaGoldPixelDiff pixel_diff;
178     views::AnyWidgetObserver widget_observer{
179         views::test::AnyWidgetTestPasskey()};
180 
181     // If this app isn't a test, it shouldn't timeout.
182     auto disable_timeout =
183         std::make_unique<base::test::ScopedDisableRunLoopTimeout>();
184 
185     if (under_test) {
186       pixel_diff.Init("ViewsExamples");
187       widget_observer.set_shown_callback(
188           base::BindRepeating(&ExamplesSkiaGoldPixelDiff::OnExamplesWindowShown,
189                               base::Unretained(&pixel_diff)));
190       // Enable the timeout since we're not running in a test.
191       disable_timeout.reset();
192     }
193 #else
194     base::test::ScopedDisableRunLoopTimeout disable_timeout;
195 #endif
196 
197     views::examples::ShowExamplesWindow(run_loop.QuitClosure());
198 
199     run_loop.Run();
200 
201 #if defined(OS_WIN)
202     compare_result = pixel_diff.get_result();
203 #endif
204 
205     ui::ResourceBundle::CleanupSharedInstance();
206   }
207 
208   ui::ShutdownInputMethod();
209 
210 #if defined(USE_AURA)
211   env.reset();
212 #endif
213 
214   return compare_result;
215 }
216 
217 }  // namespace examples
218 }  // namespace views
219