├── .all-contributorsrc ├── .gitignore ├── .vscode └── settings.json ├── BUILD.gn ├── README.md ├── README_zh.md ├── common └── utils.h ├── demo.cc ├── demo_android ├── BUILD.gn ├── demo_android_skia │ ├── AndroidManifest.xml │ ├── BUILD.gn │ ├── README.md │ ├── cpp │ │ ├── demo_android_skia_library_loader.cc │ │ ├── skia_canvas.cc │ │ ├── skia_canvas.h │ │ ├── skia_canvas_gl.cc │ │ ├── skia_canvas_gl.h │ │ ├── skia_canvas_software.cc │ │ ├── skia_canvas_software.h │ │ └── trace_android.h │ ├── gapid_opengles_trace.gfxtrace │ ├── res │ │ ├── layout │ │ │ └── main_activity.xml │ │ ├── mipmap-hdpi │ │ │ └── app_icon.png │ │ └── values │ │ │ └── strings.xml │ ├── src │ │ └── org │ │ │ └── demo │ │ │ ├── demo_android_skia │ │ │ ├── DemoAndroidSkiaActivity.java │ │ │ └── DemoAndroidSkiaApplication.java │ │ │ └── demo_jni │ │ │ └── SkiaCanvas.java │ └── systrace_data.zip └── demo_apk │ ├── AndroidManifest.xml │ ├── BUILD.gn │ ├── README.md │ ├── cpp │ ├── demo_apk_library_loader.cc │ ├── demo_foo.cc │ └── demo_foo.h │ ├── res │ ├── layout │ │ └── demo_apk_activity.xml │ ├── mipmap-hdpi │ │ └── app_icon.png │ └── values │ │ └── strings.xml │ └── src │ └── org │ └── chromium │ ├── demo_apk │ ├── DemoApkActivity.java │ └── DemoApkApplication.java │ └── demo_jni │ └── DemoFoo.java ├── demo_callback ├── BUILD.gn ├── demo_callback_once.cc └── demo_callback_repeating.cc ├── demo_cc ├── BUILD.gn ├── README.md ├── TRACE.txt ├── demo_cc_gui.cc └── demo_cc_offscreen.cc ├── demo_gin ├── BUILD.gn ├── README.md ├── demo_gin.cc ├── extends │ ├── async_demo.cc │ ├── async_demo.h │ ├── console.cc │ ├── console.h │ ├── demo.cc │ └── demo.h ├── shell_runner_delegate.cc └── shell_runner_delegate.h ├── demo_gl ├── BUILD.gn ├── README.md └── demo_gl.cc ├── demo_ipc ├── BUILD.gn ├── demo_ipc.cc ├── demo_ipc_message_generator.cc ├── demo_ipc_message_generator.h └── demo_ipc_messages.h ├── demo_linktest ├── BUILD.gn ├── README.md ├── a.cc ├── b.cc └── main.cc ├── demo_log ├── BUILD.gn └── demo_log.cc ├── demo_memory ├── BUILD.gn └── demo_memory.cc ├── demo_mojo ├── BUILD.gn ├── README.md ├── demo_mojo_multiple_process.cc ├── demo_mojo_multiple_process_binding.cc ├── demo_mojo_single_process.cc ├── demo_services.cc └── mojom │ ├── BUILD.gn │ ├── consumer_service_manifest.json │ ├── test.mojom │ ├── test2.mojom │ ├── test3.mojom │ ├── test4.mojom │ ├── test_service.mojom │ └── test_service_manifest.json ├── demo_mojo_v8 ├── BUILD.gn ├── README.md ├── browser │ ├── demo_impl.cc │ └── demo_impl.h ├── mojom │ └── demo.mojom ├── renderer │ ├── demo_render_frame_observer.cc │ ├── demo_render_frame_observer.h │ ├── demo_v8_binding.cc │ └── demo_v8_binding.h ├── test │ └── index.html └── v8 │ ├── node.h │ ├── node_object_wrap.h │ └── node_version.h ├── demo_resources ├── BUILD.gn ├── demo_resource_ids ├── demo_resources.cc ├── demo_resources.grd ├── demo_resources_zh-CN.xtb ├── demo_strings.grd └── demo_strings_zh-CN.xtb ├── demo_shell ├── BUILD.gn ├── README.md ├── android │ ├── BUILD.gn │ ├── demo_shell_descriptors.h │ ├── demo_shell_library_loader.cc │ ├── demo_shell_manager.cc │ ├── demo_shell_manager.h │ ├── java │ │ ├── res │ │ │ ├── layout │ │ │ │ └── shell_view.xml │ │ │ ├── mipmap-hdpi │ │ │ │ └── app_icon.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── app_icon.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── app_icon.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── app_icon.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── app_icon.png │ │ │ └── values │ │ │ │ └── strings.xml │ │ └── src │ │ │ └── org │ │ │ └── chromium │ │ │ └── demo_shell │ │ │ ├── Shell.java │ │ │ ├── ShellManager.java │ │ │ └── ShellViewAndroidDelegate.java │ └── shell_apk │ │ ├── AndroidManifest.xml.jinja2 │ │ ├── res │ │ ├── layout │ │ │ └── demo_shell_activity.xml │ │ └── values │ │ │ └── strings.xml │ │ └── src │ │ └── org │ │ └── chromium │ │ └── demo_shell_apk │ │ ├── DemoShellActivity.java │ │ └── DemoShellApplication.java ├── app │ ├── demo_shell_content_main_delegate.cc │ ├── demo_shell_content_main_delegate.h │ └── demo_shell_main.cc ├── browser │ ├── demo_shell_browser_context.cc │ ├── demo_shell_browser_context.h │ ├── demo_shell_browser_main_parts.cc │ ├── demo_shell_browser_main_parts.h │ ├── demo_shell_content_browser_client.cc │ ├── demo_shell_content_browser_client.h │ ├── demo_shell_download_manager_delegate.cc │ ├── demo_shell_download_manager_delegate.h │ ├── demo_shell_permission_manager.cc │ ├── demo_shell_permission_manager.h │ ├── demo_shell_platform_data_aura.cc │ ├── demo_shell_platform_data_aura.h │ ├── shell.cc │ ├── shell.h │ ├── shell_android.cc │ └── shell_views.cc ├── common │ ├── demo_shell_content_client.cc │ ├── demo_shell_content_client.h │ ├── demo_shell_origin_trial_policy.cc │ ├── demo_shell_origin_trial_policy.h │ ├── demo_shell_switches.cc │ └── demo_shell_switches.h ├── demo_shell_resources.grd ├── renderer │ ├── demo_shell_content_renderer_client.cc │ └── demo_shell_content_renderer_client.h ├── resource_ids ├── resources │ ├── README.txt │ ├── brokenCanvas.png │ └── shell_devtools_discovery_page.html ├── utility │ ├── demo_shell_content_utility_client.cc │ └── demo_shell_content_utility_client.h └── version.h.in ├── demo_skia ├── BUILD.gn ├── README.md ├── demo_skia.cc ├── skia_canvas.cc ├── skia_canvas.h ├── skia_canvas_gl.cc ├── skia_canvas_gl.h ├── skia_canvas_software.cc └── skia_canvas_software.h ├── demo_task ├── BUILD.gn ├── demo_task_executor.cc ├── demo_task_thread.cc └── demo_task_thread_pool.cc ├── demo_tracing ├── BUILD.gn ├── README.md ├── demo_tracing_console.cc ├── demo_tracing_perfetto.cc └── demo_tracing_perfetto_content.cc ├── demo_views ├── BUILD.gn ├── README.md └── demo_views.cc ├── demo_viz ├── BUILD.gn ├── README.md ├── demo_viz_gui.cc ├── demo_viz_gui_gpu.cc ├── demo_viz_layer.cc ├── demo_viz_layer_offscreen.cc ├── demo_viz_layer_offscreen_client.cc ├── demo_viz_layer_offscreen_client.h └── demo_viz_offscreen.cc ├── demo_x11 ├── BUILD.gn ├── README.md ├── demo_x11.cc ├── demo_x11_egl.cc └── demo_x11_glx.cc ├── docs ├── content.md ├── images │ ├── 2020-01-03-09-53-49.png │ ├── 2020-01-03-10-00-48.png │ ├── 2020-01-03-10-01-55.png │ ├── 2020-01-03-13-48-06.png │ ├── 2020-01-03-13-49-40.png │ ├── 2020-01-03-14-13-56.png │ ├── 2020-01-03-15-10-02.png │ ├── 2020-01-03-17-09-31.png │ ├── 2020-05-22-17-09-02.png │ ├── chromium-mojo-layer.png │ ├── mojo_interface_pipe.png │ └── mojo_stack.png ├── mojo.md ├── startup.md ├── tracing.md ├── ui.md └── viz.md ├── patches ├── 0001-demo_viz_layer_offscreen-add-GetOffscreenTextureId.patch └── 0002-demo_mojo_v8.patch └── wechat.jpeg /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "ManonLoki", 10 | "name": "ManonLoki", 11 | "avatar_url": "https://avatars.githubusercontent.com/u/10202538?v=4", 12 | "profile": "https://github.com/ManonLoki", 13 | "contributions": [ 14 | "ideas", 15 | "code" 16 | ] 17 | }, 18 | { 19 | "login": "lgjh123", 20 | "name": "ligaojin", 21 | "avatar_url": "https://avatars.githubusercontent.com/u/33198766?v=4", 22 | "profile": "https://github.com/lgjh123", 23 | "contributions": [ 24 | "code" 25 | ] 26 | }, 27 | { 28 | "login": "Drecc", 29 | "name": "Drecc", 30 | "avatar_url": "https://avatars.githubusercontent.com/u/12831867?v=4", 31 | "profile": "https://github.com/Drecc", 32 | "contributions": [ 33 | "code" 34 | ] 35 | }, 36 | { 37 | "login": "hc-tec", 38 | "name": "hc-tec", 39 | "avatar_url": "https://avatars.githubusercontent.com/u/59106739?v=4", 40 | "profile": "https://github.com/hc-tec", 41 | "contributions": [ 42 | "code" 43 | ] 44 | }, 45 | { 46 | "login": "SamuelQZQ", 47 | "name": "QZQ", 48 | "avatar_url": "https://avatars.githubusercontent.com/u/19623228?v=4", 49 | "profile": "https://qzq.at", 50 | "contributions": [ 51 | "code" 52 | ] 53 | }, 54 | { 55 | "login": "mikucy", 56 | "name": "Midori", 57 | "avatar_url": "https://avatars.githubusercontent.com/u/23072202?v=4", 58 | "profile": "https://github.com/mikucy", 59 | "contributions": [ 60 | "code", 61 | "doc" 62 | ] 63 | }, 64 | { 65 | "login": "shaochenguang", 66 | "name": "chenguang shao", 67 | "avatar_url": "https://avatars.githubusercontent.com/u/33643378?v=4", 68 | "profile": "https://github.com/shaochenguang", 69 | "contributions": [ 70 | "code" 71 | ] 72 | } 73 | ], 74 | "contributorsPerLine": 7, 75 | "projectName": "chromium_demo", 76 | "projectOwner": "keyou", 77 | "repoType": "github", 78 | "repoHost": "https://github.com", 79 | "skipCi": true, 80 | "commitConvention": "angular", 81 | "commitType": "docs" 82 | } 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/c++,tags,code,ninja 3 | # Edit at https://www.gitignore.io/?templates=c++,tags,code,ninja 4 | 5 | ### C++ ### 6 | # Prerequisites 7 | *.d 8 | 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Compiled Dynamic libraries 20 | *.so 21 | *.dylib 22 | *.dll 23 | 24 | # Fortran module files 25 | *.mod 26 | *.smod 27 | 28 | # Compiled Static libraries 29 | *.lai 30 | *.la 31 | *.a 32 | *.lib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | 39 | ### Code ### 40 | .vscode/* 41 | !.vscode/settings.json 42 | !.vscode/tasks.json 43 | !.vscode/launch.json 44 | !.vscode/extensions.json 45 | 46 | ### Ninja ### 47 | .ninja_deps 48 | .ninja_log 49 | 50 | ### Tags ### 51 | # Ignore tags created by etags, ctags, gtags (GNU global) and cscope 52 | TAGS 53 | .TAGS 54 | !TAGS/ 55 | tags 56 | .tags 57 | !tags/ 58 | gtags.files 59 | GTAGS 60 | GRTAGS 61 | GPATH 62 | GSYMS 63 | cscope.files 64 | cscope.out 65 | cscope.in.out 66 | cscope.po.out 67 | 68 | 69 | # End of https://www.gitignore.io/api/c++,tags,code,ninja 70 | 71 | *.xmb 72 | 73 | # Ignore Mac Files 74 | .DS_Store 75 | 76 | /*.json 77 | 78 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.gni": "python", 4 | "string": "cpp", 5 | "bitset": "cpp", 6 | "forward_list": "cpp", 7 | "functional": "cpp", 8 | "list": "cpp", 9 | "memory": "cpp", 10 | "tuple": "cpp", 11 | "*.tcc": "cpp", 12 | "__tree": "cpp", 13 | "algorithm": "cpp", 14 | "random": "cpp", 15 | "optional": "cpp", 16 | "system_error": "cpp", 17 | "regex": "cpp", 18 | "typeinfo": "cpp", 19 | "__bit_reference": "cpp", 20 | "__config": "cpp", 21 | "__debug": "cpp", 22 | "__errc": "cpp", 23 | "__functional_base": "cpp", 24 | "__hash_table": "cpp", 25 | "__locale": "cpp", 26 | "__mutex_base": "cpp", 27 | "__node_handle": "cpp", 28 | "__nullptr": "cpp", 29 | "__split_buffer": "cpp", 30 | "__string": "cpp", 31 | "__threading_support": "cpp", 32 | "__tuple": "cpp", 33 | "array": "cpp", 34 | "atomic": "cpp", 35 | "bit": "cpp", 36 | "cctype": "cpp", 37 | "chrono": "cpp", 38 | "clocale": "cpp", 39 | "cmath": "cpp", 40 | "compare": "cpp", 41 | "complex": "cpp", 42 | "concepts": "cpp", 43 | "condition_variable": "cpp", 44 | "cstdarg": "cpp", 45 | "cstddef": "cpp", 46 | "cstdint": "cpp", 47 | "cstdio": "cpp", 48 | "cstdlib": "cpp", 49 | "cstring": "cpp", 50 | "ctime": "cpp", 51 | "cwchar": "cpp", 52 | "cwctype": "cpp", 53 | "deque": "cpp", 54 | "exception": "cpp", 55 | "initializer_list": "cpp", 56 | "ios": "cpp", 57 | "iosfwd": "cpp", 58 | "iostream": "cpp", 59 | "istream": "cpp", 60 | "iterator": "cpp", 61 | "limits": "cpp", 62 | "locale": "cpp", 63 | "map": "cpp", 64 | "mutex": "cpp", 65 | "new": "cpp", 66 | "numbers": "cpp", 67 | "numeric": "cpp", 68 | "ostream": "cpp", 69 | "queue": "cpp", 70 | "ratio": "cpp", 71 | "semaphore": "cpp", 72 | "sstream": "cpp", 73 | "stdexcept": "cpp", 74 | "streambuf": "cpp", 75 | "string_view": "cpp", 76 | "thread": "cpp", 77 | "type_traits": "cpp", 78 | "unordered_map": "cpp", 79 | "utility": "cpp", 80 | "vector": "cpp", 81 | "memory_resource": "cpp", 82 | "stop_token": "cpp" 83 | }, 84 | "commentTranslate.targetLanguage": "zh-CN", 85 | "pasteImage.filePathConfirmInputBoxMode": "onlyName", 86 | "pasteImage.path": "${currentFileDir}/images" 87 | } -------------------------------------------------------------------------------- /BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | is_desktop = is_linux || is_mac || is_win 3 | 4 | group("demo") { 5 | testonly = true 6 | 7 | deps = [ 8 | ":demo_exe", 9 | "demo_callback", 10 | "demo_log", 11 | "demo_task", 12 | ] 13 | 14 | if(is_desktop) { 15 | deps += [ 16 | "demo_tracing", 17 | "demo_ipc", 18 | "demo_memory", 19 | "demo_mojo", 20 | ] 21 | } 22 | 23 | if (is_linux) { 24 | deps += [ 25 | "demo_cc", 26 | "demo_gin", 27 | "demo_gl", 28 | "demo_mojo_v8", 29 | "demo_resources", 30 | "demo_shell", 31 | "demo_skia", 32 | "demo_views", 33 | "demo_viz", 34 | "demo_x11", 35 | "demo_linktest", 36 | ] 37 | } 38 | 39 | if (is_android) { 40 | deps += [ 41 | "demo_android", 42 | "demo_shell", 43 | ] 44 | } 45 | 46 | if (is_win) { 47 | deps += [ 48 | # "demo_resources", 49 | "demo_cc", 50 | "demo_gl", 51 | "demo_mojo_v8", 52 | "demo_views", 53 | # "demo_x11", windows不支持x11 54 | # "demo_skia", windows不支持x11的软件渲染 55 | "demo_viz", 56 | ] 57 | } 58 | 59 | if (is_mac) { 60 | deps += [ 61 | "demo_resources", 62 | "demo_linktest", 63 | ] 64 | } 65 | } 66 | 67 | executable("demo_exe") { 68 | sources = [ "demo.cc" ] 69 | 70 | deps = [ "//base" ] 71 | } 72 | -------------------------------------------------------------------------------- /common/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_COMMON_UTILS_H 2 | #define DEMO_COMMON_UTILS_H 3 | 4 | #include "base/base_paths.h" 5 | #include "base/command_line.h" 6 | #include "base/files/file.h" 7 | #include "base/files/file_path.h" 8 | #include "base/logging.h" 9 | #include "base/memory/ref_counted_memory.h" 10 | #include "base/strings/sys_string_conversions.h" 11 | #include "base/threading/thread.h" 12 | #include "base/trace_event/trace_buffer.h" 13 | 14 | namespace demo { 15 | 16 | std::unique_ptr& trace_file() { 17 | static std::unique_ptr g_trace_file; 18 | return g_trace_file; 19 | } 20 | 21 | void InitTrace(const std::string& file) { 22 | #if defined(OS_WIN) 23 | trace_file() = std::make_unique( 24 | base::FilePath(base::SysUTF8ToWide(file)), base::File::FLAG_OPEN_ALWAYS | 25 | base::File::FLAG_WRITE); 26 | #else 27 | trace_file() = std::make_unique( 28 | base::FilePath(file), base::File::FLAG_OPEN_ALWAYS | 29 | base::File::FLAG_WRITE | 30 | base::File::FLAG_OPEN_TRUNCATED); 31 | #endif 32 | DCHECK(trace_file()->IsValid()); 33 | trace_file()->WriteAtCurrentPos("[", 1); 34 | DLOG(INFO) << "Init trace file: " << file; 35 | } 36 | 37 | void StartTrace(const std::string& categories = "",base::trace_event::TraceRecordMode mode = base::trace_event::RECORD_AS_MUCH_AS_POSSIBLE) { 38 | DLOG(INFO) << "Start trace: " << categories; 39 | static std::string categories_; 40 | if (!categories.empty()) 41 | categories_ = categories; 42 | // 配置及启动 Trace 43 | base::trace_event::TraceConfig trace_config = 44 | base::trace_event::TraceConfig(categories_,mode); 45 | base::trace_event::TraceLog::GetInstance()->SetEnabled( 46 | trace_config, base::trace_event::TraceLog::RECORDING_MODE); 47 | } 48 | 49 | void FlushTrace(base::RepeatingClosure quit_closure) { 50 | DLOG(INFO) << "Flush trace begin."; 51 | 52 | base::trace_event::TraceLog::GetInstance()->SetDisabled(); 53 | base::trace_event::TraceLog::GetInstance()->Flush(base::BindRepeating( 54 | [](base::OnceClosure quit_closure, 55 | const scoped_refptr& events_str, 56 | bool has_more_events) { 57 | // LOG(INFO) << std::endl << events_str->data(); 58 | trace_file()->WriteAtCurrentPos(events_str->data().c_str(), 59 | events_str->size()); 60 | trace_file()->WriteAtCurrentPos(",\n", 2); 61 | if (!has_more_events) { 62 | trace_file()->WriteAtCurrentPos("\n", 1); 63 | trace_file()->Flush(); 64 | DLOG(INFO) << "Flush trace end."; 65 | if (quit_closure) 66 | std::move(quit_closure).Run(); 67 | } 68 | }, 69 | std::move(quit_closure))); 70 | } 71 | 72 | } // namespace demo 73 | 74 | #endif // !DEMO_COMMON_UTILS_H 75 | -------------------------------------------------------------------------------- /demo.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 迁移说明: 3 | * ------- 4 | * 80 -> 91: 5 | * - base::MessageLoop 被移除,使用 base::SingleThreadTaskExecutor 代替,详见 6 | * https://bugs.chromium.org/p/chromium/issues/detail?id=891670&q=891670&can=2 7 | * 8 | */ 9 | 10 | #include "base/at_exit.h" 11 | #include "base/command_line.h" 12 | #include "base/logging.h" 13 | #include "base/run_loop.h" 14 | #include "base/task/single_thread_task_executor.h" 15 | #include "base/task/thread_pool/thread_pool_instance.h" 16 | 17 | /** 18 | * 这个项目是个基础的入门demo,关于消息循环如果现在不明白可以先不用关注它,后面的 19 | * demo_task_executor 会专门演示它。 20 | */ 21 | int main(int argc, char** argv) { 22 | // 类似C++的 atexit() 方法,用于管理程序的销毁逻辑,base::Singleton类依赖它 23 | base::AtExitManager at_exit; 24 | // 初始化CommandLine 25 | base::CommandLine::Init(argc, argv); 26 | // 设置日志格式 27 | logging::SetLogItems(true,false,true,false); 28 | 29 | // 创建消息循环,旧版本的 MessageLoop 被换成了 SingleThreadTaskExecutor 30 | // 详见 commit 636e705be41ed9e7f50cdb13ceb5a9af5e3f4e5c 31 | base::SingleThreadTaskExecutor main_thread_task_executor; 32 | 33 | // 初始化线程池,会创建新的线程,在新的线程中会创建新消息循环MessageLoop 34 | base::ThreadPoolInstance::CreateAndStartWithDefaultParams("Demo"); 35 | 36 | // 复制当前文件来创建新的demo 37 | LOG(INFO) << "hello,world!"; 38 | 39 | LOG(INFO) << "running..."; 40 | base::RunLoop().Run(); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /demo_android/BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | group("demo_android") { 3 | testonly = true 4 | if(is_android) { 5 | deps = [ 6 | "demo_apk", 7 | "demo_android_skia", 8 | ] 9 | } else { 10 | print("demo_apk only support android.") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /demo_android/demo_android_skia/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /demo_android/demo_android_skia/BUILD.gn: -------------------------------------------------------------------------------- 1 | import("//build/config/android/config.gni") 2 | import("//build/config/android/rules.gni") 3 | #import("//third_party/icu/config.gni") 4 | 5 | android_resources("demo_android_skia_resources") { 6 | testonly = true 7 | sources = [ 8 | "res/layout/main_activity.xml", 9 | "res/mipmap-hdpi/app_icon.png", 10 | "res/values/strings.xml", 11 | ] 12 | custom_package = "org.demo.demo_android_skia" 13 | } 14 | 15 | # 从Java类生成JNI接口,用于让C++和JAVA可以互相调用 16 | # 详见文档://base/android/jni_generator/README.md 17 | generate_jni("demo_android_skia_jni_headers") { 18 | sources = [ 19 | "src/org/demo/demo_jni/SkiaCanvas.java", 20 | ] 21 | } 22 | 23 | android_library("demo_android_skia_java") { 24 | testonly = true 25 | 26 | #srcjar_deps = [ ":demo_javatests_aidl" ] 27 | 28 | deps = [ 29 | #":demo_android_skia_manifest", 30 | ":demo_android_skia_resources", 31 | ":demo_android_skia_jni_headers", 32 | "//base:base_java", 33 | "//base:jni_java", 34 | #"//ui/android:ui_java", 35 | ] 36 | 37 | sources = [ 38 | "src/org/demo/demo_android_skia/DemoAndroidSkiaActivity.java", 39 | "src/org/demo/demo_android_skia/DemoAndroidSkiaApplication.java", 40 | "src/org/demo/demo_jni/SkiaCanvas.java", 41 | ] 42 | 43 | #android_manifest_for_lint = demo_android_skia_manifest 44 | annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] 45 | } 46 | 47 | # native 动态库,实现JNI接口 48 | shared_library("libdemo_android_skia") { 49 | testonly = true 50 | sources = [ 51 | "cpp/demo_android_skia_library_loader.cc", 52 | "cpp/skia_canvas.cc", 53 | "cpp/skia_canvas.h", 54 | "cpp/skia_canvas_software.cc", 55 | "cpp/skia_canvas_software.h", 56 | "cpp/skia_canvas_gl.cc", 57 | "cpp/skia_canvas_gl.h", 58 | ] 59 | deps = [ 60 | ":demo_android_skia_jni_headers", 61 | "//base", 62 | # 直接依赖它会导致和chromium中的变量定义冲突 63 | #"//third_party/skia", 64 | "//skia", 65 | ] 66 | 67 | defines = ["GR_TEST_UTILS=1"] 68 | 69 | libs = ["EGL","GLESv2"] 70 | 71 | configs -= [ "//build/config/android:hide_all_but_jni_onload" ] 72 | configs += [ "//build/config/android:hide_all_but_jni" ] 73 | } 74 | 75 | # 定义生成apk的target,详见://build/config/android/rules.gni 76 | android_apk("demo_android_skia") { 77 | testonly = true 78 | apk_name = "DemoAndroidSkia" 79 | android_manifest = "AndroidManifest.xml" 80 | #android_manifest_dep = ":demo_android_skia_manifest" 81 | shared_libraries = [ ":libdemo_android_skia" ] 82 | #loadable_modules = [ "$root_out_dir/libchrome_crashpad_handler.so" ] 83 | command_line_flags_file = "demo-apk-command-line" 84 | 85 | # 默认的 min 和 target 分别为 19,23,这里修改是为了去除在21:9的屏幕上的黑边 86 | min_sdk_version = 23 87 | target_sdk_version = 26 88 | 89 | deps = [ 90 | ":demo_android_skia_java", 91 | "//base:base_java", 92 | "//base:base_java_test_support", 93 | #"//ui/android:ui_java", 94 | ] 95 | } 96 | -------------------------------------------------------------------------------- /demo_android/demo_android_skia/README.md: -------------------------------------------------------------------------------- 1 | # demo_android_skia 2 | 3 | 这个 demo 用于演示在 Android 中使用 skia 进行绘图,主要用来演示使用 skia 进行软件渲染和硬件渲染的性能差异,顺便演示 chromium 的渲染和 android 对接的方式。 4 | 5 | 在 demo 中主要演示了划线的功能,对比 chromium 中 canvas 的划线,这里演示的方法应该是 canvas 划线的性能上限,可以用来评估 chromium 渲染引入的性能损失情况。 6 | 7 | - [gapid_opengles_trace.gfxtrace](./gapid_opengles_trace.gfxtrace) 是通过 [gapid](https://github.com/google/gapid) 抓到的 OpenGLES API 的调用数据。 8 | - [systrace_data.zip](./systrace_data.zip) 是通过 [systrace](https://developer.android.com/topic/performance/tracing/command-line#app-trace) 抓到的 trace 数据,解压后可以使用浏览器直接打开。 9 | -------------------------------------------------------------------------------- /demo_android/demo_android_skia/cpp/demo_android_skia_library_loader.cc: -------------------------------------------------------------------------------- 1 | #include "base/android/jni_android.h" 2 | // #include "content/public/app/content_jni_onload.h" 3 | // #include "content/public/app/content_main.h" 4 | 5 | #include "base/android/base_jni_onload.h" 6 | #include "base/logging.h" 7 | 8 | //#include "demo/demo_shell/app/demo_shell_content_main_delegate.h" 9 | 10 | JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { 11 | DLOG(INFO) << "[demo_android_skia] JNI_OnLoad start"; 12 | // 这个初始化是必要的,因为LibraryLoader依赖它,大量的base::android::*都依赖它 13 | // 它其实就是将vm保存为了内部的全局变量 14 | base::android::InitVM(vm); 15 | // 下面这个初始化在这个程序中不是必须的,但是推荐加上,主要是初始化了ClassLoader 16 | if (!base::android::OnJNIOnLoadInit()) 17 | return false; 18 | 19 | // 我们没有使用(crazy linker)动态注册JNI函数的方式,所以这里不需要以下代码 20 | // if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env)) { 21 | // return -1; 22 | // } 23 | 24 | DLOG(INFO) << "[demo_android_skia] JNI_OnLoad finished"; 25 | return JNI_VERSION_1_4; 26 | } 27 | -------------------------------------------------------------------------------- /demo_android/demo_android_skia/cpp/skia_canvas.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_DEMO_ANDROID_SKIA_CANVAS_H 2 | #define DEMO_DEMO_ANDROID_SKIA_CANVAS_H 3 | 4 | #include 5 | 6 | #include "android/native_window_jni.h" 7 | #include "base/android/jni_android.h" 8 | #include "base/android/scoped_java_ref.h" 9 | #include "base/threading/thread.h" 10 | #include "base/sequenced_task_runner.h" 11 | 12 | #include "third_party/skia/include/core/SkBitmap.h" 13 | #include "third_party/skia/include/core/SkCanvas.h" 14 | #include "third_party/skia/include/core/SkPath.h" 15 | #include "third_party/skia/include/core/SkImageInfo.h" 16 | #include "third_party/skia/include/core/SkSurface.h" 17 | 18 | #include "base/timer/timer.h" 19 | 20 | namespace demo_jni { 21 | 22 | class SkiaCanvas { 23 | public: 24 | void OnTouch(JNIEnv* env, int action, jfloat x, jfloat y); 25 | 26 | protected: 27 | SkiaCanvas(JNIEnv* env, 28 | const base::android::JavaParamRef& caller, 29 | const base::android::JavaParamRef& surface); 30 | virtual void InitializeOnRenderThread(); 31 | virtual SkCanvas* BeginPaint() = 0; 32 | virtual void OnPaint(SkCanvas* canvas) {} 33 | virtual void SwapBuffer() = 0; 34 | void SetNeedsRedraw(bool need_redraw); 35 | void ShowInfo(std::string info); 36 | 37 | const base::android::ScopedJavaGlobalRef caller_; 38 | // SurfaceView 对应的 Window 39 | ANativeWindow* nativeWindow_; 40 | int width_; 41 | int height_; 42 | 43 | sk_sp skSurface_ = nullptr; 44 | SkPaint pathPaint_; 45 | SkPaint circlePaint_; 46 | SkPath skPath_; 47 | SkScalar strokeWidth_ = 5.f; 48 | SkColor background_ = SK_ColorBLACK; 49 | std::string tag_; 50 | bool need_redraw_ = false; 51 | bool is_drawing_ = false; 52 | base::TimeDelta total_frame_time_; 53 | base::TimeTicks last_frame_time_; 54 | unsigned int frame_count_ = 0; 55 | base::TimeDelta total_paint_time_; 56 | base::TimeDelta total_swap_time_; 57 | 58 | unsigned int touch_count_ = 0; 59 | base::TimeTicks touch_start_time_; 60 | base::TimeDelta total_touch_time_; 61 | 62 | private: 63 | void OnTouchOnRenderThread(int action, jfloat x, jfloat y); 64 | void OnRenderOnRenderThread(); 65 | void ShowFrameRateOnRenderThread(); 66 | base::Thread render_thread_; 67 | scoped_refptr render_task_runner_; 68 | base::RepeatingTimer timer_; 69 | base::RepeatingClosure render_closure_; 70 | base::WeakPtrFactory weak_factory_{this}; 71 | }; 72 | 73 | } // namespace demo_jni 74 | 75 | #endif // DEMO_DEMO_ANDROID_SKIA_CANVAS_H -------------------------------------------------------------------------------- /demo_android/demo_android_skia/cpp/skia_canvas_gl.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_DEMO_ANDROID_SKIA_CANVAS_GL_H 2 | #define DEMO_DEMO_ANDROID_SKIA_CANVAS_GL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #ifndef GL_GLEXT_PROTOTYPES 9 | #define GL_GLEXT_PROTOTYPES 10 | #endif 11 | #include 12 | 13 | #include "base/android/jni_android.h" 14 | #include "base/android/scoped_java_ref.h" 15 | 16 | #include "android/native_window_jni.h" 17 | 18 | #include "demo/demo_android/demo_android_skia/cpp/skia_canvas.h" 19 | 20 | #include "third_party/skia/include/gpu/GrContext.h" 21 | #include "third_party/skia/include/gpu/GrContextOptions.h" 22 | #include "third_party/skia/include/gpu/gl/GrGLInterface.h" 23 | #include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h" 24 | 25 | namespace demo_jni { 26 | 27 | class SkiaCanvasGL : public SkiaCanvas { 28 | public: 29 | SkiaCanvasGL(JNIEnv* env, 30 | const base::android::JavaParamRef& caller, 31 | const base::android::JavaParamRef& surface); 32 | 33 | private: 34 | void InitializeOnRenderThread() override; 35 | SkCanvas* BeginPaint() override; 36 | void OnPaint(SkCanvas* canvas) override; 37 | void SwapBuffer() override; 38 | 39 | EGLDisplay display_; 40 | EGLContext context_; 41 | EGLSurface surface_; 42 | EGLint stencilBits_; 43 | EGLint sampleCount_; 44 | sk_sp grGLInterface_; 45 | sk_sp grContext_; 46 | bool use_ddl_ = false; 47 | std::unique_ptr recorder_; 48 | }; 49 | 50 | } // namespace demo_jni 51 | 52 | #endif // DEMO_DEMO_ANDROID_SKIA_CANVAS_GL_H -------------------------------------------------------------------------------- /demo_android/demo_android_skia/cpp/skia_canvas_software.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "demo/demo_android/demo_android_skia/cpp/skia_canvas_software.h" 3 | 4 | #include "base/android/jni_android.h" 5 | #include "base/android/jni_string.h" 6 | #include "base/android/scoped_java_ref.h" 7 | #include "base/bind.h" 8 | #include "base/lazy_instance.h" 9 | 10 | namespace demo_jni { 11 | 12 | SkiaCanvasSoftware::SkiaCanvasSoftware( 13 | JNIEnv* env, 14 | const base::android::JavaParamRef& caller, 15 | const base::android::JavaParamRef& jsurface) 16 | : SkiaCanvas(env, caller, jsurface) { 17 | background_ = 0xFF00DE96; 18 | tag_ = "SkiaCanvasSoftware"; 19 | } 20 | 21 | void SkiaCanvasSoftware::InitializeOnRenderThread() { 22 | 23 | ANativeWindow_setBuffersGeometry(nativeWindow_, width_, height_, 24 | WINDOW_FORMAT_RGB_565); 25 | 26 | // 当 format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4 27 | // 时,一个像素占2个字节,所以x2 28 | // memset(buffer.bits, 0xAA, buffer.stride * buffer.height * 2); 29 | 30 | auto canvas = BeginPaint(); 31 | canvas->clear(background_); 32 | //canvas->drawCircle(20, 20, 20, circlePaint_); 33 | SwapBuffer(); 34 | SkiaCanvas::InitializeOnRenderThread(); 35 | } 36 | 37 | SkCanvas* SkiaCanvasSoftware::BeginPaint() { 38 | ANativeWindow_Buffer buffer; 39 | DCHECK(ANativeWindow_lock(nativeWindow_, &buffer, &dirtyRect_)==0); 40 | SkImageInfo info = SkImageInfo::Make(width_, height_, kRGB_565_SkColorType, 41 | kPremul_SkAlphaType, nullptr); 42 | skSurface_ = SkSurface::MakeRasterDirect(info, buffer.bits, buffer.stride * 2, 43 | nullptr); 44 | return skSurface_->getCanvas(); 45 | } 46 | 47 | void SkiaCanvasSoftware::OnPaint(SkCanvas* canvas) { 48 | skSurface_->flush(); 49 | } 50 | 51 | void SkiaCanvasSoftware::SwapBuffer() { 52 | ANativeWindow_unlockAndPost(nativeWindow_); 53 | } 54 | 55 | } // namespace demo_jni -------------------------------------------------------------------------------- /demo_android/demo_android_skia/cpp/skia_canvas_software.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_DEMO_ANDROID_SKIA_CANVAS_SOFTWARE_H 2 | #define DEMO_DEMO_ANDROID_SKIA_CANVAS_SOFTWARE_H 3 | 4 | #include 5 | 6 | #include "base/android/jni_android.h" 7 | #include "base/android/scoped_java_ref.h" 8 | 9 | #include "android/native_window_jni.h" 10 | 11 | #include "demo/demo_android/demo_android_skia/cpp/skia_canvas.h" 12 | 13 | namespace demo_jni { 14 | 15 | class SkiaCanvasSoftware : public SkiaCanvas { 16 | public: 17 | SkiaCanvasSoftware(JNIEnv* env, 18 | const base::android::JavaParamRef& caller, 19 | const base::android::JavaParamRef& surface); 20 | void InitializeOnRenderThread() override; 21 | void OnPaint(SkCanvas* canvas) override; 22 | 23 | private: 24 | SkCanvas* BeginPaint() override; 25 | void SwapBuffer() override; 26 | 27 | ARect dirtyRect_; 28 | }; 29 | 30 | } // namespace demo_jni 31 | 32 | #endif // DEMO_DEMO_ANDROID_SKIA_CANVAS_SOFTWARE_H -------------------------------------------------------------------------------- /demo_android/demo_android_skia/cpp/trace_android.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_DEMO_ANDROID_DEMO_ANDROID_SKIA_CPP_TRACE_ANDROID_H 2 | #define DEMO_DEMO_ANDROID_DEMO_ANDROID_SKIA_CPP_TRACE_ANDROID_H 3 | 4 | #include 5 | #include 6 | #include "base/logging.h" 7 | 8 | namespace demo_jni { 9 | 10 | namespace { 11 | void* (*ATrace_beginSection)(const char* sectionName); 12 | void* (*ATrace_endSection)(void); 13 | } // namespace 14 | 15 | #define ATRACE_NAME(name) ScopedTrace ___tracer(name) 16 | 17 | // ATRACE_CALL is an ATRACE_NAME that uses the current function name. 18 | #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) 19 | 20 | class ScopedTrace { 21 | public: 22 | typedef void* (*fp_ATrace_beginSection)(const char* sectionName); 23 | typedef void* (*fp_ATrace_endSection)(void); 24 | 25 | static bool Initialize() { 26 | // Retrieve a handle to libandroid. 27 | void* lib = dlopen("libandroid.so", RTLD_NOW); 28 | DCHECK(lib); 29 | // Access the native tracing functions. 30 | if (lib != nullptr) { 31 | // Use dlsym() to prevent crashes on devices running Android 5.1 32 | // (API level 22) or lower. 33 | ATrace_beginSection = reinterpret_cast( 34 | dlsym(lib, "ATrace_beginSection")); 35 | ATrace_endSection = reinterpret_cast( 36 | dlsym(lib, "ATrace_endSection")); 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | inline ScopedTrace(const char* name) { ATrace_beginSection(name); } 43 | 44 | inline ~ScopedTrace() { ATrace_endSection(); } 45 | }; 46 | 47 | } // namespace demo_jni 48 | 49 | #endif // !DEMO_DEMO_ANDROID_DEMO_ANDROID_SKIA_CPP_TRACE_ANDROID_H -------------------------------------------------------------------------------- /demo_android/demo_android_skia/gapid_opengles_trace.gfxtrace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_android/demo_android_skia/gapid_opengles_trace.gfxtrace -------------------------------------------------------------------------------- /demo_android/demo_android_skia/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 16 | 25 | 36 | 43 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /demo_android/demo_android_skia/res/mipmap-hdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_android/demo_android_skia/res/mipmap-hdpi/app_icon.png -------------------------------------------------------------------------------- /demo_android/demo_android_skia/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 上面的色块使用Skia的软件渲染。\n下面的色块使用Skia的OpenGLES硬件渲染。 4 | Hello,DemoAndroidSkia! 5 | -------------------------------------------------------------------------------- /demo_android/demo_android_skia/src/org/demo/demo_android_skia/DemoAndroidSkiaApplication.java: -------------------------------------------------------------------------------- 1 | // Copyright 2012 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 | package org.demo.demo_android_skia; 6 | 7 | import android.app.Application; 8 | import android.content.Context; 9 | import android.view.Display; 10 | import android.view.WindowManager; 11 | import android.util.Log; 12 | import android.view.Choreographer; 13 | 14 | import java.lang.reflect.Field; 15 | import java.lang.reflect.Modifier; 16 | 17 | import org.chromium.base.ApplicationStatus; 18 | import org.chromium.base.BuildConfig; 19 | import org.chromium.base.CommandLine; 20 | import org.chromium.base.ContextUtils; 21 | import org.chromium.base.PathUtils; 22 | import org.chromium.base.multidex.ChromiumMultiDexInstaller; 23 | 24 | /** 25 | * Entry point for the demo apk application. Handles initialization of 26 | * information that needs to be shared across the main activity and the child 27 | * services created. 28 | */ 29 | public class DemoAndroidSkiaApplication extends Application { 30 | public static final String COMMAND_LINE_FILE = "/data/local/tmp/demo-apk-command-line"; 31 | private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "demo_android_skia"; 32 | private static final String TAG = "DemoAndroidSkiaApplication"; 33 | 34 | public DemoAndroidSkiaApplication() { 35 | try { 36 | setFinalStatic(Choreographer.class.getDeclaredField("USE_VSYNC"), false); 37 | 38 | } catch (Exception e) { 39 | Log.e(TAG,e.toString()); 40 | } 41 | } 42 | 43 | @Override 44 | protected void attachBaseContext(Context base) { 45 | super.attachBaseContext(base); 46 | // SystemProperties.getBoolean("debug.choreographer.vsync"); 47 | boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":"); 48 | ContextUtils.initApplicationContext(this); 49 | if (isBrowserProcess) { 50 | if (BuildConfig.IS_MULTIDEX_ENABLED) { 51 | ChromiumMultiDexInstaller.install(this); 52 | } 53 | PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); 54 | ApplicationStatus.initialize(this); 55 | } 56 | 57 | Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 58 | float refreshRating = display.getRefreshRate(); 59 | Log.e(TAG, "Refresh Rating: " + refreshRating); 60 | } 61 | 62 | public void initCommandLine() { 63 | if (!CommandLine.isInitialized()) { 64 | CommandLine.initFromFile(COMMAND_LINE_FILE); 65 | } 66 | } 67 | 68 | static void setFinalStatic(Field field, Object newValue) throws Exception { 69 | field.setAccessible(true); 70 | 71 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 72 | modifiersField.setAccessible(true); 73 | modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 74 | 75 | field.set(null, newValue); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /demo_android/demo_android_skia/src/org/demo/demo_jni/SkiaCanvas.java: -------------------------------------------------------------------------------- 1 | 2 | package org.demo.demo_jni; 3 | 4 | import android.util.Log; 5 | import android.view.Surface; 6 | 7 | import java.lang.String; 8 | 9 | import org.chromium.base.annotations.CalledByNative; 10 | import org.chromium.base.annotations.JNINamespace; 11 | import org.chromium.base.annotations.NativeMethods; 12 | 13 | @JNINamespace("demo_jni") 14 | public class SkiaCanvas { 15 | 16 | public interface Callback { 17 | public void showInfo(String info); 18 | } 19 | 20 | private static final String TAG = "DemoAndroidSkia.SkiaCanvas"; 21 | private long mNativeSkiaCanvas; 22 | private Callback mCallback; 23 | 24 | public SkiaCanvas(Surface surface,Callback callback, boolean useGL) { 25 | mCallback = callback; 26 | mNativeSkiaCanvas = SkiaCanvasJni.get().init(this, surface, useGL); 27 | } 28 | 29 | public void onTouch(int action,float x,float y){ 30 | SkiaCanvasJni.get().onTouch(mNativeSkiaCanvas, action, x, y); 31 | } 32 | 33 | @CalledByNative 34 | public void showInfo(String info) { 35 | Log.i(TAG, "info: " + info); 36 | mCallback.showInfo(info); 37 | } 38 | 39 | // 固定格式,用于定义并生成JNI接口 40 | @NativeMethods 41 | public interface Natives { 42 | // 初始化,传入Java的this,返回C++的this 43 | long init(SkiaCanvas caller, Surface surface, boolean useGL); 44 | 45 | void onTouch(long nativeSkiaCanvas,int action, float x, float y); 46 | } 47 | } -------------------------------------------------------------------------------- /demo_android/demo_android_skia/systrace_data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_android/demo_android_skia/systrace_data.zip -------------------------------------------------------------------------------- /demo_android/demo_apk/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /demo_android/demo_apk/BUILD.gn: -------------------------------------------------------------------------------- 1 | import("//build/config/android/config.gni") 2 | import("//build/config/android/rules.gni") 3 | import("//third_party/icu/config.gni") 4 | 5 | # 可以使用 jinja 模板来生成 Manifest 6 | # 这里不使用jinja模板,直接像普通的Android一样提前写好 7 | # demo_apk_manifest = "$target_gen_dir/demo_apk_manifest_jinja/AndroidManifest.xml" 8 | # jinja_template("demo_apk_manifest") { 9 | # testonly = true 10 | # input = "AndroidManifest.xml.jinja2" 11 | # output = demo_apk_manifest 12 | # variables = [ "manifest_package=org.chromium.demo_apk" ] 13 | # } 14 | 15 | android_resources("demo_apk_resources") { 16 | testonly = true 17 | sources = [ 18 | "res/layout/demo_apk_activity.xml", 19 | "res/mipmap-hdpi/app_icon.png", 20 | "res/values/strings.xml", 21 | ] 22 | custom_package = "org.chromium.demo_apk" 23 | } 24 | 25 | # 从Java类生成JNI接口,用于让C++和JAVA可以互相调用 26 | # 详见文档://base/android/jni_generator/README.md 27 | generate_jni("demo_apk_jni_headers") { 28 | sources = [ 29 | "src/org/chromium/demo_jni/DemoFoo.java", 30 | ] 31 | } 32 | 33 | android_library("demo_apk_java") { 34 | testonly = true 35 | 36 | #srcjar_deps = [ ":demo_javatests_aidl" ] 37 | 38 | deps = [ 39 | #":demo_apk_manifest", 40 | ":demo_apk_resources", 41 | ":demo_apk_jni_headers", 42 | "//base:base_java", 43 | "//base:jni_java", 44 | "//ui/android:ui_java", 45 | ] 46 | 47 | sources = [ 48 | "src/org/chromium/demo_apk/DemoApkActivity.java", 49 | "src/org/chromium/demo_apk/DemoApkApplication.java", 50 | "src/org/chromium/demo_jni/DemoFoo.java", 51 | ] 52 | 53 | #android_manifest_for_lint = demo_apk_manifest 54 | annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] 55 | } 56 | 57 | # native 动态库,实现JNI接口 58 | shared_library("libdemo_apk") { 59 | testonly = true 60 | sources = [ 61 | "cpp/demo_apk_library_loader.cc", 62 | "cpp/demo_foo.cc", 63 | "cpp/demo_foo.h", 64 | ] 65 | deps = [ 66 | ":demo_apk_jni_headers", 67 | "//base", 68 | ] 69 | 70 | configs -= [ "//build/config/android:hide_all_but_jni_onload" ] 71 | configs += [ "//build/config/android:hide_all_but_jni" ] 72 | } 73 | 74 | # 定义生成apk的target,详见://build/config/android/rules.gni 75 | android_apk("demo_apk") { 76 | testonly = true 77 | apk_name = "DemoApk" 78 | android_manifest = "AndroidManifest.xml" 79 | #android_manifest_dep = ":demo_apk_manifest" 80 | shared_libraries = [ ":libdemo_apk" ] 81 | #loadable_modules = [ "$root_out_dir/libchrome_crashpad_handler.so" ] 82 | command_line_flags_file = "demo-apk-command-line" 83 | 84 | # 默认的 min 和 target 分别为 19,23,这里修改是为了去除在21:9的屏幕上的黑边 85 | min_sdk_version = 23 86 | target_sdk_version = 26 87 | 88 | deps = [ 89 | ":demo_apk_java", 90 | "//base:base_java", 91 | "//base:base_java_test_support", 92 | "//ui/android:ui_java", 93 | ] 94 | } 95 | -------------------------------------------------------------------------------- /demo_android/demo_apk/README.md: -------------------------------------------------------------------------------- 1 | # demo_apk 2 | 3 | `demo_apk` 可以构建出一名为`DemoApk.apk`的Android应用,它和普通的Android应用最大的不同就是构建方式。一般的Android开发者使用AndroidStudio等IDE来构建Android应用,在chromium中不使用这些IDE而使用gn。 4 | 5 | chromium提供了一套gn配置用来打包各种Android组件,包括 apk,aar,jar 等。主要的脚本位于`//build/config/android/`目录下。可以重点查看以下两个文件: 6 | 7 | ```gn 8 | //build/config/android/config.gni 9 | //build/config/android/rules.gni 10 | ``` 11 | 12 | ## demo_apk 构成 13 | 14 | demo_apk 由以下几部分组成: 15 | 16 | 1. `AndroidManifest.xml`:Android应用的描述文件,包括权限定义,icon等; 17 | 2. `res`: Android应用的资源文件,包括UI布局,图片,字符串等; 18 | 3. `src`: 源代码文件; 19 | 4. `cpp`: 保存 JNI 相关代码; 20 | 21 | ## JNI 22 | 23 | gn提供了从java代码生成JNI/C++头文件的脚本,具体信息参考`base/android/jni_generator/README.md`。 -------------------------------------------------------------------------------- /demo_android/demo_apk/cpp/demo_apk_library_loader.cc: -------------------------------------------------------------------------------- 1 | #include "base/android/jni_android.h" 2 | // #include "content/public/app/content_jni_onload.h" 3 | // #include "content/public/app/content_main.h" 4 | 5 | #include "base/android/base_jni_onload.h" 6 | #include "base/logging.h" 7 | 8 | //#include "demo/demo_shell/app/demo_shell_content_main_delegate.h" 9 | 10 | JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { 11 | DLOG(INFO) << "[demo_apk] JNI_OnLoad start"; 12 | // 这个初始化是必要的,因为LibraryLoader依赖它,大量的base::android::*都依赖它 13 | // 它其实就是将vm保存为了内部的全局变量 14 | base::android::InitVM(vm); 15 | // 下面这个初始化在这个程序中不是必须的,但是推荐加上,主要是初始化了ClassLoader 16 | if (!base::android::OnJNIOnLoadInit()) 17 | return false; 18 | 19 | // 我们没有使用(crazy linker)动态注册JNI函数的方式,所以这里不需要以下代码 20 | // if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env)) { 21 | // return -1; 22 | // } 23 | 24 | DLOG(INFO) << "[demo_apk] JNI_OnLoad finished"; 25 | return JNI_VERSION_1_4; 26 | } 27 | -------------------------------------------------------------------------------- /demo_android/demo_apk/cpp/demo_foo.cc: -------------------------------------------------------------------------------- 1 | #include "demo/demo_android/demo_apk/cpp/demo_foo.h" 2 | 3 | #include "base/android/jni_android.h" 4 | #include "base/android/jni_string.h" 5 | #include "base/android/scoped_java_ref.h" 6 | #include "base/bind.h" 7 | #include "base/lazy_instance.h" 8 | 9 | #include "demo/demo_android/demo_apk/demo_apk_jni_headers/DemoFoo_jni.h" 10 | 11 | namespace demo_jni { 12 | 13 | base::android::ScopedJavaGlobalRef j_demo_foo; 14 | 15 | void DemoFoo::HelloDemoFoo(JNIEnv* env, const base::android::JavaParamRef& who) { 16 | LOG(INFO)<<"[demo_foo] DemoFoo::HelloDemoFoo: Hello," << base::android::ConvertJavaStringToUTF8(env, who); 17 | } 18 | 19 | static jlong JNI_DemoFoo_Init(JNIEnv* env, const base::android::JavaParamRef& caller) { 20 | DLOG(INFO) << "[demo_apk]================ JNI_DemoFoo_Init"; 21 | j_demo_foo.Reset(caller); 22 | return reinterpret_cast(new DemoFoo()); 23 | } 24 | 25 | static void JNI_DemoFoo_Hello(JNIEnv* env, const base::android::JavaParamRef& who) { 26 | LOG(INFO)<<"[demo_foo] JNI_DemoFoo_Hello: Hello,"< 5 | 6 | #include "base/android/jni_android.h" 7 | #include "base/android/scoped_java_ref.h" 8 | 9 | namespace demo_jni { 10 | 11 | class DemoFoo { 12 | public: 13 | void HelloDemoFoo(JNIEnv* env, const base::android::JavaParamRef& who); 14 | }; 15 | 16 | void Hi(std::string who); 17 | void HiStatic(std::string who); 18 | } 19 | 20 | #endif //DEMO_DEMO_ANDROID_DEMO_FOO_H -------------------------------------------------------------------------------- /demo_android/demo_apk/res/layout/demo_apk_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 16 | 25 | 26 | -------------------------------------------------------------------------------- /demo_android/demo_apk/res/mipmap-hdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_android/demo_apk/res/mipmap-hdpi/app_icon.png -------------------------------------------------------------------------------- /demo_android/demo_apk/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello,DemoApk! 4 | -------------------------------------------------------------------------------- /demo_android/demo_apk/src/org/chromium/demo_apk/DemoApkActivity.java: -------------------------------------------------------------------------------- 1 | // Copyright 2012 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 | package org.chromium.demo_apk; 6 | 7 | import android.app.Activity; 8 | import android.content.Intent; 9 | import android.os.Bundle; 10 | import android.util.Log; 11 | import android.view.View; 12 | 13 | import org.chromium.base.CommandLine; 14 | import org.chromium.base.library_loader.LibraryLoader; 15 | import org.chromium.base.library_loader.LibraryProcessType; 16 | 17 | import org.chromium.demo_jni.DemoFoo; 18 | 19 | /** 20 | * Activity for managing the Demo shell. 21 | */ 22 | public class DemoApkActivity extends Activity { 23 | 24 | private static final String TAG = "DemoApk.DemoApkActivity"; 25 | 26 | public static final String COMMAND_LINE_ARGS_KEY = "commandLineArgs"; 27 | 28 | @Override 29 | protected void onCreate(final Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | 32 | // Initializing the command line must occur before loading the library. 33 | if (!CommandLine.isInitialized()) { 34 | ((DemoApkApplication) getApplication()).initCommandLine(); 35 | String[] commandLineParams = getCommandLineParamsFromIntent(getIntent()); 36 | if (commandLineParams != null) { 37 | CommandLine.getInstance().appendSwitchesAndArguments(commandLineParams); 38 | } 39 | } 40 | 41 | setContentView(R.layout.demo_apk_activity); 42 | } 43 | 44 | private static String[] getCommandLineParamsFromIntent(Intent intent) { 45 | return intent != null ? intent.getStringArrayExtra(COMMAND_LINE_ARGS_KEY) : null; 46 | } 47 | 48 | public void onClick(View view) { 49 | Log.i(TAG,"Call onClick"); 50 | 51 | // 加载JNI库 52 | LibraryLoader.getInstance().ensureInitialized(LibraryProcessType.PROCESS_BROWSER); 53 | 54 | DemoFoo foo = new DemoFoo(); 55 | foo.Hello("JNI"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /demo_android/demo_apk/src/org/chromium/demo_apk/DemoApkApplication.java: -------------------------------------------------------------------------------- 1 | // Copyright 2012 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 | package org.chromium.demo_apk; 6 | 7 | import android.app.Application; 8 | import android.content.Context; 9 | 10 | import org.chromium.base.ApplicationStatus; 11 | import org.chromium.base.BuildConfig; 12 | import org.chromium.base.CommandLine; 13 | import org.chromium.base.ContextUtils; 14 | import org.chromium.base.PathUtils; 15 | import org.chromium.base.multidex.ChromiumMultiDexInstaller; 16 | import org.chromium.ui.base.ResourceBundle; 17 | 18 | /** 19 | * Entry point for the demo apk application. Handles initialization of information that needs 20 | * to be shared across the main activity and the child services created. 21 | */ 22 | public class DemoApkApplication extends Application { 23 | public static final String COMMAND_LINE_FILE = "/data/local/tmp/demo-apk-command-line"; 24 | private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "demo_apk"; 25 | 26 | @Override 27 | protected void attachBaseContext(Context base) { 28 | super.attachBaseContext(base); 29 | boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":"); 30 | ContextUtils.initApplicationContext(this); 31 | ResourceBundle.setNoAvailableLocalePaks(); 32 | if (isBrowserProcess) { 33 | if (BuildConfig.IS_MULTIDEX_ENABLED) { 34 | ChromiumMultiDexInstaller.install(this); 35 | } 36 | PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); 37 | ApplicationStatus.initialize(this); 38 | } 39 | } 40 | 41 | public void initCommandLine() { 42 | if (!CommandLine.isInitialized()) { 43 | CommandLine.initFromFile(COMMAND_LINE_FILE); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /demo_android/demo_apk/src/org/chromium/demo_jni/DemoFoo.java: -------------------------------------------------------------------------------- 1 | 2 | package org.chromium.demo_jni; 3 | 4 | import android.util.Log; 5 | import java.lang.String; 6 | import org.chromium.base.annotations.CalledByNative; 7 | import org.chromium.base.annotations.JNINamespace; 8 | import org.chromium.base.annotations.NativeMethods; 9 | 10 | @JNINamespace("demo_jni") 11 | public class DemoFoo { 12 | 13 | private static final String TAG = "DemoApk.DemoFoo"; 14 | private long mNativeDemoFoo; 15 | 16 | public DemoFoo() { 17 | Log.i(TAG,"Call DemoFoo.ctor"); 18 | mNativeDemoFoo = DemoFooJni.get().init(this); 19 | } 20 | 21 | public void HelloDemoFoo(String who) { 22 | Log.i(TAG,"Call HelloDemoFoo"); 23 | DemoFoo.Natives foo = DemoFooJni.get(); 24 | foo.HelloDemoFoo(mNativeDemoFoo,who); 25 | } 26 | 27 | public void Hello(String who) { 28 | // DemoFooJni 是根据DemoFoo.Natives自动生成的类 29 | Log.i(TAG,"Call Hello"); 30 | DemoFooJni.get().Hello(who); 31 | } 32 | 33 | // C++和Java都可以调用该方法 34 | // 演示实例方法的使用 35 | @CalledByNative 36 | public void Hi(String who) { 37 | Log.i(TAG,"Hi,"+who); 38 | } 39 | 40 | // C++和Java都可以调用该方法 41 | // 演示static方法的使用 42 | @CalledByNative 43 | public static void HiStatic(String who) { 44 | Log.i(TAG,"Hi Static,"+who); 45 | } 46 | 47 | // 固定格式,用于定义并生成JNI接口 48 | @NativeMethods 49 | public interface Natives { 50 | // 初始化,传入Java的this,返回C++的this 51 | long init(DemoFoo caller); 52 | // 第一个参数以 native 开头,因此调用nativeDemoFoo对象的实例方法 53 | void HelloDemoFoo(long nativeDemoFoo,String who); 54 | // 第一个参数不是以 native 开头,因此调用全局方法 55 | void Hello(String who); 56 | 57 | } 58 | } -------------------------------------------------------------------------------- /demo_callback/BUILD.gn: -------------------------------------------------------------------------------- 1 | group("demo_callback"){ 2 | deps = [ 3 | ":demo_callback_once", 4 | ":demo_callback_repeating", 5 | ] 6 | } 7 | 8 | executable("demo_callback_once"){ 9 | sources =[ 10 | "demo_callback_once.cc" 11 | ] 12 | deps = [ 13 | "//base" 14 | ] 15 | } 16 | 17 | executable("demo_callback_repeating"){ 18 | sources =[ 19 | "demo_callback_repeating.cc" 20 | ] 21 | deps = [ 22 | "//base" 23 | ] 24 | } -------------------------------------------------------------------------------- /demo_callback/demo_callback_once.cc: -------------------------------------------------------------------------------- 1 | #include "base/logging.h" 2 | #include "base/run_loop.h" 3 | #include "base/task/single_thread_task_executor.h" 4 | 5 | // 1. 基本使用 使用函数的回调 6 | void SayHello(const std::string& name) { 7 | LOG(INFO) << "Hello " << name << "!"; 8 | } 9 | void BasicUsage() { 10 | // OnceCallback是一次性的回调,绑定处理函数对应BindOne 11 | base::OnceCallback callback = 12 | base::BindOnce(&SayHello); 13 | ; 14 | //使用时需要转移所有权,之后就不能再调用了 15 | std::move(callback).Run("Basic Usage"); 16 | } 17 | 18 | // 2. 使用类的方法 19 | class ClassUsage { 20 | public: 21 | ClassUsage() {} 22 | ~ClassUsage() {} 23 | 24 | void Run() { 25 | // 如果是调用当前类型内部的方法 26 | // 参数需要指定当前方法所在的类型实例 27 | // 这样除了指定当前类型,也可以指定其他类型的方法作为回调函数 28 | // base::Unretained函数表示当前回调不持有引用 29 | base::OnceCallback callback = 30 | base::BindOnce(&ClassUsage::SayHello, base::Unretained(this)); 31 | 32 | std::move(callback).Run("ClassUsage"); 33 | } 34 | 35 | private: 36 | void SayHello(const std::string& name) { 37 | LOG(INFO) << "Hello " << name << "!"; 38 | } 39 | }; 40 | 41 | // 使用Lambda表达式 42 | void LambdaUsage() { 43 | // Lambda 44 | base::OnceCallback callback = base::BindOnce( 45 | [](const std::string& name) { LOG(INFO) << "Hello " << name << "!"; }); 46 | 47 | std::move(callback).Run("LambdaUsage"); 48 | } 49 | 50 | // 更多的参数与与返回值 51 | void MoreParamsAndReturnUsage() { 52 | // 这里我们修改刚刚的模板 53 | // 在拥有返回值后,无论是函数,方法,还是lambda记得返回相同类型的返回值 54 | base::OnceCallback callback = 55 | base::BindOnce([](int a, int b) { return a + b; }); 56 | 57 | LOG(INFO) << "CallbackWithReturn " 58 | << "1+1=" << std::move(callback).Run(1, 1); 59 | } 60 | // Bind时捕获外部参数 61 | void BindWithOutterParamsUsage() { 62 | int power = 3; 63 | 64 | // 可以在BindOnce后面增加外部参数,额外增加的参数,在回调参数列表内是倒序排列的 65 | // 例如 void(int) + 参数a + 参数b 66 | // 最后的处理函数中的顺序是 (b,a,runArgs); 67 | base::OnceCallback callback = base::BindOnce( 68 | [](int power, int source) { 69 | LOG(INFO) << "Power " << source << " With " << power << " is " 70 | << power * source; 71 | }, 72 | power); 73 | 74 | std::move(callback).Run(3); 75 | } 76 | // 闭包用例 77 | void BindWithClosureUsage() { 78 | // 当函数签名为 void(void)时,我们可以使用闭包代替BindOnce callback) { 87 | std::move(callback).Run("Helo World!"); 88 | } 89 | 90 | int main(int argc, char** argv) { 91 | // 设置日志 92 | logging::LoggingSettings settings; 93 | settings.logging_dest = logging::LOG_TO_STDERR; 94 | logging::InitLogging(settings); 95 | logging::SetLogItems(true, true, true, false); 96 | 97 | // Demos 98 | BasicUsage(); 99 | (new ClassUsage())->Run(); 100 | LambdaUsage(); 101 | MoreParamsAndReturnUsage(); 102 | BindWithOutterParamsUsage(); 103 | BindWithClosureUsage(); 104 | 105 | // OnceCallback作为参数时,传递参数需要转移所有权 106 | base::OnceCallback cb = base::BindOnce( 107 | [](const std::string& msg) { LOG(INFO) << "TransmitUsage " << msg; }); 108 | TransmitUsage(std::move(cb)); 109 | 110 | // 创建单线程任务运行环境 111 | base::SingleThreadTaskExecutor main_task_executor; 112 | // 启动事件循环 113 | base::RunLoop().Run(); 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /demo_callback/demo_callback_repeating.cc: -------------------------------------------------------------------------------- 1 | #include "base/logging.h" 2 | #include "base/run_loop.h" 3 | #include "base/task/single_thread_task_executor.h" 4 | 5 | /** 6 | * 写在最前 7 | * RepeatingCallback和OnceCallback最大的区别在于可以被重复调用 8 | * 因此不需要进行所有权转移 9 | * 但是需要注意指针和内存问题 10 | */ 11 | 12 | // 1. 基本使用 使用函数的回调 13 | void SayHello(const std::string& name) { 14 | LOG(INFO) << "Hello " << name << "!"; 15 | } 16 | void BasicUsage() { 17 | base::RepeatingCallback callback = 18 | base::BindRepeating(&SayHello); 19 | ; 20 | //使用时需要转移所有权,之后就不能再调用了 21 | callback.Run("Basic Usage"); 22 | callback.Run("Basic Usage Repeat"); 23 | } 24 | 25 | // 2. 使用类的方法 26 | class ClassUsage { 27 | public: 28 | ClassUsage() {} 29 | ~ClassUsage() {} 30 | 31 | void Run() { 32 | // 如果是调用当前类型内部的方法 33 | // 参数需要指定当前方法所在的类型实例 34 | // 这样除了指定当前类型,也可以指定其他类型的方法作为回调函数 35 | // base::Unretained函数表示当前回调不持有引用 36 | base::RepeatingCallback callback = 37 | base::BindRepeating(&ClassUsage::SayHello, base::Unretained(this)); 38 | 39 | callback.Run("ClassUsage"); 40 | callback.Run("Class Useage Repeat"); 41 | } 42 | 43 | private: 44 | void SayHello(const std::string& name) { 45 | LOG(INFO) << "Hello " << name << "!"; 46 | } 47 | }; 48 | 49 | // 使用Lambda表达式 50 | void LambdaUsage() { 51 | // Lambda 52 | base::RepeatingCallback callback = 53 | base::BindRepeating([](const std::string& name) { 54 | LOG(INFO) << "Hello " << name << "!"; 55 | }); 56 | 57 | callback.Run("LambdaUsage"); 58 | callback.Run("LambdaUsage Repeat"); 59 | } 60 | 61 | // 更多的参数与与返回值 62 | void MoreParamsAndReturnUsage() { 63 | // 这里我们修改刚刚的模板 64 | // 在拥有返回值后,无论是函数,方法,还是lambda记得返回相同类型的返回值 65 | base::RepeatingCallback callback = 66 | base::BindRepeating([](int a, int b) { return a + b; }); 67 | 68 | LOG(INFO) << "CallbackWithReturn " 69 | << "1+1=" << callback.Run(1, 1); 70 | LOG(INFO) << "CallbackWithReturn " 71 | << "2+2=" << callback.Run(2, 2); 72 | } 73 | // Bind时捕获外部参数 74 | void BindWithOutterParamsUsage() { 75 | int power = 3; 76 | 77 | // 可以在BindRepeating后面增加外部参数,额外增加的参数,在回调参数列表内是倒序排列的 78 | // 例如 void(int) + 参数a + 参数b 79 | // 最后的处理函数中的顺序是 (b,a,runArgs); 80 | base::RepeatingCallback callback = base::BindRepeating( 81 | [](int power, int source) { 82 | LOG(INFO) << "Power " << source << " With " << power << " is " 83 | << power * source; 84 | }, 85 | power); 86 | 87 | callback.Run(3); 88 | callback.Run(4); 89 | } 90 | // 闭包用例 91 | void BindWithClosureUsage() { 92 | // 当函数签名为 void(void)时,我们可以使用闭包代替BindRepeating callback) { 103 | callback.Run("Helo World!"); 104 | callback.Run("Thanks Keyou And All Group Members"); 105 | } 106 | 107 | int main(int argc, char** argv) { 108 | // 设置日志 109 | logging::LoggingSettings settings; 110 | settings.logging_dest = logging::LOG_TO_STDERR; 111 | logging::InitLogging(settings); 112 | logging::SetLogItems(true, true, true, false); 113 | 114 | // Demos 115 | BasicUsage(); 116 | (new ClassUsage())->Run(); 117 | LambdaUsage(); 118 | MoreParamsAndReturnUsage(); 119 | BindWithOutterParamsUsage(); 120 | BindWithClosureUsage(); 121 | 122 | // RepeatingCallback作为参数时,没有任何限制 123 | base::RepeatingCallback cb = base::BindRepeating( 124 | [](const std::string& msg) { LOG(INFO) << "TransmitUsage " << msg; }); 125 | TransmitUsage(cb); 126 | TransmitUsage(cb); 127 | 128 | // 创建单线程任务运行环境 129 | base::SingleThreadTaskExecutor main_task_executor; 130 | // 启动事件循环 131 | base::RunLoop().Run(); 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /demo_cc/BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | import("//build/config/ui.gni") 3 | 4 | template("cc") { 5 | executable(target_name){ 6 | testonly = true 7 | forward_variables_from(invoker, "*") 8 | 9 | deps = [ 10 | "//base", 11 | "//build/win:default_exe_manifest", 12 | "//cc:test_support", 13 | "//cc", 14 | "//components/viz/demo:host", 15 | "//components/viz/demo:service", 16 | "//components/viz/host", 17 | "//components/viz/service", 18 | "//components/viz/service/main", 19 | "//mojo/core/embedder", 20 | "//skia", 21 | "//ui/events", 22 | "//ui/events/platform", 23 | "//ui/platform_window", 24 | ] 25 | 26 | if (ozone_platform_x11) { 27 | deps += [ 28 | "//ui/events/platform/x11", 29 | "//ui/ozone", 30 | ] 31 | #configs += [ "//build/config/linux:x11" ] 32 | } 33 | if (is_win) { 34 | deps += [ 35 | "//ui/platform_window/win:win", 36 | ] 37 | } 38 | } 39 | } 40 | 41 | group("demo_cc") { 42 | testonly = true 43 | deps = [ 44 | ":demo_cc_gui", 45 | ":demo_cc_offscreen" 46 | ] 47 | } 48 | 49 | cc("demo_cc_gui") { 50 | sources = [ 51 | "demo_cc_gui.cc" 52 | ] 53 | } 54 | 55 | cc("demo_cc_offscreen") { 56 | sources = [ 57 | "demo_cc_offscreen.cc" 58 | ] 59 | } 60 | 61 | -------------------------------------------------------------------------------- /demo_cc/README.md: -------------------------------------------------------------------------------- 1 | # cc (Chrome Compositor) 2 | 3 | > Viz 和 cc 相关的类图见: 4 | 5 | TODO: 完善文档 6 | 7 | cc 的核心调度入口在 `cc::Scheduler::ProcessScheduledActions()`,主要代码如下: 8 | 9 | ```C++ 10 | // 2020年1月(v80.0.3987.158),有删减 11 | void Scheduler::ProcessScheduledActions() { 12 | SchedulerStateMachine::Action action; 13 | do { 14 | action = state_machine_.NextAction(); 15 | switch (action) { 16 | case SchedulerStateMachine::Action::NONE: 17 | break; 18 | case SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME: 19 | // 绘制新帧,这会触发cc embedder的绘制(Paint),比如views::View::Paint()或者blink::GraphicsLayer::Paint() 20 | client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_); 21 | break; 22 | case SchedulerStateMachine::Action::COMMIT: { 23 | // 执行提交,也就是将cc::Layer的内容复制到cc::LayerImpl中 24 | client_->ScheduledActionCommit(); 25 | break; 26 | } 27 | case SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE: 28 | // 执行同步,也就是将pending_tree的内容同步到active_tree 29 | client_->ScheduledActionActivateSyncTree(); 30 | break; 31 | case SchedulerStateMachine::Action::DRAW_IF_POSSIBLE: 32 | // 执行submit,创建CompositorFrame并提交到DisplayCompsitor 33 | DrawIfPossible(); 34 | break; 35 | case SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION: 36 | // 初始化,请求创建LayerTreeFrameSink 37 | client_->ScheduledActionBeginLayerTreeFrameSinkCreation(); 38 | break; 39 | case SchedulerStateMachine::Action::PREPARE_TILES: 40 | // 执行Raster,并且准备Tiles 41 | client_->ScheduledActionPrepareTiles(); 42 | break; 43 | } 44 | } 45 | } while (action != SchedulerStateMachine::Action::NONE); 46 | 47 | // 用于设定一个Deadline,在该Deadline之前都允许触发SEND_BEGIN_MAIN_FRAME事件,在Deadline触发后就不再允许触发该事件。它会Post一个延迟的OnBeginImplFrameDeadline事件,如果该事件执行了表示已经到了Deadline(状态机进入INSIDE_DEADLINE状态),它会设置一些状态禁止触发BeginMainFrame,然后进行下一次调度,这些调度都是需要在Deadline状态才能执行的操作,可能调度到DRAW_IF_POSSIBLE,这会触发client提交CF到viz,也可能调度到其他状态比如PREPARE_TILES等,当然也可能调度到NONE状态,在进入Deadline之后的所有操作都完成之后,调度器会进入空闲状态IDLE,此时就算退出Deadline了,后续就允许触发SEND_BEGIN_MAIN_FRAME事件了。 48 | ScheduleBeginImplFrameDeadline(); 49 | 50 | // 用于检测是否需要触发SEND_BEGIN_MAIN_FRAME事件,如果需要它会Post HandlePendingBeginFrame事件,该事件执行后会使状态机进入INSIDE_BEGIN_FRAME状态,随后调度器会在合适的时机触发SEND_BEGIN_MAIN_FRAME事件,这会调用client进行绘制,在client绘制完成之后会请求调度器执行提交COMMIT以及激活ACTIVATE_SYNC_TREE。 51 | PostPendingBeginFrameTask(); 52 | 53 | // 用于检测当前是否处于IDLE状态,如果是则将自己从 BFS 移除,否则则将自己 加入BFS。如果调度器将自己从BFS上移除,则会进入”休眠状态“,此时不会调度器不会占用CPU,如果后续外部需要更新显示的画面,可以通过cc::Scheduler::SetNeedsBeginFrame()来激活调度器(注意cc模块外可以通过cc::LayerTreeHost::SetNeedsCommit()来间接调用它,如果在cc::Layer中,则可以直接调用它的SetNeedsCommit成员函数,如果cc::Layer没有任何变化,只调用SetNeddsCommit()则不会激活调度器,必须有实际的变更或者标记区域demaged)。 54 | StartOrStopBeginFrames(); 55 | } 56 | ``` 57 | -------------------------------------------------------------------------------- /demo_gin/BUILD.gn: -------------------------------------------------------------------------------- 1 | # 可执行文件 2 | executable("demo_gin"){ 3 | testonly = true 4 | 5 | sources = [ 6 | # 主入口 7 | "demo_gin.cc", 8 | 9 | # ShellRunnerDelegate 10 | "shell_runner_delegate.cc", 11 | "shell_runner_delegate.h", 12 | 13 | # 我们扩展的方法 14 | "extends/console.cc", 15 | "extends/console.h", 16 | "extends/demo.cc", 17 | "extends/demo.h", 18 | 19 | "extends/async_demo.cc", 20 | "extends/async_demo.h" 21 | 22 | 23 | ] 24 | include_dirs = [ 25 | "//demo", 26 | ] 27 | deps = [ 28 | "//base", 29 | "//gin", 30 | "//v8" 31 | ] 32 | # 如果希望Demo运行,必须要配置初始化数据 33 | configs += [ "//v8:external_startup_data" ] 34 | } 35 | -------------------------------------------------------------------------------- /demo_gin/README.md: -------------------------------------------------------------------------------- 1 | # demo_gin 2 | 3 | gin 是一个轻量级的 v8 绑定实现,可以用来构建简单的 v8 扩展。 4 | 5 | 这是一个简单的 gin 应用,演示如何使用 gin 创建一个简单的 js 运行时。 6 | 7 | 其中 extends 目录是我们为 globalThis(window) 对象扩展的方法。 8 | 9 | 编译后直接运行 demo 即可,支持 es6 语法。 10 | -------------------------------------------------------------------------------- /demo_gin/demo_gin.cc: -------------------------------------------------------------------------------- 1 | #include "base/at_exit.h" 2 | #include "base/command_line.h" 3 | #include "base/run_loop.h" 4 | #include "base/task/single_thread_task_executor.h" 5 | #include "base/task/single_thread_task_runner.h" 6 | #include "base/task/thread_pool/thread_pool_instance.h" 7 | #include "demo_gin/shell_runner_delegate.h" 8 | #include "gin/array_buffer.h" 9 | #include "gin/public/isolate_holder.h" 10 | #include "gin/shell_runner.h" 11 | #include "gin/v8_initializer.h" 12 | 13 | // 要执行的脚本 14 | // 可以改为读取文件形式 15 | const char kScript[] = 16 | R"script( 17 | // 输出Hello World 18 | log('hello world'); 19 | 20 | // 进行计算 输出结果 Result 3 21 | let a = demo.add(1,2); 22 | log(`Result ${a}`); 23 | 24 | // 异步计算 输出结果 1.before 2.after 3. result:3 25 | log('before call async'); 26 | asyncDemo.add(1,2).then(m=>log(`result:${m}`)); 27 | log('after call async'); 28 | 29 | )script"; 30 | 31 | namespace { 32 | // 执行脚本 33 | void Run(base::WeakPtr runner) { 34 | if (!runner) 35 | return; 36 | gin::Runner::Scope scope(runner.get()); 37 | 38 | runner->Run(kScript, "demo"); 39 | } 40 | 41 | } // namespace 42 | 43 | int main(int argc, char** argv) { 44 | // 构建事件循环及相关线程 45 | base::AtExitManager at_exit; 46 | base::CommandLine::Init(argc, argv); 47 | base::SingleThreadTaskExecutor main_thread_task_executor; 48 | base::ThreadPoolInstance::CreateAndStartWithDefaultParams("gin"); 49 | 50 | // Load V8快照默认资源 51 | gin::V8Initializer::LoadV8Snapshot(); 52 | 53 | { 54 | // 初始化VM 55 | gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode, 56 | gin::ArrayBufferAllocator::SharedInstance()); 57 | 58 | // 创建VM实例 59 | gin::IsolateHolder instance( 60 | base::SingleThreadTaskRunner::GetCurrentDefault(), 61 | gin::IsolateHolder::IsolateType::kBlinkMainThread); 62 | 63 | // 构建GinShellRunner 用于执行文件脚本 64 | demo::DemoShellRunnerDelegate delegate; 65 | gin::ShellRunner runner(&delegate, instance.isolate()); 66 | 67 | // 创建Handle容器 68 | { 69 | gin::Runner::Scope scope(&runner); 70 | runner.GetContextHolder() 71 | ->isolate() 72 | ->SetCaptureStackTraceForUncaughtExceptions(true); 73 | } 74 | 75 | // 执行脚本 76 | base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( 77 | FROM_HERE, base::BindOnce(Run, runner.GetWeakPtr())); 78 | base::RunLoop().RunUntilIdle(); 79 | } 80 | 81 | // 结束线程池 82 | base::ThreadPoolInstance::Get()->Shutdown(); 83 | 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /demo_gin/extends/async_demo.cc: -------------------------------------------------------------------------------- 1 | #include "demo_gin/extends/async_demo.h" 2 | 3 | #include "base/logging.h" 4 | #include "base/task/single_thread_task_runner.h" 5 | #include "gin/arguments.h" 6 | #include "gin/converter.h" 7 | #include "v8/include/v8-microtask-queue.h" 8 | #include "v8/include/v8-template.h" 9 | 10 | namespace demo { 11 | 12 | namespace { 13 | 14 | // 实际运行的Add计算的异步方法 15 | void AsyncAdd(v8::Global resolver, 16 | v8::Global original_context, 17 | v8::Isolate* isolate, 18 | int a, 19 | int b) { 20 | // 创建微任务Scope 21 | v8::MicrotasksScope microtasks_scope( 22 | isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); 23 | v8::HandleScope handle_scope(isolate); 24 | // 将Persistent 转为Local 25 | v8::Local context = original_context.Get(isolate); 26 | // 真正执行计算 27 | int result = a + b; 28 | LOG(INFO) << "Add Arg1:" << a << " And Arg2:" << b << " Result:" << result; 29 | // 获取LocalResolver 并执行Resolve 30 | resolver.Get(isolate) 31 | ->Resolve(context, v8::Integer::New(isolate, result)) 32 | .ToChecked(); 33 | } 34 | 35 | // Add 方法 产生一个Promise 36 | void Add(const v8::FunctionCallbackInfo& info) { 37 | auto* isolate = info.GetIsolate(); 38 | auto context = isolate->GetCurrentContext(); 39 | // 创建 Promise Resolver对象 40 | auto resolver = v8::Promise::Resolver::New(context).ToLocalChecked(); 41 | 42 | // 获取参数 43 | gin::Arguments args(info); 44 | int a = 0; 45 | int b = 0; 46 | if (!args.GetNext(&a) || !args.GetNext(&b)) { 47 | args.ThrowError(); 48 | return; 49 | } 50 | 51 | // 构建Persistent Resolver和Context 52 | // 保证他们的生命周期超过当前函数栈 53 | v8::Global unique_resolver = 54 | v8::Global(isolate, resolver); 55 | v8::Global persisted_context = 56 | v8::Global(isolate, context); 57 | 58 | // 返回Promise 59 | info.GetReturnValue().Set(resolver->GetPromise()); 60 | 61 | // 执行异步计算 62 | base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( 63 | FROM_HERE, base::BindOnce(AsyncAdd, std::move(unique_resolver), 64 | std::move(persisted_context), isolate, a, b)); 65 | } 66 | 67 | } // namespace 68 | 69 | void AsyncDemo::Register(v8::Isolate* isolate, 70 | v8::Local global_tmpl) { 71 | // 构建AsyncDemo Object模板 72 | v8::Local async_demo_tmpl = 73 | v8::ObjectTemplate::New(isolate); 74 | global_tmpl->Set(gin::StringToSymbol(isolate, "asyncDemo"), async_demo_tmpl); 75 | 76 | // 构建AsyncDemo Object Function模板 77 | v8::Local add_tmpl = v8::FunctionTemplate::New( 78 | isolate, Add, v8::Local(), v8::Local(), 0, 79 | v8::ConstructorBehavior::kThrow); 80 | 81 | async_demo_tmpl->Set(gin::StringToSymbol(isolate, "add"), add_tmpl); 82 | } 83 | } // namespace demo 84 | -------------------------------------------------------------------------------- /demo_gin/extends/async_demo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gin/gin_export.h" 4 | #include "v8/include/v8-forward.h" 5 | 6 | namespace demo { 7 | // 提供Add方法的类 8 | class GIN_EXPORT AsyncDemo { 9 | public: 10 | // 注册对应的方法和对象 11 | static void Register(v8::Isolate* isolate, 12 | v8::Local global_tmpl); 13 | }; 14 | } // namespace demo -------------------------------------------------------------------------------- /demo_gin/extends/console.cc: -------------------------------------------------------------------------------- 1 | #include "demo_gin/extends/console.h" 2 | 3 | #include "base/strings/string_util.h" 4 | #include "gin/arguments.h" 5 | #include "gin/converter.h" 6 | #include "v8/include/v8-template.h" 7 | 8 | namespace demo { 9 | 10 | namespace { 11 | 12 | void Log(const v8::FunctionCallbackInfo& info) { 13 | gin::Arguments args(info); 14 | std::vector messages; 15 | if (!args.GetRemaining(&messages)) { 16 | args.ThrowError(); 17 | return; 18 | } 19 | printf("%s\n", base::JoinString(messages, " ").c_str()); 20 | } 21 | 22 | } // namespace 23 | 24 | void Console::Register(v8::Isolate* isolate, 25 | v8::Local global_tmpl) { 26 | // 构建Log Function 27 | v8::Local log_tmpl = v8::FunctionTemplate::New( 28 | isolate, Log, v8::Local(), v8::Local(), 0, 29 | v8::ConstructorBehavior::kThrow); 30 | 31 | global_tmpl->Set(gin::StringToSymbol(isolate, "log"), log_tmpl); 32 | } 33 | } // namespace demo 34 | -------------------------------------------------------------------------------- /demo_gin/extends/console.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gin/gin_export.h" 4 | #include "v8/include/v8-forward.h" 5 | 6 | namespace demo { 7 | // 提供Add方法的类 8 | class GIN_EXPORT Console { 9 | public: 10 | // 注册对应的方法和对象 11 | static void Register(v8::Isolate* isolate, 12 | v8::Local global_tmpl); 13 | }; 14 | } // namespace demo -------------------------------------------------------------------------------- /demo_gin/extends/demo.cc: -------------------------------------------------------------------------------- 1 | #include "demo_gin/extends/demo.h" 2 | 3 | #include "base/logging.h" 4 | #include "gin/arguments.h" 5 | #include "gin/converter.h" 6 | #include "v8/include/v8-template.h" 7 | 8 | namespace demo { 9 | 10 | namespace { 11 | 12 | // 实际运行的Add方法 13 | void Add(const v8::FunctionCallbackInfo& info) { 14 | gin::Arguments args(info); 15 | int a = 0; 16 | int b = 0; 17 | if (!args.GetNext(&a) || !args.GetNext(&b)) { 18 | args.ThrowError(); 19 | return; 20 | } 21 | 22 | LOG(INFO) << "Add Arg1:" << a << " And Arg2:" << b << " Result:" << a + b; 23 | 24 | info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), a + b)); 25 | } 26 | 27 | } // namespace 28 | 29 | 30 | void Demo::Register(v8::Isolate* isolate, v8::Local global_tmpl) { 31 | // 构建Demo Object模板 32 | v8::Local demo_tmpl = v8::ObjectTemplate::New(isolate); 33 | global_tmpl->Set(gin::StringToSymbol(isolate, "demo"), demo_tmpl); 34 | 35 | // 构建Demo Object Function模板 36 | v8::Local add_tmpl = v8::FunctionTemplate::New( 37 | isolate, Add, v8::Local(), v8::Local(), 0, 38 | v8::ConstructorBehavior::kThrow); 39 | 40 | demo_tmpl->Set(gin::StringToSymbol(isolate, "add"), add_tmpl); 41 | 42 | } 43 | } // namespace demo 44 | -------------------------------------------------------------------------------- /demo_gin/extends/demo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gin/gin_export.h" 4 | #include "v8/include/v8-forward.h" 5 | 6 | namespace demo { 7 | // 提供Add方法的类 8 | class GIN_EXPORT Demo { 9 | public: 10 | // 注册对应的方法和对象 11 | static void Register(v8::Isolate* isolate, 12 | 13 | v8::Local global_tmpl); 14 | }; 15 | } // namespace demo -------------------------------------------------------------------------------- /demo_gin/shell_runner_delegate.cc: -------------------------------------------------------------------------------- 1 | #include "demo_gin/shell_runner_delegate.h" 2 | #include "base/logging.h" 3 | #include "gin/object_template_builder.h" 4 | #include "demo_gin/extends/console.h" 5 | #include "demo_gin/extends/demo.h" 6 | 7 | #include "demo_gin/extends/async_demo.h" 8 | 9 | namespace demo { 10 | 11 | v8::Local DemoShellRunnerDelegate::GetGlobalTemplate( 12 | gin::ShellRunner* runner, 13 | v8::Isolate* isolate) { 14 | // 构建GlobalThis对象 15 | v8::Local global_tmpl = 16 | gin::ObjectTemplateBuilder(isolate).Build(); 17 | 18 | // 注册Console 19 | demo::Console::Register(isolate, global_tmpl); 20 | 21 | // 注册Demo 22 | demo::Demo::Register(isolate, global_tmpl); 23 | 24 | 25 | // 注册AsyncDemo 26 | demo::AsyncDemo::Register(isolate,global_tmpl); 27 | 28 | return global_tmpl; 29 | } 30 | 31 | void DemoShellRunnerDelegate::UnhandledException(gin::ShellRunner* runner, 32 | gin::TryCatch& try_catch) { 33 | LOG(ERROR) << try_catch.GetStackTrace(); 34 | } 35 | } // namespace demo -------------------------------------------------------------------------------- /demo_gin/shell_runner_delegate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gin/shell_runner.h" 3 | #include "gin/try_catch.h" 4 | 5 | namespace demo { 6 | 7 | // 实现我们自己的ShellRunnerDelegate 8 | // 主要用于注册我们自己提供的方法 9 | class DemoShellRunnerDelegate : public gin::ShellRunnerDelegate { 10 | public: 11 | DemoShellRunnerDelegate() = default; 12 | DemoShellRunnerDelegate(const DemoShellRunnerDelegate&) = delete; 13 | DemoShellRunnerDelegate& operator=(const DemoShellRunnerDelegate&) = delete; 14 | 15 | // 获取GlobalThis对象 16 | v8::Local GetGlobalTemplate( 17 | gin::ShellRunner* runner, 18 | v8::Isolate* isolate) override; 19 | 20 | // 处理异常 21 | void UnhandledException(gin::ShellRunner* runner, 22 | gin::TryCatch& try_catch) override; 23 | }; 24 | } // namespace demo -------------------------------------------------------------------------------- /demo_gl/BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | import("//build/config/ui.gni") 3 | 4 | executable("demo_gl") { 5 | testonly = true 6 | 7 | sources = [ 8 | "demo_gl.cc", 9 | ] 10 | 11 | deps = [ 12 | "//base", 13 | "//base:i18n", 14 | "//gpu", 15 | "//gpu:gles2", 16 | "//gpu:raster", 17 | # "//gpu/command_buffer/client", 18 | # "//gpu/command_buffer/client:gles2_cmd_helper", 19 | # "//gpu/command_buffer/service", 20 | # "//gpu/command_buffer/service:gles2", 21 | "//ui/base", 22 | "//ui/gl", 23 | "//ui/gl/init", 24 | "//ui/events", 25 | "//ui/events/platform", 26 | "//ui/platform_window", 27 | # "//skia", 28 | ] 29 | 30 | if (ozone_platform_x11) { 31 | deps += [ 32 | "//ui/events/platform/x11", 33 | "//ui/ozone", 34 | ] 35 | #configs += [ "//build/config/linux:x11" ] 36 | } 37 | 38 | if (use_ozone) { 39 | deps += [ 40 | "//ui/ozone", 41 | ] 42 | } 43 | 44 | if (is_win) { 45 | deps += [ 46 | "//ui/platform_window/win:win", 47 | ] 48 | } 49 | 50 | # libs = ["EGL","GLESv2"] 51 | } 52 | -------------------------------------------------------------------------------- /demo_gl/README.md: -------------------------------------------------------------------------------- 1 | # demo_gl 2 | 3 | 演示如何通过 `//ui/gl` 模块进行 EGL/GL 调用。 4 | 5 | `//ui/gl` 模块封装了各平台的 native GL,在 Chromium 中负责直接和 native GL 打交道,运行在 GPU 进程中。 6 | -------------------------------------------------------------------------------- /demo_ipc/BUILD.gn: -------------------------------------------------------------------------------- 1 | executable("demo_ipc") { 2 | testonly = true 3 | sources = [ 4 | "demo_ipc.cc", 5 | "demo_ipc_messages.h", 6 | "demo_ipc_message_generator.h", 7 | "demo_ipc_message_generator.cc", 8 | ] 9 | 10 | deps = [ 11 | "//base", 12 | "//base:base_static", 13 | "//mojo/public", 14 | "//mojo/core/embedder", 15 | "//demo/demo_mojo/mojom", 16 | ] 17 | } -------------------------------------------------------------------------------- /demo_ipc/demo_ipc_message_generator.cc: -------------------------------------------------------------------------------- 1 | // Get basic type definitions. 2 | #define IPC_MESSAGE_IMPL 3 | #include "demo_ipc_message_generator.h" 4 | // Generate constructors. 5 | #include "ipc/struct_constructor_macros.h" 6 | #include "demo_ipc_message_generator.h" 7 | // Generate param traits write methods. 8 | #include "ipc/param_traits_write_macros.h" 9 | namespace IPC { 10 | #include "demo_ipc_message_generator.h" 11 | } // namespace IPC 12 | // Generate param traits read methods. 13 | #include "ipc/param_traits_read_macros.h" 14 | namespace IPC { 15 | #include "demo_ipc_message_generator.h" 16 | } // namespace IPC 17 | // Generate param traits log methods. 18 | #include "ipc/param_traits_log_macros.h" 19 | namespace IPC { 20 | #include "demo_ipc_message_generator.h" 21 | } // namespace IPC -------------------------------------------------------------------------------- /demo_ipc/demo_ipc_message_generator.h: -------------------------------------------------------------------------------- 1 | #undef DEMO_IPC_MESSAGES_H_ 2 | #include "demo_ipc_messages.h" 3 | #ifndef DEMO_IPC_MESSAGES_H_ 4 | #error "Failed to include header demo_ipc_messages.h" 5 | #endif -------------------------------------------------------------------------------- /demo_ipc/demo_ipc_messages.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_IPC_MESSAGES_H_ 2 | #define DEMO_IPC_MESSAGES_H_ 3 | 4 | #include "ipc/ipc_message.h" 5 | #include "ipc/ipc_message_macros.h" 6 | #include "ipc/ipc_message_start.h" 7 | #include "ipc/ipc_param_traits.h" 8 | 9 | // 使用 IPCTestMsgStart 来测试,它不能随意命名,必须存在于 ipc/ipc_message_start.h 中 10 | // 详情见 ipc/ipc_message_start.h 文件头的解释 11 | // 关于 IPC 的介绍见 http://www.chromium.org/developers/design-documents/inter-process-communication 12 | #define IPC_MESSAGE_START TestMsgStart 13 | 14 | IPC_MESSAGE_CONTROL1(IPCTestMsg_Hello,std::string) 15 | IPC_MESSAGE_CONTROL1(IPCTestMsg_Hi,std::string) 16 | 17 | IPC_MESSAGE_ROUTED1(IPCTestMsg_RoutedHello,std::string) 18 | IPC_MESSAGE_ROUTED1(IPCTestMsg_RoutedHi,std::string) 19 | 20 | #endif //DEMO_IPC_MESSAGES_H_ -------------------------------------------------------------------------------- /demo_linktest/BUILD.gn: -------------------------------------------------------------------------------- 1 | # 修改该值然后重新编译来观察编译结果是否符合预期。 2 | # 0: release,debug 都不会出错; 3 | # 1: release 出错,debug 不出错; 4 | # 2: release 不出错,debug 出错; 5 | should_error = 0 6 | if (should_error == 0) { 7 | # release,debug 都不会报错。 8 | 9 | # debug: demo_linktest = demo_linktest/main.o + b.so 10 | # release: demo_linktest = lintest/main.o + b.a + a/a.o 11 | executable("demo_linktest") { 12 | sources = [ 13 | # "a.cc", 14 | "main.cc", # demo_linktest/main.o 15 | ] 16 | 17 | deps = [ 18 | ":b", # debug: b.so; release: b.a + a/a.o 19 | ] 20 | } 21 | 22 | # debug: b.so = b/b.o + a/a.o,产出 b.so 23 | # release: b.a = b/b.o,产出 b.a + a/a.o 24 | component("b") { 25 | sources = [ 26 | # "a.cc", 27 | "b.cc", # b/b.o 28 | ] 29 | deps = [ ":a" ] # a/a.o 30 | } 31 | } else if (should_error == 1) { 32 | # 在 release 下编译该目标报错,但是在 debug 下不会报错。 33 | 34 | # debug: demo_linktest = demo_linktest/main.o + demo_linktest/a.o + b.so 35 | # release: demo_linktest = lintest/main.o + demo_linktest/a.o + b.a + a/a.o,两个 a.o,报错!!! 36 | executable("demo_linktest") { 37 | sources = [ 38 | "a.cc", # demo_linktest/a.o 39 | "main.cc", # demo_linktest/main.o 40 | ] 41 | 42 | deps = [ 43 | ":b", # debug: b.so; release: b.a + a/a.o 44 | ] 45 | } 46 | 47 | # debug: b.so = b/b.o + a/a.o,产出 b.so 48 | # release: b.a = b/b.o,产出 b.a + a/a.o 49 | component("b") { 50 | sources = [ 51 | # "a.cc", 52 | "b.cc", # b/b.o 53 | ] 54 | deps = [ ":a" ] # a/a.o 55 | } 56 | } else { 57 | # 在 debug 下编译该目标报错,但是在 release 下不会报错。 58 | 59 | # debug: demo_linktest = main.o + a/a.o + b.so 60 | # release: demo_linktest = main.o + a/a.o + b.a 61 | executable("demo_linktest") { 62 | sources = [ 63 | # "a.cc", 64 | "main.cc", # main.o 65 | ] 66 | 67 | deps = [ 68 | ":a", # a/a.o 69 | ":b", # debug: b.so; release: b.a + a/a.o 70 | ] 71 | } 72 | 73 | # debug: b.so = b/a.o + b/b.o + a/a.o,两个 a.o,报错!!! 74 | # release: b.a = b/a.o + b/b.o,产出 b.a + a/a.o 75 | component("b") { 76 | sources = [ 77 | "a.cc", # b/a.o 78 | "b.cc", # b/b.o 79 | ] 80 | deps = [ ":a" ] # a/a.o 81 | } 82 | } 83 | 84 | # 不管在 debug 还是 release 都产出 a/a.o 85 | source_set("a") { 86 | sources = [ "a.cc" ] # a/a.o 87 | } 88 | -------------------------------------------------------------------------------- /demo_linktest/README.md: -------------------------------------------------------------------------------- 1 | # demo_linktest 2 | 3 | 这个 demo 演示为什么有时候链接错误只出现在 debug 或者 release,而不是同时出现。详情见 BULLD.gn。 4 | -------------------------------------------------------------------------------- /demo_linktest/a.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __attribute__((visibility("default"))) void aaa() { 4 | std::cout << "aaaa"; 5 | } -------------------------------------------------------------------------------- /demo_linktest/b.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __attribute__((visibility("default"))) void aaa(); 4 | 5 | __attribute__((visibility("default"))) void bbb() { 6 | std::cout << "bbbb"; 7 | aaa(); 8 | } -------------------------------------------------------------------------------- /demo_linktest/main.cc: -------------------------------------------------------------------------------- 1 | 2 | __attribute__((visibility("default"))) void aaa(); 3 | __attribute__((visibility("default"))) void bbb(); 4 | 5 | int main() { 6 | aaa(); 7 | bbb(); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /demo_log/BUILD.gn: -------------------------------------------------------------------------------- 1 | executable("demo_log") { 2 | testonly = true 3 | sources = [ 4 | "demo_log.cc" 5 | ] 6 | deps = [ 7 | "//base", 8 | ] 9 | } 10 | 11 | -------------------------------------------------------------------------------- /demo_log/demo_log.cc: -------------------------------------------------------------------------------- 1 | #include "base/command_line.h" 2 | #include "base/logging.h" 3 | #include "base/debug/stack_trace.h" 4 | 5 | int main(int argc, char** argv) { 6 | // 使用log依赖它 7 | base::CommandLine::Init(argc, argv); 8 | 9 | int loglevel = -1; 10 | 11 | logging::SetLogPrefix("demo"); 12 | logging::SetLogItems(true,false,true,false); 13 | // 设置为负数启用VLOG,在chromium中使用 --v=1 达到同样效果 14 | logging::SetMinLogLevel(loglevel); 15 | 16 | logging::LoggingSettings settings; 17 | settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR; 18 | settings.log_file_path = nullptr; 19 | settings.lock_log = logging::DONT_LOCK_LOG_FILE; 20 | settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE; 21 | bool logging_res = logging::InitLogging(settings); 22 | CHECK(logging_res); 23 | 24 | // 主动打印堆栈信息 25 | LOG(INFO) << "Stack: " << base::debug::StackTrace().ToString(); 26 | 27 | LOG(INFO) << "set loglevel to: " << loglevel; 28 | 29 | LOG(INFO) << "LOG: INFO"; 30 | DLOG(INFO) << "DLOG: INFO"; 31 | 32 | LOG(WARNING) << "LOG: WARNING"; 33 | LOG(ERROR) << "LOG: ERROR"; 34 | 35 | LOG_IF(INFO,2>1) << "LOG_IF: INFO 2>1"; 36 | DLOG_IF(INFO,2>1) << "DLOG_IF: INFO 2>1"; 37 | 38 | // 不会打印出来,因为我们设置了LogLevel为 -1 39 | VLOG(2) << "VLOG: 2"; 40 | VLOG(3) << "VLOG: 3"; 41 | 42 | VLOG(1) << "VLOG: 1"; 43 | DVLOG(1) << "DVLOG: 1"; 44 | 45 | // 在日志后面追加 GetLastError() on Windows and errno on POSIX 46 | PLOG(INFO) << "PLOG: INFO"; 47 | DPLOG(INFO) << "DPLOG: INFO"; 48 | 49 | // 会使进程立即退出 50 | DLOG(FATAL) << "DLOG: FATAL"; 51 | LOG(FATAL) << "LOG: FATAL"; 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /demo_memory/BUILD.gn: -------------------------------------------------------------------------------- 1 | executable("demo_memory"){ 2 | sources = [ 3 | "demo_memory.cc", 4 | ] 5 | 6 | deps = [ 7 | "//base" 8 | ] 9 | } -------------------------------------------------------------------------------- /demo_mojo/BUILD.gn: -------------------------------------------------------------------------------- 1 | group("demo_mojo"){ 2 | testonly = true 3 | deps = [ 4 | ":demo_mojo_single_process", 5 | ":demo_mojo_multiple_process", 6 | ":demo_mojo_multiple_process_binding", 7 | # ":demo_services" 8 | ] 9 | } 10 | 11 | executable("demo_mojo_single_process") { 12 | testonly = true 13 | sources = [ 14 | "demo_mojo_single_process.cc", 15 | ] 16 | 17 | deps = [ 18 | "//base", 19 | "//mojo/public", 20 | "//mojo/core/embedder", 21 | ] 22 | } 23 | 24 | executable("demo_mojo_multiple_process") { 25 | testonly = true 26 | sources = [ 27 | "demo_mojo_multiple_process.cc", 28 | ] 29 | 30 | deps = [ 31 | 32 | "//base", 33 | "//mojo/public", 34 | "//mojo/core/embedder", 35 | "mojom", 36 | ] 37 | } 38 | 39 | executable("demo_mojo_multiple_process_binding") { 40 | testonly = true 41 | sources = [ 42 | "demo_mojo_multiple_process_binding.cc", 43 | ] 44 | 45 | deps = [ 46 | "//base", 47 | "//mojo/public", 48 | "//mojo/core/embedder", 49 | "mojom", 50 | ] 51 | } 52 | 53 | executable("demo_services") { 54 | testonly = true 55 | sources = [ 56 | "demo_services.cc", 57 | ] 58 | 59 | deps = [ 60 | "mojom", 61 | "//base", 62 | # TODO: 查明为什么这里必须显式依赖base_static,它明明已经作为base的public_deps了, 63 | # 难道public_deps对静态库(base_static)无效? 64 | "//base:base_static", 65 | "//mojo/public", 66 | "//services/service_manager", 67 | # "//services/service_manager/embedder", 68 | "//services/service_manager/public/cpp/service_executable:support" 69 | ] 70 | } -------------------------------------------------------------------------------- /demo_mojo/README.md: -------------------------------------------------------------------------------- 1 | # demo_mojo 2 | 3 | 该目录中的 demo 用来演示 chromium 中的 IPC 组件 `mojo`。 它是 chromium 多进程架构依赖的基础组件,因此非常重要。关于它的详细介绍可以参考官方文档或者我的 [Blog](https://keyou.github.io/blog/2020/01/03/Chromium-Mojo&IPC/)。 4 | 5 | 需要注意的是,这里演示的是 mojo 本身的接口及其使用方法,这些接口不依赖于任何的 chromium 核心逻辑,因此在 chromium 中看起来可能不太一样,原因是 chromium 对一些接口进行了更多的包装。 6 | 7 | 该目录包含以下几个 demo: 8 | - demo_mojo_single_process: 演示在单进程中使用 mojo 的 C 接口; 9 | - demo_mojo_multiple_process: 演示在多进程使用 mojo 的 C 接口; 10 | - demo_mojo_multiple_process_binding: 演示在多进程中使用 mojo 的 C++ 接口; 11 | - demo_services: (**DEPRECATED**)演示在多进程中使用 service 机制; -------------------------------------------------------------------------------- /demo_mojo/mojom/BUILD.gn: -------------------------------------------------------------------------------- 1 | # for mojo 2 | import("//mojo/public/tools/bindings/mojom.gni") 3 | 4 | group("mojom"){ 5 | testonly =true 6 | deps = [ 7 | ":mojom_test", 8 | ":mojom_test2", 9 | ":mojom_test3", 10 | ":mojom_test4", 11 | ":mojom_test_service", 12 | ] 13 | } 14 | 15 | mojom("mojom_test") { 16 | sources = [ 17 | "test.mojom", 18 | ] 19 | } 20 | 21 | mojom("mojom_test2") { 22 | sources = [ 23 | "test2.mojom", 24 | ] 25 | } 26 | 27 | mojom("mojom_test3") { 28 | sources = [ 29 | "test3.mojom", 30 | ] 31 | } 32 | 33 | mojom("mojom_test4") { 34 | sources = [ 35 | "test4.mojom", 36 | ] 37 | } 38 | 39 | mojom("mojom_test_service") { 40 | sources = [ 41 | "test_service.mojom", 42 | ] 43 | } 44 | 45 | -------------------------------------------------------------------------------- /demo_mojo/mojom/consumer_service_manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "consumer_service", 3 | "display_name": "Consumer Service", 4 | "interface_provider_specs": { 5 | "service_manager:connector": { 6 | "provides": { 7 | "root": ["demo.demo_mojo.mojom.RootInterface"] 8 | }, 9 | "requires": { 10 | "test_service": ["test"] 11 | } 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /demo_mojo/mojom/test.mojom: -------------------------------------------------------------------------------- 1 | 2 | // Chromium 推荐将mojom文件放在单独的mojom目录下 3 | 4 | module demo.demo_mojo.mojom; 5 | 6 | interface Test { 7 | Hello(string who); 8 | Hi() => (string who); 9 | }; -------------------------------------------------------------------------------- /demo_mojo/mojom/test2.mojom: -------------------------------------------------------------------------------- 1 | 2 | // Chromium 推荐将mojom文件放在单独的mojom目录下 3 | 4 | module demo.demo_mojo.mojom; 5 | 6 | interface Test2 { 7 | SendMessagePipeHandle(handle pipe_handle); 8 | }; 9 | -------------------------------------------------------------------------------- /demo_mojo/mojom/test3.mojom: -------------------------------------------------------------------------------- 1 | 2 | // Chromium 推荐将mojom文件放在单独的mojom目录下 3 | 4 | module demo.demo_mojo.mojom; 5 | 6 | interface Api { 7 | PrintApi(string data); 8 | }; 9 | 10 | interface Api2 { 11 | PrintApi2(string data); 12 | }; 13 | 14 | // see https://docs.google.com/document/d/1Jwfbzbe8ozaoilhqj5mAPYbYGpgZCen_XAAAdwmyP1E/edit#heading=h.serv9pzfw6sd 15 | interface Test3 { 16 | GetApi(pending_receiver api); 17 | SetApi2(pending_remote api2); 18 | }; 19 | 20 | interface Test32 { 21 | GetApi(pending_associated_receiver api); 22 | SetApi2(pending_associated_remote api2); 23 | }; -------------------------------------------------------------------------------- /demo_mojo/mojom/test4.mojom: -------------------------------------------------------------------------------- 1 | 2 | // Chromium 推荐将mojom文件放在单独的mojom目录下 3 | 4 | module demo.demo_mojo.mojom; 5 | 6 | // generic_pending_receiver 在新版中才有 7 | // import "mojo/public/mojom/base/generic_pending_receiver.mojom"; 8 | 9 | // interface Test4 { 10 | // TTTT(mojo_base.mojom.GenericPendingReceiver receiver); 11 | // }; 12 | 13 | interface InterfaceBroker { 14 | GetInterface(string name,handle pipe_handle); 15 | }; 16 | 17 | interface Interface1 { 18 | Hello(string who); 19 | }; 20 | 21 | interface Interface2 { 22 | Hi(string who); 23 | }; 24 | -------------------------------------------------------------------------------- /demo_mojo/mojom/test_service.mojom: -------------------------------------------------------------------------------- 1 | 2 | module demo.demo_mojo.mojom; 3 | 4 | // const string kServiceName = "testservice"; 5 | // const string kTestCapability = "test"; 6 | 7 | interface TestInterface { 8 | Hello(string who); 9 | }; 10 | 11 | interface RootInterface { 12 | Hi(string who); 13 | }; 14 | -------------------------------------------------------------------------------- /demo_mojo/mojom/test_service_manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test_service", 3 | "display_name": "Test Service", 4 | "interface_provider_specs": { 5 | "service_manager:connector": { 6 | "provides": { 7 | "test": ["demo.demo_mojo.mojom.TestInterface"] 8 | }, 9 | "requires": { 10 | "consumer_service":["root"] 11 | } 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /demo_mojo_v8/BUILD.gn: -------------------------------------------------------------------------------- 1 | import("//mojo/public/tools/bindings/mojom.gni") 2 | 3 | group("demo_mojo_v8") { 4 | # Please read the README file in 'demo_mojo_v8/' directory! 5 | } 6 | 7 | # 应用于渲染进程 8 | source_set("renderer"){ 9 | # 工具类只有头文件,声明在这里 10 | public = [ 11 | "v8/node_object_wrap.h", 12 | "v8/node_version.h", 13 | "v8/node.h", 14 | ] 15 | # 我们实现的全部源码 16 | sources =[ 17 | # Render部分 18 | "renderer/demo_render_frame_observer.cc", 19 | "renderer/demo_render_frame_observer.h", 20 | "renderer/demo_v8_binding.cc", 21 | "renderer/demo_v8_binding.h", 22 | ] 23 | # 依赖 24 | public_deps =[ 25 | ":mojom", 26 | ] 27 | deps = [ 28 | "//base", 29 | "//mojo/public:sdk", 30 | "//mojo/public/mojom/base", 31 | "//skia", 32 | "//v8", 33 | ] 34 | } 35 | 36 | # 应用于浏览器进程 37 | source_set("browser"){ 38 | # 我们实现的全部源码 39 | sources =[ 40 | # Browser部分 41 | "browser/demo_impl.h", 42 | "browser/demo_impl.cc", 43 | ] 44 | # 依赖 45 | public_deps =[ 46 | ":mojom", 47 | ] 48 | deps = [ 49 | "//base", 50 | "//mojo/public:sdk", 51 | "//mojo/public/mojom/base", 52 | ] 53 | } 54 | # mojom 55 | mojom("mojom") { 56 | sources = [ 57 | "mojom/demo.mojom", 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /demo_mojo_v8/README.md: -------------------------------------------------------------------------------- 1 | # demo_mojo_v8 2 | 3 | 这个 demo 主要演示了如何使用运行在 render 进程中的 js 代码,调用 browser 中的 mojo 接口。 4 | 5 | 如果希望用在 content_shell 中,只需要把下边的注入点替换到 content_shell 对应位置即可。 6 | 7 | 这里主要用到了 mojo 与 v8 相关知识。 8 | 9 | TODO: [PR Request] 添加 v8 相关 demo 演示如何用向 v8 中注入 js 对象/方法。 10 | 11 | ## 感谢 12 | 13 | 感谢飞书 @博博 大佬的支持,这个 demo 完全基于它的 demo 修改而成。 14 | 15 | ## 调用方向 16 | 17 | v8 js -> render -> mojo -> browser 18 | 19 | render 和 browser 通过自定义 mojo 接口进行通信。 20 | 21 | ## 使用方式 22 | 23 | 首先确保 `src` 仓库的分支为 `91.0.4472.*`,然后进入 `src` 目录下,使用以下命令应用 0002 号 patch `demo/patches/0002-demo_mojo_v8.patch`: 24 | 25 | ```sh 26 | git apply demo/patches/0002-demo_mojo_v8.patch 27 | ``` 28 | 29 | 然后编译 chrome: 30 | 31 | ```sh 32 | autoninja -C out/Default chrome 33 | ``` 34 | 35 | 最后使用使用编译好的 chrome 打开 `demo/demo_mojo_v8/test/index.html` 文件,观察页面控制台即可看到运行结果。 36 | -------------------------------------------------------------------------------- /demo_mojo_v8/browser/demo_impl.cc: -------------------------------------------------------------------------------- 1 | #include "demo/demo_mojo_v8/browser/demo_impl.h" 2 | #include "mojo/public/cpp/bindings/self_owned_receiver.h" 3 | 4 | namespace demo { 5 | namespace { 6 | void BindMojomImpl(mojo::PendingReceiver receiver) { 7 | mojo::MakeSelfOwnedReceiver(base::WrapUnique(new DemoImpl), 8 | std::move(receiver)); 9 | } 10 | } // namespace 11 | // 初始化,向BinderRegistry注册当前实例的工厂 12 | bool DemoImpl::Initialize(service_manager::BinderRegistry* registry) { 13 | registry->AddInterface(base::BindRepeating(&BindMojomImpl), 14 | base::SequencedTaskRunnerHandle::Get()); 15 | return true; 16 | } 17 | 18 | DemoImpl::DemoImpl() {} 19 | DemoImpl::~DemoImpl() {} 20 | 21 | // 实现Hello 22 | void DemoImpl::Hello(const std::string& who) { 23 | LOG(INFO) << "DemoImpl Call Hello:" << who; 24 | } 25 | } // namespace demo -------------------------------------------------------------------------------- /demo_mojo_v8/browser/demo_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/logging.h" 4 | #include "mojo/public/cpp/bindings/pending_receiver.h" 5 | #include "mojo/public/cpp/bindings/receiver.h" 6 | #include "services/service_manager/public/cpp/binder_registry.h" 7 | 8 | #include "demo/demo_mojo_v8/mojom/demo.mojom.h" 9 | namespace demo { 10 | 11 | // 实现Demo Mojom 12 | class DemoImpl : public demo::mojom::Demo { 13 | public: 14 | DemoImpl(); 15 | ~DemoImpl() override; 16 | 17 | // 初始化Receiver并注册到BinderRegisty中 18 | static bool Initialize(service_manager::BinderRegistry* registry); 19 | 20 | // 实现Mojo定义 21 | void Hello(const std::string& name) override; 22 | 23 | private: 24 | DISALLOW_COPY_AND_ASSIGN(DemoImpl); 25 | }; 26 | } // namespace demo 27 | -------------------------------------------------------------------------------- /demo_mojo_v8/mojom/demo.mojom: -------------------------------------------------------------------------------- 1 | module demo.mojom; 2 | 3 | interface Demo { 4 | Hello(string name); 5 | }; 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo_mojo_v8/renderer/demo_render_frame_observer.cc: -------------------------------------------------------------------------------- 1 | #include "demo/demo_mojo_v8/renderer/demo_render_frame_observer.h" 2 | #include "demo/demo_mojo_v8/renderer/demo_v8_binding.h" 3 | #include "content/public/renderer/render_frame.h" 4 | 5 | namespace demo { 6 | DemoRenderFrameObserver::DemoRenderFrameObserver( 7 | content::RenderFrame* render_frame) 8 | : content::RenderFrameObserver(render_frame), 9 | render_frame_(render_frame) {} 10 | 11 | DemoRenderFrameObserver::~DemoRenderFrameObserver() {} 12 | 13 | // content::RenderFrameObserver implementation 14 | void DemoRenderFrameObserver::DidCreateScriptContext( 15 | v8::Local context, 16 | int32_t world_id) { 17 | if (!render_frame_->IsMainFrame()) { 18 | return; 19 | } 20 | v8::Isolate* isolate = v8::Isolate::GetCurrent(); 21 | v8::Isolate::Scope isolate_scope(isolate); 22 | v8::HandleScope scope(isolate); 23 | v8::Context::Scope context_scope(context); 24 | 25 | // 初始化我们的V8实现,并绑定到当前作用域下 26 | DemoV8Binding::Initialize(isolate, context, context->Global()); 27 | } 28 | 29 | void DemoRenderFrameObserver::WillReleaseScriptContext( 30 | v8::Local context, 31 | int32_t world_id) {} 32 | 33 | void DemoRenderFrameObserver::OnDestruct() { 34 | delete this; 35 | } 36 | } // namespace demo -------------------------------------------------------------------------------- /demo_mojo_v8/renderer/demo_render_frame_observer.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include "content/public/renderer/render_frame_observer.h" 4 | 5 | namespace content { 6 | class RenderFrame; 7 | } 8 | 9 | namespace demo { 10 | class DemoRenderFrameObserver : public content::RenderFrameObserver { 11 | public: 12 | DemoRenderFrameObserver() = delete; 13 | 14 | explicit DemoRenderFrameObserver(content::RenderFrame* render_frame); 15 | ~DemoRenderFrameObserver() override; 16 | 17 | // content::RenderFrameObserver override 18 | void DidCreateScriptContext(v8::Local context, 19 | int32_t world_id) override; 20 | 21 | void WillReleaseScriptContext(v8::Local context, 22 | int32_t world_id) override; 23 | 24 | void OnDestruct() override; 25 | 26 | private: 27 | content::RenderFrame* render_frame_; 28 | DISALLOW_COPY_AND_ASSIGN(DemoRenderFrameObserver); 29 | }; 30 | } // namespace demo 31 | -------------------------------------------------------------------------------- /demo_mojo_v8/renderer/demo_v8_binding.cc: -------------------------------------------------------------------------------- 1 | #include "demo/demo_mojo_v8/renderer/demo_v8_binding.h" 2 | 3 | #include "content/public/renderer/render_thread.h" 4 | #include "demo/demo_mojo_v8/v8/node_version.h" 5 | #include "demo/demo_mojo_v8/v8/node.h" 6 | 7 | 8 | namespace { 9 | // 构造函数(Class) 的名称 10 | constexpr static const char* kClassName = "Demo"; 11 | 12 | inline demo::DemoV8Binding* GetSelfPointer(v8::Local handle) { 13 | return node::ObjectWrap::Unwrap(handle); 14 | } 15 | 16 | } // namespace 17 | 18 | namespace demo { 19 | 20 | DemoV8Binding::DemoV8Binding() : weak_ptr_factory_(this) { 21 | BindRemote(); 22 | } 23 | DemoV8Binding::~DemoV8Binding() { 24 | // Release Mojo 25 | } 26 | 27 | bool DemoV8Binding::Initialize(v8::Isolate* bind_isolate, 28 | v8::Local bind_context, 29 | v8::Local bind_parent_object) { 30 | v8::Local binding_settings_tempalte = 31 | v8::ObjectTemplate::New(bind_isolate); 32 | binding_settings_tempalte->SetInternalFieldCount(1); 33 | v8::Local object = 34 | binding_settings_tempalte->NewInstance(bind_context).ToLocalChecked(); 35 | // constructor 36 | v8::Local function_template = 37 | v8::FunctionTemplate::New(bind_isolate, V8New, object); 38 | function_template->SetClassName( 39 | v8::String::NewFromUtf8(bind_isolate, kClassName).ToLocalChecked()); 40 | v8::Local instance_template = 41 | function_template->InstanceTemplate(); 42 | instance_template->SetInternalFieldCount(1); 43 | 44 | // 进行属性绑定 45 | NODE_SET_PROTOTYPE_METHOD(function_template, "hello", V8Hello); 46 | 47 | v8::Local constructor = 48 | function_template->GetFunction(bind_context).ToLocalChecked(); 49 | object->SetInternalField(0, constructor); 50 | bind_parent_object 51 | ->Set(bind_context, 52 | v8::String::NewFromUtf8(bind_isolate, kClassName).ToLocalChecked(), 53 | constructor) 54 | .FromJust(); 55 | return true; 56 | } 57 | 58 | void DemoV8Binding::V8New(const v8::FunctionCallbackInfo& info) { 59 | v8::Isolate* isolate = info.GetIsolate(); 60 | 61 | if (!info.IsConstructCall()) { 62 | isolate->ThrowException(v8::Exception::TypeError( 63 | v8::String::NewFromUtf8(isolate, "Must invoke by new !") 64 | .ToLocalChecked())); 65 | return; 66 | } 67 | 68 | DemoV8Binding* pointer = new DemoV8Binding(); 69 | pointer->Wrap(info.This()); 70 | info.GetReturnValue().Set(info.This()); 71 | } 72 | 73 | void DemoV8Binding::V8Hello(const v8::FunctionCallbackInfo& info) { 74 | v8::Isolate* isolate = info.GetIsolate(); 75 | DCHECK(isolate); 76 | if ((info.Length() != 1) || !info[0]->IsString()) { 77 | isolate->ThrowException(v8::Exception::TypeError( 78 | v8::String::NewFromUtf8(isolate, "args number valid !") 79 | .ToLocalChecked())); 80 | return; 81 | } 82 | v8::String::Utf8Value utf8_value(isolate, info[0]); 83 | std::string utf8_string(*utf8_value); 84 | DemoV8Binding* self_pointer = GetSelfPointer(info.Holder()); 85 | DCHECK(self_pointer); 86 | self_pointer->Hello(utf8_string); 87 | } 88 | 89 | void DemoV8Binding::Hello(const std::string& message) { 90 | remote_->Hello(message); 91 | } 92 | 93 | // 绑定Remote 94 | bool DemoV8Binding::BindRemote() { 95 | if (remote_) { 96 | return false; 97 | } 98 | content::RenderThread::Get()->BindHostReceiver( 99 | remote_.BindNewPipeAndPassReceiver()); 100 | remote_.set_disconnect_handler(base::BindOnce( 101 | &DemoV8Binding::MojomDisconnected, weak_ptr_factory_.GetWeakPtr())); 102 | 103 | LOG(INFO) << "Binding Call BindRemote"; 104 | return true; 105 | } 106 | 107 | void DemoV8Binding::MojomDisconnected() {} 108 | 109 | } // namespace demo 110 | -------------------------------------------------------------------------------- /demo_mojo_v8/renderer/demo_v8_binding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "base/macros.h" 4 | #include "base/memory/weak_ptr.h" 5 | #include "base/sequenced_task_runner.h" 6 | #include "mojo/public/cpp/bindings/remote.h" 7 | #include "v8/include/v8.h" 8 | 9 | #include "demo/demo_mojo_v8/mojom/demo.mojom.h" 10 | #include "demo/demo_mojo_v8/v8/node_object_wrap.h" 11 | 12 | namespace demo { 13 | 14 | // 这是一个V8对象 15 | class DemoV8Binding : public node::ObjectWrap { 16 | public: 17 | static bool Initialize(v8::Isolate* bind_isolate, 18 | v8::Local bind_context, 19 | v8::Local bind_parent_object); 20 | 21 | private: 22 | static void V8New(const v8::FunctionCallbackInfo& info); 23 | static void V8Hello(const v8::FunctionCallbackInfo& info); 24 | 25 | private: 26 | explicit DemoV8Binding(); 27 | ~DemoV8Binding() override; 28 | 29 | void Hello(const std::string& name); 30 | bool BindRemote(); 31 | void MojomDisconnected(); 32 | 33 | private: 34 | SEQUENCE_CHECKER(sequence_checker_); 35 | mojo::Remote remote_; 36 | base::WeakPtrFactory weak_ptr_factory_; 37 | DISALLOW_COPY_AND_ASSIGN(DemoV8Binding); 38 | }; 39 | } // namespace demo -------------------------------------------------------------------------------- /demo_mojo_v8/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mojo实际应用测试页面 4 | 5 | 6 | 7 | 8 |

Mojo&V8在Chromiu中的应用Demo

9 |

10 | 再次感谢博佬 11 | 12 | 我们在页面加载完毕后,应该会在IDE的调试控制台中看到 13 | >> Binding Call BindRemote 14 | >> DemoImpl Call Hello:manonloki 15 |

16 | 20 | -------------------------------------------------------------------------------- /demo_mojo_v8/v8/node_object_wrap.h: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | #ifndef SRC_NODE_OBJECT_WRAP_H_ 23 | #define SRC_NODE_OBJECT_WRAP_H_ 24 | 25 | #include "v8.h" 26 | #include 27 | 28 | 29 | namespace node { 30 | 31 | class ObjectWrap { 32 | public: 33 | ObjectWrap() { 34 | refs_ = 0; 35 | } 36 | 37 | 38 | virtual ~ObjectWrap() { 39 | if (persistent().IsEmpty()) 40 | return; 41 | persistent().ClearWeak(); 42 | persistent().Reset(); 43 | } 44 | 45 | 46 | template 47 | static inline T* Unwrap(v8::Local handle) { 48 | assert(!handle.IsEmpty()); 49 | assert(handle->InternalFieldCount() > 0); 50 | // Cast to ObjectWrap before casting to T. A direct cast from void 51 | // to T won't work right when T has more than one base class. 52 | void* ptr = handle->GetAlignedPointerFromInternalField(0); 53 | ObjectWrap* wrap = static_cast(ptr); 54 | return static_cast(wrap); 55 | } 56 | 57 | 58 | inline v8::Local handle() { 59 | return handle(v8::Isolate::GetCurrent()); 60 | } 61 | 62 | 63 | inline v8::Local handle(v8::Isolate* isolate) { 64 | return v8::Local::New(isolate, persistent()); 65 | } 66 | 67 | 68 | // NOLINTNEXTLINE(runtime/v8_persistent) 69 | inline v8::Persistent& persistent() { 70 | return handle_; 71 | } 72 | 73 | 74 | protected: 75 | inline void Wrap(v8::Local handle) { 76 | assert(persistent().IsEmpty()); 77 | assert(handle->InternalFieldCount() > 0); 78 | handle->SetAlignedPointerInInternalField(0, this); 79 | persistent().Reset(v8::Isolate::GetCurrent(), handle); 80 | MakeWeak(); 81 | } 82 | 83 | 84 | inline void MakeWeak() { 85 | persistent().SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); 86 | } 87 | 88 | /* Ref() marks the object as being attached to an event loop. 89 | * Refed objects will not be garbage collected, even if 90 | * all references are lost. 91 | */ 92 | virtual void Ref() { 93 | assert(!persistent().IsEmpty()); 94 | persistent().ClearWeak(); 95 | refs_++; 96 | } 97 | 98 | /* Unref() marks an object as detached from the event loop. This is its 99 | * default state. When an object with a "weak" reference changes from 100 | * attached to detached state it will be freed. Be careful not to access 101 | * the object after making this call as it might be gone! 102 | * (A "weak reference" means an object that only has a 103 | * persistent handle.) 104 | * 105 | * DO NOT CALL THIS FROM DESTRUCTOR 106 | */ 107 | virtual void Unref() { 108 | assert(!persistent().IsEmpty()); 109 | assert(!persistent().IsWeak()); 110 | assert(refs_ > 0); 111 | if (--refs_ == 0) 112 | MakeWeak(); 113 | } 114 | 115 | int refs_; // ro 116 | 117 | private: 118 | static void WeakCallback( 119 | const v8::WeakCallbackInfo& data) { 120 | ObjectWrap* wrap = data.GetParameter(); 121 | assert(wrap->refs_ == 0); 122 | wrap->handle_.Reset(); 123 | delete wrap; 124 | } 125 | 126 | // NOLINTNEXTLINE(runtime/v8_persistent) 127 | v8::Persistent handle_; 128 | }; 129 | 130 | } // namespace node 131 | 132 | #endif // SRC_NODE_OBJECT_WRAP_H_ -------------------------------------------------------------------------------- /demo_resources/BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | # for demo_resources 3 | import("//tools/grit/grit_rule.gni") 4 | import("//tools/grit/repack.gni") 5 | 6 | executable("demo_resources") { 7 | sources = [ 8 | "demo_resources.cc", 9 | ] 10 | 11 | deps = [ 12 | ":demo_resources_pak", 13 | "//base", 14 | "//ui/base", 15 | # 因为使用了xxx_map.cc,因此需要添加对他们的直接依赖 16 | ":demo_resources_grit", 17 | ":demo_strings_grit", 18 | ] 19 | } 20 | 21 | grit("demo_resources_grit") { 22 | source = "demo_resources.grd" 23 | # 设置为""可以使用grd文件中的first_ids_file 24 | # resource_ids = "" 25 | resource_ids = "demo_resource_ids" 26 | outputs = [ 27 | "grit/demo_gen_resources.h", 28 | "grit/demo_gen_resources_map.h", 29 | "grit/demo_gen_resources_map.cc", 30 | "grit/demo_gen_resources_en.pak", 31 | "grit/demo_gen_resources_zh-CN.pak", 32 | "grit/demo_gen_resources_en.rc", 33 | "grit/demo_gen_resources_zh-CN.rc", 34 | "grit/demo_gen_resources_translateable_zh-CN.rc", 35 | "grit/demo_gen_resources_nontranslateable_zh-CN.rc", 36 | ] 37 | } 38 | 39 | grit("demo_strings_grit") { 40 | source = "demo_strings.grd" 41 | resource_ids = "demo_resource_ids" 42 | outputs = [ 43 | "grit/demo_gen_strings.h", 44 | "grit/demo_gen_strings_map.h", 45 | "grit/demo_gen_strings_map.cc", 46 | "grit/demo_gen_strings_en.pak", 47 | "grit/demo_gen_strings_zh-CN.pak", 48 | ] 49 | } 50 | 51 | repack("demo_resources_pak_en") { 52 | sources = [ 53 | "$root_gen_dir/demo/demo_resources/grit/demo_gen_resources_en.pak", 54 | "$root_gen_dir/demo/demo_resources/grit/demo_gen_strings_en.pak", 55 | ] 56 | output = "$root_gen_dir/demo/demo_resources/grit/demo_gen_pak_en.pak" 57 | deps = [ 58 | ":demo_resources_grit", 59 | ":demo_strings_grit", 60 | ] 61 | } 62 | 63 | repack("demo_resources_pak_zh-CN") { 64 | sources = [ 65 | "$root_gen_dir/demo/demo_resources/grit/demo_gen_resources_zh-CN.pak", 66 | "$root_gen_dir/demo/demo_resources/grit/demo_gen_strings_zh-CN.pak", 67 | ] 68 | output = "$root_gen_dir/demo/demo_resources/grit/demo_gen_pak_zh-CN.pak" 69 | deps = [ 70 | ":demo_resources_grit", 71 | ":demo_strings_grit", 72 | ] 73 | } 74 | 75 | group("demo_resources_pak") { 76 | deps = [ 77 | ":demo_resources_pak_en", 78 | ":demo_resources_pak_zh-CN", 79 | ] 80 | } -------------------------------------------------------------------------------- /demo_resources/demo_resource_ids: -------------------------------------------------------------------------------- 1 | { 2 | "SRCDIR": ".", 3 | # 31000之后的范围留给第三方,所以我们从31000开始 4 | "demo_resources.grd": { 5 | "messages": [31000], 6 | }, 7 | 8 | "demo_strings.grd": { 9 | "messages": [32000], 10 | }, 11 | } -------------------------------------------------------------------------------- /demo_resources/demo_resources.cc: -------------------------------------------------------------------------------- 1 | #include "base/at_exit.h" 2 | #include "base/command_line.h" 3 | #include "base/logging.h" 4 | #include "base/run_loop.h" 5 | #include "base/task/single_thread_task_executor.h" 6 | #include "base/path_service.h" 7 | #include "base/task/thread_pool/thread_pool_instance.h" 8 | 9 | #include 10 | 11 | // for resources 12 | #include "ui/base/l10n/l10n_util.h" 13 | #include "ui/base/resource/resource_bundle.h" 14 | #include "ui/base/ui_base_paths.h" 15 | 16 | // grit生成的头文件 17 | #include "demo/demo_resources/grit/demo_gen_resources.h" 18 | #include "demo/demo_resources/grit/demo_gen_resources_map.h" 19 | #include "demo/demo_resources/grit/demo_gen_strings.h" 20 | #include "demo/demo_resources/grit/demo_gen_strings_map.h" 21 | 22 | void LoadResources(base::StringPiece resource_file, bool use_strings = false) { 23 | // 因为InitSharedInstanceWithxxx只能执行一次,因此这里先清除之前的数据 24 | if (ui::ResourceBundle::HasSharedInstance()) 25 | ui::ResourceBundle::CleanupSharedInstance(); 26 | 27 | // 初始化locale,也就是本地化/语言资源包 28 | // 会导致代码去加载 29 | // chrome_100_percent.pak,chrome_200_percent.pak,locale/xxx.pak 30 | // 前2个资源如果不存在的,会报WARNING. 31 | // 最后一个资源我本机是有的,如果你本地没有会崩溃。 32 | // 这里传入了空的语言类型,因为在Linux/Android等系统上这个值是没有用的,代码会从系统获取语言类型 33 | // 具体逻辑见 l10n_util::GetApplicationLocaleInternal 34 | // 实际项目中应该使用这个进行初始化 35 | // ui::ResourceBundle::InitSharedInstanceWithLocale( 36 | // "", nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES); 37 | 38 | // 加载数据资源包 39 | base::FilePath resource_path; 40 | if (base::PathService::Get(base::DIR_MODULE, &resource_path)) 41 | resource_path = resource_path.AppendASCII(resource_file); 42 | ui::ResourceBundle::InitSharedInstanceWithPakPath(resource_path); 43 | 44 | ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); 45 | // 你也可以使用这个方法来加载其他的pak资源 46 | // SCALE_FATOR 47 | // 缩放因子,用来支持高分屏等情况,用户可以根据当前显示的情况选择使用拥有哪一个缩放因子的资源 48 | // 在初始化的时候,大多数情况会支持SCALE_FACTOR_100P和SCALE_FACTOR_200P,在IOS上还支持SCALE_FACTOR_300P 49 | // 具有相同ID并且SCALE_FATOR相同的资源只能有一个,否则会导致崩溃 50 | // bundle.AddDataPackFromPath(resource_path, ui::SCALE_FACTOR_NONE); 51 | 52 | std::cout << "Load: " << resource_file << std::endl; 53 | 54 | // 遍历demo_gen_resources.pak资源 55 | // text6会显示类似乱码的样子,因为grit使用了伪翻译,详见demo_resources.grd文件 56 | // 这里故意保持乱码以便读者注意这个问题 57 | for (size_t i = 0; i < kDemoGenResourcesSize; i++) { 58 | auto resource = kDemoGenResources[i]; 59 | 60 | std::cout << resource.path << ": [" 61 | << bundle.GetRawDataResource(resource.id) << "]" << std::endl; 62 | // 读取语言内容 63 | // 本来应该读不到的,因为语言资源包里没有这些资源,但是内部代码为了单元测试 64 | // 添加了failback到数据资源包的逻辑,所以这里也能读取出来数据资源 65 | // 注意我本机是有 locale/xxx.pak 文件的(因为编译过content_shell) 66 | std::cout << resource.path << ": [" 67 | << l10n_util::GetStringUTF16(resource.id) << "]" << std::endl; 68 | } 69 | if (use_strings) { 70 | std::cout << "------------------------------------------" << std::endl; 71 | // 遍历demo_gen_strings.pak资源 72 | for (size_t i = 0; i < kDemoGenStringsSize; i++) { 73 | auto resource = kDemoGenStrings[i]; 74 | std::cout << resource.path << ": [" 75 | << bundle.GetRawDataResource(resource.id) << "]" 76 | << std::endl; 77 | std::cout << resource.path << ": [" 78 | << l10n_util::GetStringUTF16(resource.id) << "]" 79 | << std::endl; 80 | } 81 | } 82 | std::cout << "==========================================" << std::endl; 83 | } 84 | 85 | int main(int argc, char** argv) { 86 | // 类似C++的 atexit() 方法,用于管理程序的销毁逻辑,base::Singleton类依赖它 87 | base::AtExitManager at_exit; 88 | // 初始化CommandLine 89 | base::CommandLine::Init(argc, argv); 90 | // 设置日志格式 91 | logging::SetLogItems(true, false, true, false); 92 | // 创建主消息循环 93 | base::SingleThreadTaskExecutor single_thread_task_executor; 94 | // 初始化线程池,会创建新的线程,在新的线程中会创建新消息循环MessageLoop 95 | base::ThreadPoolInstance::CreateAndStartWithDefaultParams("Demo"); 96 | 97 | // 提供 DIR_LOCALE 路径,用于寻找资源 98 | ui::RegisterPathProvider(); 99 | 100 | LoadResources("gen/demo/demo_resources/grit/demo_gen_resources_en.pak"); 101 | LoadResources("gen/demo/demo_resources/grit/demo_gen_resources_zh-CN.pak"); 102 | LoadResources("gen/demo/demo_resources/grit/demo_gen_pak_en.pak", true); 103 | LoadResources("gen/demo/demo_resources/grit/demo_gen_pak_zh-CN.pak", true); 104 | 105 | LOG(INFO) << "running..."; 106 | base::RunLoop().Run(); 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /demo_resources/demo_resources_zh-CN.xtb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | xtb:你好,文本2带有4个空格前缀。(use_name_for_id=true) 5 | xtb:你好,文本4。(可翻译) 6 | xtb:你好,文本5。这是第个文本。 7 | -------------------------------------------------------------------------------- /demo_resources/demo_strings.grd: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | strings_grd:Hello. 23 | 24 | 25 | strings_grd:Hi. 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /demo_resources/demo_strings_zh-CN.xtb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | strings_xtb:你好,Hello 5 | strings_xtb:你好,Hi 6 | 7 | -------------------------------------------------------------------------------- /demo_shell/README.md: -------------------------------------------------------------------------------- 1 | # demo_shell 2 | 3 | TODO: 完善 demo_shell 的文档。 4 | -------------------------------------------------------------------------------- /demo_shell/android/demo_shell_descriptors.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 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 | #ifndef DEMO_DEMO_SHELL_ANDROID_DEMO_SHELL_DESCRIPTORS_H_ 6 | #define DEMO_DEMO_SHELL_ANDROID_DEMO_SHELL_DESCRIPTORS_H_ 7 | 8 | #include "content/public/common/content_descriptors.h" 9 | 10 | // This is a list of global descriptor keys to be used with the 11 | // base::GlobalDescriptors object (see base/posix/global_descriptors.h) 12 | enum { 13 | kShellPakDescriptor = kContentIPCDescriptorMax + 1, 14 | kAndroidMinidumpDescriptor, 15 | }; 16 | 17 | #endif // DEMO_DEMO_SHELL_ANDROID_DEMO_SHELL_DESCRIPTORS_H_ -------------------------------------------------------------------------------- /demo_shell/android/demo_shell_library_loader.cc: -------------------------------------------------------------------------------- 1 | #include "base/android/jni_android.h" 2 | #include "content/public/app/content_jni_onload.h" 3 | #include "content/public/app/content_main.h" 4 | 5 | #include "base/android/base_jni_onload.h" 6 | #include "base/logging.h" 7 | 8 | #include "demo/demo_shell/app/demo_shell_content_main_delegate.h" 9 | 10 | JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { 11 | base::android::InitVM(vm); 12 | // JNIEnv* env = base::android::AttachCurrentThread(); 13 | // if (!RegisterMainDexNatives(env) || !RegisterNonMainDexNatives(env)) { 14 | // return -1; 15 | // } 16 | if (!content::android::OnJNIOnLoadInit()) 17 | return -1; 18 | content::SetContentMainDelegate(new content::DemoShellContentMainDelegate()); 19 | DLOG(INFO) << "======JNI_OnLoad finished"; 20 | return JNI_VERSION_1_4; 21 | } 22 | -------------------------------------------------------------------------------- /demo_shell/android/demo_shell_manager.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 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 "demo/demo_shell/android/demo_shell_manager.h" 6 | 7 | #include "base/android/jni_android.h" 8 | #include "base/android/jni_string.h" 9 | #include "base/android/scoped_java_ref.h" 10 | #include "base/bind.h" 11 | #include "base/lazy_instance.h" 12 | #include "content/public/browser/web_contents.h" 13 | 14 | #include "demo/demo_shell/browser/shell.h" 15 | #include "demo/demo_shell/browser/demo_shell_browser_context.h" 16 | #include "demo/demo_shell/browser/demo_shell_content_browser_client.h" 17 | #include "demo/demo_shell/android/demo_shell_jni_headers/ShellManager_jni.h" 18 | 19 | #include "url/gurl.h" 20 | 21 | using base::android::JavaParamRef; 22 | using base::android::JavaRef; 23 | using base::android::ScopedJavaLocalRef; 24 | 25 | namespace { 26 | 27 | struct GlobalState { 28 | GlobalState() {} 29 | base::android::ScopedJavaGlobalRef j_shell_manager; 30 | }; 31 | 32 | base::LazyInstance::DestructorAtExit g_global_state = 33 | LAZY_INSTANCE_INITIALIZER; 34 | 35 | } // namespace 36 | 37 | namespace content { 38 | 39 | ScopedJavaLocalRef CreateShellView(DemoShell* shell) { 40 | DLOG(INFO) << "============== CreateShellView"; 41 | 42 | JNIEnv* env = base::android::AttachCurrentThread(); 43 | return Java_ShellManager_createShell(env, 44 | g_global_state.Get().j_shell_manager, 45 | reinterpret_cast(shell)); 46 | } 47 | 48 | void RemoveShellView(const JavaRef& shell_view) { 49 | JNIEnv* env = base::android::AttachCurrentThread(); 50 | Java_ShellManager_removeShell(env, g_global_state.Get().j_shell_manager, 51 | shell_view); 52 | } 53 | 54 | static void JNI_ShellManager_Init(JNIEnv* env, 55 | const JavaParamRef& obj) { 56 | g_global_state.Get().j_shell_manager.Reset(obj); 57 | DLOG(INFO) << "============== JNI_ShellManager_Init"; 58 | } 59 | 60 | void JNI_ShellManager_LaunchShell(JNIEnv* env, 61 | const JavaParamRef& jurl) { 62 | DemoShellBrowserContext* browserContext = 63 | DemoShellContentBrowserClient::Get()->browser_context(); 64 | GURL url(base::android::ConvertJavaStringToUTF8(env, jurl)); 65 | DemoShell::CreateNewWindow(browserContext, 66 | url, 67 | nullptr, 68 | gfx::Size()); 69 | DLOG(INFO) << "============== JNI_ShellManager_LaunchShell"; 70 | 71 | } 72 | 73 | void DestroyShellManager() { 74 | JNIEnv* env = base::android::AttachCurrentThread(); 75 | Java_ShellManager_destroy(env, g_global_state.Get().j_shell_manager); 76 | DLOG(INFO) << "============== DestroyShellManager"; 77 | 78 | } 79 | 80 | } // namespace content 81 | -------------------------------------------------------------------------------- /demo_shell/android/demo_shell_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTENT_DEMO_SHELL_ANDROID_SHELL_MANAGER_H_ 2 | #define CONTENT_DEMO_SHELL_ANDROID_SHELL_MANAGER_H_ 3 | 4 | #include 5 | 6 | #include "base/android/jni_android.h" 7 | #include "base/android/scoped_java_ref.h" 8 | 9 | class DemoShell; 10 | 11 | namespace cc { 12 | class Layer; 13 | } 14 | 15 | namespace content { 16 | 17 | // Creates an Android specific shell view, which is our version of a shell 18 | // window. This view holds the controls and content views necessary to 19 | // render a shell window. Returns the java object representing the shell view. 20 | // object. 21 | base::android::ScopedJavaLocalRef CreateShellView(DemoShell* shell); 22 | 23 | // Removes a previously created shell view. 24 | void RemoveShellView(const base::android::JavaRef& shell_view); 25 | 26 | void ShellAttachLayer(cc::Layer* layer); 27 | void ShellRemoveLayer(cc::Layer* layer); 28 | 29 | // Destroys the ShellManager on app exit. Must not use the above functions 30 | // after this is called. 31 | void DestroyShellManager(); 32 | 33 | } // namespace content 34 | 35 | #endif // CONTENT_DEMO_SHELL_ANDROID_SHELL_MANAGER_H_ -------------------------------------------------------------------------------- /demo_shell/android/java/res/layout/shell_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 16 | 51 | 55 | -------------------------------------------------------------------------------- /demo_shell/android/java/res/mipmap-hdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_shell/android/java/res/mipmap-hdpi/app_icon.png -------------------------------------------------------------------------------- /demo_shell/android/java/res/mipmap-mdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_shell/android/java/res/mipmap-mdpi/app_icon.png -------------------------------------------------------------------------------- /demo_shell/android/java/res/mipmap-xhdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_shell/android/java/res/mipmap-xhdpi/app_icon.png -------------------------------------------------------------------------------- /demo_shell/android/java/res/mipmap-xxhdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_shell/android/java/res/mipmap-xxhdpi/app_icon.png -------------------------------------------------------------------------------- /demo_shell/android/java/res/mipmap-xxxhdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_shell/android/java/res/mipmap-xxxhdpi/app_icon.png -------------------------------------------------------------------------------- /demo_shell/android/java/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /demo_shell/android/java/src/org/chromium/demo_shell/ShellViewAndroidDelegate.java: -------------------------------------------------------------------------------- 1 | // Copyright 2017 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 | package org.chromium.demo_shell; 6 | 7 | import android.graphics.Bitmap; 8 | import android.view.ViewGroup; 9 | 10 | import org.chromium.ui.base.ViewAndroidDelegate; 11 | import org.chromium.ui_base.web.CursorType; 12 | 13 | /** 14 | * Implementation of the abstract class {@link ViewAndroidDelegate} for demo shell. 15 | * Extended for testing. 16 | */ 17 | public class ShellViewAndroidDelegate extends ViewAndroidDelegate { 18 | /** 19 | * An interface delegates a {@link CallbackHelper} for cursor update. see more in {@link 20 | * ContentViewPointerTypeTest.OnCursorUpdateHelperImpl}. 21 | */ 22 | public interface OnCursorUpdateHelper { 23 | /** 24 | * Record the last notifyCalled pointer type, see more {@link CallbackHelper#notifyCalled}. 25 | * @param type The pointer type of the notifyCalled. 26 | */ 27 | void notifyCalled(int type); 28 | } 29 | 30 | private OnCursorUpdateHelper mOnCursorUpdateHelper; 31 | 32 | public ShellViewAndroidDelegate(ViewGroup containerView) { 33 | super(containerView); 34 | } 35 | 36 | public void setOnCursorUpdateHelper(OnCursorUpdateHelper helper) { 37 | mOnCursorUpdateHelper = helper; 38 | } 39 | 40 | public OnCursorUpdateHelper getOnCursorUpdateHelper() { 41 | return mOnCursorUpdateHelper; 42 | } 43 | 44 | @Override 45 | public void onCursorChangedToCustom(Bitmap customCursorBitmap, int hotspotX, int hotspotY) { 46 | super.onCursorChangedToCustom(customCursorBitmap, hotspotX, hotspotY); 47 | if (mOnCursorUpdateHelper != null) { 48 | mOnCursorUpdateHelper.notifyCalled(CursorType.CUSTOM); 49 | } 50 | } 51 | 52 | @Override 53 | public void onCursorChanged(int cursorType) { 54 | super.onCursorChanged(cursorType); 55 | if (mOnCursorUpdateHelper != null) { 56 | mOnCursorUpdateHelper.notifyCalled(cursorType); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /demo_shell/android/shell_apk/res/layout/demo_shell_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /demo_shell/android/shell_apk/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | Initialization failed. 11 | 12 | -------------------------------------------------------------------------------- /demo_shell/android/shell_apk/src/org/chromium/demo_shell_apk/DemoShellApplication.java: -------------------------------------------------------------------------------- 1 | // Copyright 2012 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 | package org.chromium.demo_shell_apk; 6 | 7 | import android.app.Application; 8 | import android.content.Context; 9 | 10 | import org.chromium.base.ApplicationStatus; 11 | import org.chromium.base.BuildConfig; 12 | import org.chromium.base.CommandLine; 13 | import org.chromium.base.ContextUtils; 14 | import org.chromium.base.PathUtils; 15 | import org.chromium.base.multidex.ChromiumMultiDexInstaller; 16 | import org.chromium.ui.base.ResourceBundle; 17 | 18 | /** 19 | * Entry point for the demo shell application. Handles initialization of information that needs 20 | * to be shared across the main activity and the child services created. 21 | */ 22 | public class DemoShellApplication extends Application { 23 | public static final String COMMAND_LINE_FILE = "/data/local/tmp/content-shell-command-line"; 24 | private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "demo_shell"; 25 | 26 | @Override 27 | protected void attachBaseContext(Context base) { 28 | super.attachBaseContext(base); 29 | boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":"); 30 | ContextUtils.initApplicationContext(this); 31 | ResourceBundle.setNoAvailableLocalePaks(); 32 | if (isBrowserProcess) { 33 | if (BuildConfig.IS_MULTIDEX_ENABLED) { 34 | ChromiumMultiDexInstaller.install(this); 35 | } 36 | PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); 37 | ApplicationStatus.initialize(this); 38 | } 39 | } 40 | 41 | public void initCommandLine() { 42 | if (!CommandLine.isInitialized()) { 43 | CommandLine.initFromFile(COMMAND_LINE_FILE); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /demo_shell/app/demo_shell_content_main_delegate.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTENT_DEMO_SHELL_APP_DEMO_SHELL_CONTENT_MAIN_DELEGATE_H 2 | #define CONTENT_DEMO_SHELL_APP_DEMO_SHELL_CONTENT_MAIN_DELEGATE_H 3 | 4 | #include "content/public/app/content_main_delegate.h" 5 | #include "base/macros.h" 6 | #include "build/build_config.h" 7 | 8 | namespace content{ 9 | 10 | class ContentClient; 11 | class DemoShellContentBrowserClient; 12 | class ShellContentUtilityClient; 13 | class DemoShellContentRendererClient; 14 | 15 | class DemoShellContentMainDelegate : public content::ContentMainDelegate { 16 | public: 17 | 18 | DemoShellContentMainDelegate(); 19 | 20 | ~DemoShellContentMainDelegate() override; 21 | 22 | //基本的初始化工作完成,此时可以安全创建某些单例和检查命令行工作 23 | bool BasicStartupComplete(int* exit_code) override; 24 | 25 | //Sandbox启动前的逻辑,主要用于初始化User Data目录和PDF模块 26 | void PreSandboxStartup() override; 27 | 28 | // 用于请求embedder启动一个进程。 29 | int RunProcess( 30 | const std::string& process_type, 31 | const MainFunctionParams& main_function_params) override; 32 | 33 | #if defined(OS_LINUX) 34 | void ZygoteForked() override; 35 | #endif 36 | 37 | //如下函数由DemoContentMainRunnerImpl中的ContentClientInitializer调用 38 | ContentBrowserClient* CreateContentBrowserClient() override; 39 | ContentGpuClient* CreateContentGpuClient() override; 40 | ContentRendererClient* CreateContentRendererClient() override; 41 | ContentUtilityClient* CreateContentUtilityClient() override; 42 | 43 | static void InitializeResourceBundle(); 44 | 45 | private: 46 | 47 | std::unique_ptr browser_client_; 48 | std::unique_ptr gpu_client_; 49 | std::unique_ptr renderer_client_; 50 | std::unique_ptr utility_client_; 51 | std::unique_ptr content_client_; 52 | 53 | 54 | DISALLOW_COPY_AND_ASSIGN(DemoShellContentMainDelegate); 55 | 56 | }; 57 | 58 | } 59 | 60 | 61 | #endif //CONTENT_DEMO_SHELL_APP_DEMO_SHELL_MAIN_DELEGATE_H -------------------------------------------------------------------------------- /demo_shell/app/demo_shell_main.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "demo/demo_shell/app/demo_shell_content_main_delegate.h" 3 | #include "content/public/app/content_main.h" 4 | 5 | int main(int argc, const char** argv){ 6 | content::DemoShellContentMainDelegate demo_shell_content_delegate; 7 | content::ContentMainParams content_main_params(&demo_shell_content_delegate); 8 | content_main_params.argc = argc; 9 | content_main_params.argv = argv; 10 | content::ContentMain(content_main_params); 11 | } -------------------------------------------------------------------------------- /demo_shell/browser/demo_shell_browser_context.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | #ifndef CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_BROWSER_CONTEXT_H_ 6 | #define CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_BROWSER_CONTEXT_H_ 7 | 8 | #include 9 | 10 | #include "base/compiler_specific.h" 11 | #include "base/files/file_path.h" 12 | #include "base/macros.h" 13 | #include "base/memory/ref_counted.h" 14 | #include "content/public/browser/browser_context.h" 15 | #include "content/public/browser/content_browser_client.h" 16 | #include "content/public/browser/resource_context.h" 17 | #include "net/url_request/url_request_job_factory.h" 18 | 19 | namespace content { 20 | 21 | class BackgroundSyncController; 22 | class DownloadManagerDelegate; 23 | class PermissionControllerDelegate; 24 | class DemoShellDownloadManagerDelegate; 25 | class DemoShellPermissionManager; 26 | 27 | #if !defined(OS_ANDROID) 28 | class ZoomLevelDelegate; 29 | #endif // !defined(OS_ANDROID) 30 | 31 | class DemoShellBrowserContext : public BrowserContext { 32 | public: 33 | // If |delay_services_creation| is true, the owner is responsible for calling 34 | // CreateBrowserContextServices() for this BrowserContext. 35 | DemoShellBrowserContext(bool off_the_record, 36 | bool delay_services_creation = false); 37 | ~DemoShellBrowserContext() override; 38 | 39 | // BrowserContext implementation. 40 | base::FilePath GetPath() override; 41 | #if !defined(OS_ANDROID) 42 | std::unique_ptr CreateZoomLevelDelegate( 43 | const base::FilePath& partition_path) override; 44 | #endif // !defined(OS_ANDROID) 45 | bool IsOffTheRecord() override; 46 | DownloadManagerDelegate* GetDownloadManagerDelegate() override; 47 | ResourceContext* GetResourceContext() override; 48 | BrowserPluginGuestManager* GetGuestManager() override; 49 | storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override; 50 | PushMessagingService* GetPushMessagingService() override; 51 | StorageNotificationService* GetStorageNotificationService() override; 52 | SSLHostStateDelegate* GetSSLHostStateDelegate() override; 53 | PermissionControllerDelegate* GetPermissionControllerDelegate() override; 54 | ClientHintsControllerDelegate* GetClientHintsControllerDelegate() override; 55 | BackgroundFetchDelegate* GetBackgroundFetchDelegate() override; 56 | BackgroundSyncController* GetBackgroundSyncController() override; 57 | BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate() override; 58 | ContentIndexProvider* GetContentIndexProvider() override; 59 | 60 | protected: 61 | // Contains URLRequestContextGetter required for resource loading. 62 | class DemoShellResourceContext : public ResourceContext { 63 | public: 64 | DemoShellResourceContext(); 65 | ~DemoShellResourceContext() override; 66 | 67 | DISALLOW_COPY_AND_ASSIGN(DemoShellResourceContext); 68 | }; 69 | 70 | std::unique_ptr resource_context_; 71 | std::unique_ptr download_manager_delegate_; 72 | std::unique_ptr permission_manager_; 73 | std::unique_ptr background_sync_controller_; 74 | 75 | private: 76 | // Performs initialization of the ShellBrowserContext while IO is still 77 | // allowed on the current thread. 78 | void InitWhileIOAllowed(); 79 | 80 | bool off_the_record_; 81 | base::FilePath path_; 82 | 83 | DISALLOW_COPY_AND_ASSIGN(DemoShellBrowserContext); 84 | }; 85 | 86 | } // namespace content 87 | 88 | #endif // CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_BROWSER_CONTEXT_H_ 89 | -------------------------------------------------------------------------------- /demo_shell/browser/demo_shell_browser_main_parts.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_BROWSER_MAIN_PARTS_H_ 2 | #define CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_BROWSER_MAIN_PARTS_H_ 3 | 4 | #include "content/public/browser/browser_main_parts.h" 5 | #include "content/public/common/main_function_params.h" 6 | #include "base/macros.h" 7 | 8 | #include "demo/demo_shell/browser/demo_shell_browser_context.h" 9 | 10 | namespace content { 11 | 12 | class DemoShellBrowserMainParts : public BrowserMainParts { 13 | public: 14 | DemoShellBrowserMainParts(const MainFunctionParams& params); 15 | ~DemoShellBrowserMainParts() override; 16 | 17 | // BrowserMainParts overrides. 18 | int PreEarlyInitialization() override; 19 | int PreCreateThreads() override; 20 | void PreMainMessageLoopStart() override; 21 | void PostMainMessageLoopStart() override; 22 | void PreMainMessageLoopRun() override; 23 | bool MainMessageLoopRun(int* result_code) override; 24 | void PreDefaultMainMessageLoopRun(base::OnceClosure quit_closure) override; 25 | void PostMainMessageLoopRun() override; 26 | void PostDestroyThreads() override; 27 | 28 | DemoShellBrowserContext* browser_context() { 29 | return browser_context_.get(); 30 | } 31 | 32 | protected: 33 | virtual void InitializeBrowserContexts(); 34 | virtual void InitializeMessageLoopContext(); 35 | 36 | 37 | private: 38 | const MainFunctionParams main_function_params_; 39 | bool run_message_loop_; 40 | 41 | std::unique_ptr browser_context_; 42 | 43 | DISALLOW_COPY_AND_ASSIGN(DemoShellBrowserMainParts); 44 | }; 45 | 46 | } 47 | 48 | #endif //CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_BROWSER_MAIN_PARTS_H_ -------------------------------------------------------------------------------- /demo_shell/browser/demo_shell_content_browser_client.cc: -------------------------------------------------------------------------------- 1 | #include "demo/demo_shell/browser/demo_shell_content_browser_client.h" 2 | #include "demo/demo_shell/browser/demo_shell_browser_main_parts.h" 3 | #include "demo/demo_shell/browser/demo_shell_browser_context.h" 4 | 5 | 6 | namespace content{ 7 | 8 | DemoShellContentBrowserClient* g_demo_content_browser_client; 9 | DemoShellContentBrowserClient* DemoShellContentBrowserClient::Get(){ 10 | return g_demo_content_browser_client; 11 | } 12 | 13 | DemoShellContentBrowserClient::DemoShellContentBrowserClient() 14 | :demo_shell_browser_main_parts_(nullptr){ 15 | DCHECK(!g_demo_content_browser_client); 16 | g_demo_content_browser_client = this; 17 | } 18 | 19 | DemoShellContentBrowserClient::~DemoShellContentBrowserClient() { 20 | g_demo_content_browser_client = nullptr; 21 | } 22 | 23 | std::unique_ptr DemoShellContentBrowserClient::CreateBrowserMainParts( 24 | const MainFunctionParams& parameters) { 25 | auto parts = std::make_unique(parameters); 26 | demo_shell_browser_main_parts_ = parts.get(); 27 | return parts; 28 | } 29 | 30 | DemoShellBrowserContext* DemoShellContentBrowserClient::browser_context() { 31 | if(demo_shell_browser_main_parts_) { 32 | return demo_shell_browser_main_parts_->browser_context(); 33 | } 34 | return nullptr; 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /demo_shell/browser/demo_shell_content_browser_client.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_CONTENT_BROWSER_CLIENT_H_ 2 | #define CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_CONTENT_BROWSER_CLIENT_H_ 3 | 4 | #include "content/public/browser/content_browser_client.h" 5 | 6 | 7 | namespace content{ 8 | 9 | class DemoShellBrowserMainParts; 10 | class DemoShellBrowserContext; 11 | 12 | class DemoShellContentBrowserClient : public ContentBrowserClient { 13 | public: 14 | static DemoShellContentBrowserClient* Get(); 15 | 16 | DemoShellContentBrowserClient(); 17 | ~DemoShellContentBrowserClient() override; 18 | 19 | // ContentBrowserClient overrides. 20 | std::unique_ptr CreateBrowserMainParts( 21 | const MainFunctionParams& parameters) override; 22 | 23 | DemoShellBrowserContext* browser_context(); 24 | 25 | private: 26 | DemoShellBrowserMainParts* demo_shell_browser_main_parts_ = nullptr; 27 | 28 | }; 29 | 30 | } 31 | 32 | #endif //CONTENT_DEMO_SHELL_BROWSER_DEMO_SHELL_CONTENT_BROWSER_CLIENT_H_ -------------------------------------------------------------------------------- /demo_shell/browser/demo_shell_download_manager_delegate.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | #ifndef CONTENT_DEMO_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_ 6 | #define CONTENT_DEMO_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_ 7 | 8 | #include 9 | 10 | #include "base/callback_forward.h" 11 | #include "base/compiler_specific.h" 12 | #include "base/macros.h" 13 | #include "base/memory/weak_ptr.h" 14 | #include "content/public/browser/download_manager_delegate.h" 15 | 16 | namespace content { 17 | 18 | class DownloadManager; 19 | 20 | class DemoShellDownloadManagerDelegate : public DownloadManagerDelegate { 21 | public: 22 | DemoShellDownloadManagerDelegate(); 23 | ~DemoShellDownloadManagerDelegate() override; 24 | 25 | void SetDownloadManager(DownloadManager* manager); 26 | 27 | void Shutdown() override; 28 | bool DetermineDownloadTarget(download::DownloadItem* download, 29 | const DownloadTargetCallback& callback) override; 30 | bool ShouldOpenDownload(download::DownloadItem* item, 31 | const DownloadOpenDelayedCallback& callback) override; 32 | void GetNextId(const DownloadIdCallback& callback) override; 33 | 34 | private: 35 | friend class base::RefCountedThreadSafe; 36 | 37 | using FilenameDeterminedCallback = 38 | base::OnceCallback; 39 | 40 | static void GenerateFilename(const GURL& url, 41 | const std::string& content_disposition, 42 | const std::string& suggested_filename, 43 | const std::string& mime_type, 44 | const base::FilePath& suggested_directory, 45 | FilenameDeterminedCallback callback); 46 | void OnDownloadPathGenerated(uint32_t download_id, 47 | const DownloadTargetCallback& callback, 48 | const base::FilePath& suggested_path); 49 | void ChooseDownloadPath(uint32_t download_id, 50 | const DownloadTargetCallback& callback, 51 | const base::FilePath& suggested_path); 52 | 53 | DownloadManager* download_manager_; 54 | base::FilePath default_download_path_; 55 | bool suppress_prompting_; 56 | base::WeakPtrFactory weak_ptr_factory_{this}; 57 | 58 | DISALLOW_COPY_AND_ASSIGN(DemoShellDownloadManagerDelegate); 59 | }; 60 | 61 | } // namespace content 62 | 63 | #endif // CONTENT_DEMO_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_ 64 | -------------------------------------------------------------------------------- /demo_shell/browser/demo_shell_permission_manager.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 | #ifndef CONTENT_SHELL_BROWSER_SHELL_PERMISSION_MANAGER_H_ 6 | #define CONTENT_SHELL_BROWSER_SHELL_PERMISSION_MANAGER_H_ 7 | 8 | #include "base/callback_forward.h" 9 | #include "base/macros.h" 10 | #include "content/public/browser/permission_controller_delegate.h" 11 | 12 | namespace content { 13 | 14 | class DemoShellPermissionManager : public PermissionControllerDelegate { 15 | public: 16 | DemoShellPermissionManager(); 17 | ~DemoShellPermissionManager() override; 18 | 19 | // PermissionManager implementation. 20 | int RequestPermission(PermissionType permission, 21 | RenderFrameHost* render_frame_host, 22 | const GURL& requesting_origin, 23 | bool user_gesture, 24 | base::OnceCallback 25 | callback) override; 26 | int RequestPermissions( 27 | const std::vector& permission, 28 | RenderFrameHost* render_frame_host, 29 | const GURL& requesting_origin, 30 | bool user_gesture, 31 | base::OnceCallback< 32 | void(const std::vector&)> callback) 33 | override; 34 | void ResetPermission(PermissionType permission, 35 | const GURL& requesting_origin, 36 | const GURL& embedding_origin) override; 37 | blink::mojom::PermissionStatus GetPermissionStatus( 38 | PermissionType permission, 39 | const GURL& requesting_origin, 40 | const GURL& embedding_origin) override; 41 | blink::mojom::PermissionStatus GetPermissionStatusForFrame( 42 | content::PermissionType permission, 43 | content::RenderFrameHost* render_frame_host, 44 | const GURL& requesting_origin) override; 45 | int SubscribePermissionStatusChange( 46 | PermissionType permission, 47 | RenderFrameHost* render_frame_host, 48 | const GURL& requesting_origin, 49 | base::RepeatingCallback callback) 50 | override; 51 | void UnsubscribePermissionStatusChange(int subscription_id) override; 52 | 53 | private: 54 | DISALLOW_COPY_AND_ASSIGN(DemoShellPermissionManager); 55 | }; 56 | 57 | } // namespace content 58 | 59 | #endif // CONTENT_SHELL_BROWSER_SHELL_PERMISSION_MANAGER_H 60 | -------------------------------------------------------------------------------- /demo_shell/browser/demo_shell_platform_data_aura.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2014 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 "demo/demo_shell/browser/demo_shell_platform_data_aura.h" 6 | 7 | #include "base/macros.h" 8 | #include "build/build_config.h" 9 | #include "ui/aura/client/default_capture_client.h" 10 | #include "ui/aura/env.h" 11 | #include "ui/aura/layout_manager.h" 12 | #include "ui/aura/test/test_focus_client.h" 13 | #include "ui/aura/test/test_screen.h" 14 | #include "ui/aura/test/test_window_parenting_client.h" 15 | #include "ui/aura/window.h" 16 | #include "ui/aura/window_event_dispatcher.h" 17 | #include "ui/ozone/public/ozone_platform.h" 18 | #include "ui/platform_window/platform_window_init_properties.h" 19 | #include "ui/wm/core/default_activation_client.h" 20 | 21 | #if defined(USE_OZONE) 22 | #include "ui/aura/screen_ozone.h" 23 | #endif 24 | 25 | #include "demo/demo_shell/browser/shell.h" 26 | 27 | namespace content { 28 | 29 | namespace { 30 | 31 | class FillLayout : public aura::LayoutManager { 32 | public: 33 | explicit FillLayout(aura::Window* root) 34 | : root_(root), has_bounds_(!root->bounds().IsEmpty()) {} 35 | 36 | ~FillLayout() override {} 37 | 38 | private: 39 | // aura::LayoutManager: 40 | void OnWindowResized() override { 41 | // If window bounds were not set previously then resize all children to 42 | // match the size of the parent. 43 | if (!has_bounds_) { 44 | has_bounds_ = true; 45 | for (aura::Window* child : root_->children()) 46 | SetChildBoundsDirect(child, gfx::Rect(root_->bounds().size())); 47 | } 48 | } 49 | 50 | void OnWindowAddedToLayout(aura::Window* child) override { 51 | child->SetBounds(root_->bounds()); 52 | } 53 | 54 | void OnWillRemoveWindowFromLayout(aura::Window* child) override {} 55 | 56 | void OnWindowRemovedFromLayout(aura::Window* child) override {} 57 | 58 | void OnChildWindowVisibilityChanged(aura::Window* child, 59 | bool visible) override {} 60 | 61 | void SetChildBounds(aura::Window* child, 62 | const gfx::Rect& requested_bounds) override { 63 | SetChildBoundsDirect(child, requested_bounds); 64 | } 65 | 66 | aura::Window* root_; 67 | bool has_bounds_; 68 | 69 | DISALLOW_COPY_AND_ASSIGN(FillLayout); 70 | }; 71 | 72 | } 73 | 74 | DemoShellPlatformDataAura::DemoShellPlatformDataAura(const gfx::Size& initial_size) { 75 | CHECK(aura::Env::GetInstance()); 76 | 77 | #if defined(USE_OZONE) 78 | // Setup global display::Screen singleton. 79 | if (!display::Screen::GetScreen()) { 80 | screen_ = std::make_unique(); 81 | display::Screen::SetScreenInstance(screen_.get()); 82 | } 83 | #endif // defined(USE_OZONE) 84 | 85 | ui::PlatformWindowInitProperties properties; 86 | properties.bounds = gfx::Rect(initial_size); 87 | 88 | host_ = aura::WindowTreeHost::Create(std::move(properties)); 89 | host_->InitHost(); 90 | host_->window()->Show(); 91 | host_->window()->SetLayoutManager(new FillLayout(host_->window())); 92 | 93 | focus_client_.reset(new aura::test::TestFocusClient()); 94 | aura::client::SetFocusClient(host_->window(), focus_client_.get()); 95 | 96 | new wm::DefaultActivationClient(host_->window()); 97 | capture_client_.reset( 98 | new aura::client::DefaultCaptureClient(host_->window())); 99 | window_parenting_client_.reset( 100 | new aura::test::TestWindowParentingClient(host_->window())); 101 | } 102 | 103 | DemoShellPlatformDataAura::~DemoShellPlatformDataAura() { 104 | if (screen_) 105 | display::Screen::SetScreenInstance(nullptr); 106 | } 107 | 108 | void DemoShellPlatformDataAura::ShowWindow() { 109 | host_->Show(); 110 | } 111 | 112 | void DemoShellPlatformDataAura::ResizeWindow(const gfx::Size& size) { 113 | host_->SetBoundsInPixels(gfx::Rect(size)); 114 | } 115 | 116 | } // namespace content 117 | -------------------------------------------------------------------------------- /demo_shell/browser/demo_shell_platform_data_aura.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 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 | #ifndef CONTENT_DEMO_SHELL_BROWSER_SHELL_PLATFORM_DATA_AURA_H_ 6 | #define CONTENT_DEMO_SHELL_BROWSER_SHELL_PLATFORM_DATA_AURA_H_ 7 | 8 | #include 9 | 10 | #include "base/macros.h" 11 | #include "ui/aura/window_tree_host.h" 12 | 13 | namespace aura { 14 | namespace client { 15 | class DefaultCaptureClient; 16 | class FocusClient; 17 | class WindowParentingClient; 18 | } 19 | } 20 | 21 | namespace display { 22 | class Screen; 23 | } 24 | 25 | namespace gfx { 26 | class Size; 27 | } 28 | 29 | namespace content { 30 | 31 | class DemoShellPlatformDataAura { 32 | public: 33 | explicit DemoShellPlatformDataAura(const gfx::Size& initial_size); 34 | ~DemoShellPlatformDataAura(); 35 | 36 | void ShowWindow(); 37 | void ResizeWindow(const gfx::Size& size); 38 | 39 | aura::WindowTreeHost* host() { return host_.get(); } 40 | 41 | private: 42 | std::unique_ptr screen_; 43 | 44 | std::unique_ptr host_; 45 | std::unique_ptr focus_client_; 46 | std::unique_ptr capture_client_; 47 | std::unique_ptr window_parenting_client_; 48 | 49 | DISALLOW_COPY_AND_ASSIGN(DemoShellPlatformDataAura); 50 | }; 51 | 52 | } // namespace content 53 | 54 | #endif // CONTENT_DEMO_SHELL_BROWSER_SHELL_PLATFORM_DATA_AURA_H_ 55 | -------------------------------------------------------------------------------- /demo_shell/browser/shell_android.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 "demo/demo_shell/browser/shell.h" 6 | 7 | #include 8 | 9 | #include "base/android/jni_string.h" 10 | #include "base/android/scoped_java_ref.h" 11 | #include "base/command_line.h" 12 | #include "base/logging.h" 13 | #include "base/strings/string_piece.h" 14 | #include "content/public/browser/web_contents.h" 15 | #include "content/public/common/content_switches.h" 16 | 17 | #include "demo/demo_shell/android/demo_shell_jni_headers/Shell_jni.h" 18 | #include "demo/demo_shell/android/demo_shell_manager.h" 19 | 20 | using base::android::AttachCurrentThread; 21 | using base::android::ConvertUTF8ToJavaString; 22 | using base::android::JavaParamRef; 23 | using base::android::ScopedJavaLocalRef; 24 | 25 | namespace content { 26 | 27 | void DemoShell::PlatformInitialize(const gfx::Size& default_window_size) { 28 | DLOG(INFO) << "=========PlatformInitialize"; 29 | } 30 | 31 | void DemoShell::PlatformExit() { 32 | DLOG(INFO) << "=========PlatformExit"; 33 | 34 | DestroyShellManager(); 35 | } 36 | 37 | void DemoShell::PlatformCleanUp() { 38 | DLOG(INFO) << "=========PlatformCleanUp"; 39 | 40 | JNIEnv* env = AttachCurrentThread(); 41 | if (java_object_.is_null()) 42 | return; 43 | Java_Shell_onNativeDestroyed(env, java_object_); 44 | } 45 | 46 | void DemoShell::PlatformCreateWindow(int width, int height) { 47 | DLOG(INFO) << "=========PlatformCreateWindow"; 48 | 49 | java_object_.Reset(CreateShellView(this)); 50 | } 51 | 52 | void DemoShell::PlatformSetContents() { 53 | DLOG(INFO) << "=========PlatformSetContents"; 54 | 55 | JNIEnv* env = AttachCurrentThread(); 56 | Java_Shell_initFromNativeTabContents(env, java_object_, 57 | web_contents()->GetJavaWebContents()); 58 | } 59 | 60 | void DemoShell::SizeTo(const gfx::Size& content_size) { 61 | DLOG(INFO) << "=========SizeTo"; 62 | 63 | JNIEnv* env = AttachCurrentThread(); 64 | Java_Shell_sizeTo(env, java_object_, content_size.width(), 65 | content_size.height()); 66 | } 67 | 68 | 69 | // static 70 | void JNI_Shell_CloseShell(JNIEnv* env, 71 | jlong shellPtr) { 72 | DLOG(INFO) << "=========JNI_Shell_CloseShell"; 73 | 74 | // DemoShell* shell = reinterpret_cast(shellPtr); 75 | 76 | } 77 | 78 | } // namespace content 79 | -------------------------------------------------------------------------------- /demo_shell/common/demo_shell_content_client.cc: -------------------------------------------------------------------------------- 1 | #include "demo/demo_shell/common/demo_shell_content_client.h" 2 | 3 | #include "content/public/common/user_agent.h" 4 | #include "ui/base/l10n/l10n_util.h" 5 | #include "ui/base/resource/resource_bundle.h" 6 | #include "content/public/common/content_switches.h" 7 | #include "base/command_line.h" 8 | #include "base/values.h" 9 | 10 | namespace content{ 11 | 12 | DemoShellContentClient::DemoShellContentClient() = default; 13 | 14 | DemoShellContentClient::~DemoShellContentClient() = default; 15 | 16 | base::string16 DemoShellContentClient::GetLocalizedString(int message_id) { 17 | return l10n_util::GetStringUTF16(message_id); 18 | } 19 | 20 | base::StringPiece DemoShellContentClient::GetDataResource( 21 | int resource_id, 22 | ui::ScaleFactor scale_factor) { 23 | return ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale( 24 | resource_id, scale_factor); 25 | } 26 | 27 | base::RefCountedMemory* DemoShellContentClient::GetDataResourceBytes( 28 | int resource_id) { 29 | return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes( 30 | resource_id); 31 | } 32 | 33 | gfx::Image& DemoShellContentClient::GetNativeImageNamed(int resource_id){ 34 | return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( 35 | resource_id); 36 | } 37 | 38 | base::DictionaryValue DemoShellContentClient::GetNetLogConstants() { 39 | base::DictionaryValue client_constants; 40 | client_constants.SetString("name", "demo_shell"); 41 | client_constants.SetString( 42 | "command_line", 43 | base::CommandLine::ForCurrentProcess()->GetCommandLineString()); 44 | base::DictionaryValue constants; 45 | constants.SetKey("clientInfo", std::move(client_constants)); 46 | return constants; 47 | } 48 | 49 | blink::OriginTrialPolicy* DemoShellContentClient::GetOriginTrialPolicy(){ 50 | // return &origin_trial_policy_; 51 | return nullptr; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /demo_shell/common/demo_shell_content_client.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTENT_DEMO_SHELL_COMMON_DEMO_SHELL_CONTENT_CLIENT_H_ 2 | #define CONTENT_DEMO_SHELL_COMMON_DEMO_SHELL_CONTENT_CLIENT_H_ 3 | 4 | #include 5 | #include "content/public/common/content_client.h" 6 | #include "base/compiler_specific.h" 7 | // #include "demo_shell/common/demo_shell_origin_trial_policy.h" 8 | 9 | 10 | namespace content { 11 | std::string GetDemoShellUserAgent(); 12 | 13 | class DemoShellContentClient : public content::ContentClient { 14 | public: 15 | DemoShellContentClient(); 16 | ~DemoShellContentClient() override; 17 | 18 | base::string16 GetLocalizedString(int message_id) override; 19 | base::StringPiece GetDataResource( 20 | int resource_id, 21 | ui::ScaleFactor scale_factor) override; 22 | base::RefCountedMemory* GetDataResourceBytes( 23 | int resource_id) override; 24 | gfx::Image& GetNativeImageNamed(int resource_id) override; 25 | base::DictionaryValue GetNetLogConstants() override; 26 | blink::OriginTrialPolicy* GetOriginTrialPolicy() override; 27 | 28 | 29 | private: 30 | 31 | // DemoShellOriginTrialPolicy origin_trial_policy_; 32 | 33 | }; 34 | 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /demo_shell/common/demo_shell_origin_trial_policy.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 "demo/demo_shell/common/demo_shell_origin_trial_policy.h" 6 | 7 | #include "base/feature_list.h" 8 | #include "content/public/common/content_features.h" 9 | #include "content/public/common/origin_util.h" 10 | 11 | namespace content { 12 | 13 | namespace { 14 | 15 | // This is the public key which the content shell will use to enable origin 16 | // trial features. Trial tokens for use in layout tests can be created with the 17 | // tool in /tools/origin_trials/generate_token.py, using the private key 18 | // contained in /tools/origin_trials/eftest.key. 19 | static const uint8_t kOriginTrialPublicKey[] = { 20 | 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, 21 | 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, 22 | 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0, 23 | }; 24 | 25 | } // namespace 26 | 27 | DemoShellOriginTrialPolicy::DemoShellOriginTrialPolicy() 28 | : public_key_(base::StringPiece( 29 | reinterpret_cast(kOriginTrialPublicKey), 30 | arraysize(kOriginTrialPublicKey))) {} 31 | 32 | DemoShellOriginTrialPolicy::~DemoShellOriginTrialPolicy() {} 33 | 34 | bool DemoShellOriginTrialPolicy::IsOriginTrialsSupported() const { 35 | return base::FeatureList::IsEnabled(features::kOriginTrials); 36 | } 37 | 38 | base::StringPiece DemoShellOriginTrialPolicy::GetPublicKey() const { 39 | return public_key_; 40 | } 41 | 42 | bool DemoShellOriginTrialPolicy::IsOriginSecure(const GURL& url) const { 43 | return content::IsOriginSecure(url); 44 | } 45 | 46 | } // namespace content 47 | -------------------------------------------------------------------------------- /demo_shell/common/demo_shell_origin_trial_policy.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTENT_DEMO_SHELL_COMMON_DEMO_SHELL_ORIGIN_TRIAL_POLICY_H_ 2 | #define CONTENT_DEMO_SHELL_COMMON_DEMO_SHELL_ORIGIN_TRIAL_POLICY_H_ 3 | 4 | #include "third_party/blink/public/common/origin_trials/origin_trial_policy.h" 5 | #include "base/macros.h" 6 | #include "base/strings/string_piece.h" 7 | 8 | namespace content{ 9 | class DemoShellOriginTrialPolicy: public blink::OriginTrialPolicy{ 10 | public: 11 | DemoShellOriginTrialPolicy(); 12 | ~DemoShellOriginTrialPolicy() override; 13 | // blink::OriginTrialPolicy interface 14 | bool IsOriginTrialsSupported() const override; 15 | base::StringPiece GetPublicKey() const override; 16 | bool IsOriginSecure(const GURL& url) const override; 17 | 18 | private: 19 | base::StringPiece public_key_; 20 | 21 | DISALLOW_COPY_AND_ASSIGN(DemoShellOriginTrialPolicy); 22 | }; 23 | } 24 | 25 | #endif //CONTENT_DEMO_SHELL_COMMON_DEMO_SHELL_ORIGIN_TRIAL_POLICY_H_ -------------------------------------------------------------------------------- /demo_shell/common/demo_shell_switches.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 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 "demo/demo_shell/common/demo_shell_switches.h" 6 | 7 | #include "base/command_line.h" 8 | #include "base/strings/string_split.h" 9 | 10 | namespace switches { 11 | 12 | // Makes Content Shell use the given path for its data directory. 13 | const char kContentShellDataPath[] = "data-path"; 14 | 15 | // The directory breakpad should store minidumps in. 16 | const char kCrashDumpsDir[] = "crash-dumps-dir"; 17 | 18 | // Exposes the window.internals object to JavaScript for interactive development 19 | // and debugging of web tests that rely on it. 20 | const char kExposeInternalsForTesting[] = "expose-internals-for-testing"; 21 | 22 | // Registers additional font files on Windows (for fonts outside the usual 23 | // %WINDIR%\Fonts location). Multiple files can be used by separating them 24 | // with a semicolon (;). 25 | const char kRegisterFontFiles[] = "register-font-files"; 26 | 27 | // Size for the content_shell's host window (i.e. "800x600"). 28 | const char kContentShellHostWindowSize[] = "content-shell-host-window-size"; 29 | 30 | // Hides toolbar from content_shell's host window. 31 | const char kContentShellHideToolbar[] = "content-shell-hide-toolbar"; 32 | 33 | 34 | } // namespace switches 35 | -------------------------------------------------------------------------------- /demo_shell/common/demo_shell_switches.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 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 | // Defines all the "content_shell" command-line switches. 6 | 7 | #ifndef CONTENT_DEMO_SHELL_COMMON_SHELL_SWITCHES_H_ 8 | #define CONTENT_DEMO_SHELL_COMMON_SHELL_SWITCHES_H_ 9 | 10 | #include 11 | #include 12 | 13 | namespace switches { 14 | 15 | extern const char kContentShellDataPath[]; 16 | extern const char kCrashDumpsDir[]; 17 | extern const char kExposeInternalsForTesting[]; 18 | extern const char kRegisterFontFiles[]; 19 | extern const char kContentShellHostWindowSize[]; 20 | extern const char kContentShellHideToolbar[]; 21 | 22 | 23 | } // namespace switches 24 | 25 | #endif // CONTENT_DEMO_SHELL_COMMON_SHELL_SWITCHES_H_ 26 | -------------------------------------------------------------------------------- /demo_shell/demo_shell_resources.grd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /demo_shell/renderer/demo_shell_content_renderer_client.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 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 "demo/demo_shell/renderer/demo_shell_content_renderer_client.h" 6 | 7 | #include 8 | 9 | #include "base/bind.h" 10 | #include "base/command_line.h" 11 | #include "base/logging.h" 12 | #include "base/macros.h" 13 | #include "base/strings/string_number_conversions.h" 14 | #include "components/cdm/renderer/external_clear_key_key_system_properties.h" 15 | #include "components/web_cache/renderer/web_cache_impl.h" 16 | #include "content/public/child/child_thread.h" 17 | #include "content/public/common/service_manager_connection.h" 18 | #include "mojo/public/cpp/bindings/pending_receiver.h" 19 | #include "mojo/public/cpp/bindings/receiver.h" 20 | #include "mojo/public/cpp/system/message_pipe.h" 21 | #include "net/base/net_errors.h" 22 | #include "ppapi/buildflags/buildflags.h" 23 | #include "services/service_manager/public/cpp/binder_registry.h" 24 | #include "third_party/blink/public/platform/web_url_error.h" 25 | #include "third_party/blink/public/web/web_testing_support.h" 26 | #include "third_party/blink/public/web/web_view.h" 27 | #include "v8/include/v8.h" 28 | 29 | #if BUILDFLAG(ENABLE_PLUGINS) 30 | #include "ppapi/shared_impl/ppapi_switches.h" // nogncheck 31 | #endif 32 | 33 | #if BUILDFLAG(ENABLE_MOJO_CDM) 34 | #include "base/feature_list.h" 35 | #include "media/base/media_switches.h" 36 | #endif 37 | 38 | namespace content { 39 | 40 | DemoShellContentRendererClient::DemoShellContentRendererClient() {} 41 | 42 | DemoShellContentRendererClient::~DemoShellContentRendererClient() { 43 | } 44 | 45 | void DemoShellContentRendererClient::RenderThreadStarted() { 46 | LOG(WARNING)<<"DemoShellContentRendererClient::RenderThreadStarted"; 47 | } 48 | 49 | void DemoShellContentRendererClient::ExposeInterfacesToBrowser(mojo::BinderMap* binders) { 50 | DVLOG(2)<<"DemoShellContentRendererClient::ExposeInterfacesToBrowser"; 51 | } 52 | 53 | void DemoShellContentRendererClient::RenderViewCreated(RenderView* render_view) { 54 | // new ShellRenderViewObserver(render_view); 55 | LOG(WARNING)<<"DemoShellContentRendererClient::RenderViewCreated"; 56 | 57 | } 58 | 59 | bool DemoShellContentRendererClient::HasErrorPage(int http_status_code) { 60 | LOG(WARNING)<<"DemoShellContentRendererClient::HasErrorPage"; 61 | return http_status_code >= 400 && http_status_code < 600; 62 | } 63 | 64 | void DemoShellContentRendererClient::PrepareErrorPage( 65 | RenderFrame* render_frame, 66 | const blink::WebURLError& error, 67 | const std::string& http_method, 68 | std::string* error_html) { 69 | LOG(WARNING)<<"DemoShellContentRendererClient::PrepareErrorPage"; 70 | if (error_html && error_html->empty()) { 71 | *error_html = 72 | "ErrorCould not load the requested " 73 | "resource.
Error code: " + 74 | base::NumberToString(error.reason()) + 75 | (error.reason() < 0 ? " (" + net::ErrorToString(error.reason()) + ")" 76 | : "") + 77 | ""; 78 | } 79 | } 80 | 81 | void DemoShellContentRendererClient::PrepareErrorPageForHttpStatusError( 82 | content::RenderFrame* render_frame, 83 | const GURL& unreachable_url, 84 | const std::string& http_method, 85 | int http_status, 86 | std::string* error_html) { 87 | LOG(WARNING)<<"DemoShellContentRendererClient::PrepareErrorPageForHttpStatusError"; 88 | if (error_html) { 89 | *error_html = 90 | "ErrorServer returned HTTP status " + 91 | base::NumberToString(http_status) + ""; 92 | } 93 | } 94 | 95 | bool DemoShellContentRendererClient::IsPluginAllowedToUseDevChannelAPIs() { 96 | LOG(WARNING)<<"DemoShellContentRendererClient::IsPluginAllowedToUseDevChannelAPIs"; 97 | return false; 98 | } 99 | 100 | void DemoShellContentRendererClient::DidInitializeWorkerContextOnWorkerThread( 101 | v8::Local context) { 102 | LOG(WARNING)<<"DemoShellContentRendererClient::DidInitializeWorkerContextOnWorkerThread"; 103 | } 104 | 105 | } // namespace content 106 | -------------------------------------------------------------------------------- /demo_shell/renderer/demo_shell_content_renderer_client.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 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 | #ifndef CONTENT_SHELL_RENDERER_SHELL_CONTENT_RENDERER_CLIENT_H_ 6 | #define CONTENT_SHELL_RENDERER_SHELL_CONTENT_RENDERER_CLIENT_H_ 7 | 8 | #include 9 | #include 10 | 11 | #include "base/compiler_specific.h" 12 | #include "build/build_config.h" 13 | #include "content/public/renderer/content_renderer_client.h" 14 | #include "media/mojo/buildflags.h" 15 | 16 | namespace web_cache { 17 | class WebCacheImpl; 18 | } 19 | 20 | namespace content { 21 | 22 | class DemoShellContentRendererClient : public ContentRendererClient { 23 | public: 24 | DemoShellContentRendererClient(); 25 | ~DemoShellContentRendererClient() override; 26 | 27 | // ContentRendererClient implementation. 28 | void RenderThreadStarted() override; 29 | void ExposeInterfacesToBrowser(mojo::BinderMap* binders) override; 30 | void RenderViewCreated(RenderView* render_view) override; 31 | bool HasErrorPage(int http_status_code) override; 32 | void PrepareErrorPage(RenderFrame* render_frame, 33 | const blink::WebURLError& error, 34 | const std::string& http_method, 35 | std::string* error_html) override; 36 | void PrepareErrorPageForHttpStatusError(content::RenderFrame* render_frame, 37 | const GURL& unreachable_url, 38 | const std::string& http_method, 39 | int http_status, 40 | std::string* error_html) override; 41 | 42 | // TODO(mkwst): These toggle based on the kEnablePepperTesting flag. Do we 43 | // need that outside of web tests? 44 | bool IsPluginAllowedToUseDevChannelAPIs() override; 45 | 46 | void DidInitializeWorkerContextOnWorkerThread( 47 | v8::Local context) override; 48 | 49 | }; 50 | 51 | } // namespace content 52 | 53 | #endif // CONTENT_SHELL_RENDERER_SHELL_CONTENT_RENDERER_CLIENT_H_ 54 | -------------------------------------------------------------------------------- /demo_shell/resource_ids: -------------------------------------------------------------------------------- 1 | { 2 | "SRCDIR": ".", 3 | # 31000之后的范围留给第三方,所以我们从31000开始 4 | "demo_shell_resources.grd": { 5 | "includes": [31000], 6 | }, 7 | 8 | } -------------------------------------------------------------------------------- /demo_shell/resources/README.txt: -------------------------------------------------------------------------------- 1 | missingImage.gif was created from Webkit data: WebCore/Resources/missingImage.tiff 2 | 3 | Licence text for missingImage.tiff from which missingImage.gif was generated: 4 | 5 | Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | missingImage.png is the same as WebCore/Resources/missingImage.png and carries exactly the same license. 27 | -------------------------------------------------------------------------------- /demo_shell/resources/brokenCanvas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/demo_shell/resources/brokenCanvas.png -------------------------------------------------------------------------------- /demo_shell/resources/shell_devtools_discovery_page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Content shell remote debugging 4 | 6 | 7 | 49 | 50 | 51 |
Inspectable WebContents
52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /demo_shell/utility/demo_shell_content_utility_client.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 | #ifndef CONTENT_DEMO_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_ 6 | #define CONTENT_DEMO_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_ 7 | 8 | #include "base/macros.h" 9 | #include "content/public/test/audio_service_test_helper.h" 10 | #include "content/public/test/network_service_test_helper.h" 11 | #include "content/public/utility/content_utility_client.h" 12 | 13 | namespace content { 14 | 15 | class DemoShellContentUtilityClient : public ContentUtilityClient { 16 | public: 17 | explicit DemoShellContentUtilityClient(); 18 | ~DemoShellContentUtilityClient() override; 19 | 20 | // ContentUtilityClient: 21 | 22 | private: 23 | 24 | 25 | DISALLOW_COPY_AND_ASSIGN(DemoShellContentUtilityClient); 26 | }; 27 | 28 | } // namespace content 29 | 30 | #endif // CONTENT_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_ 31 | -------------------------------------------------------------------------------- /demo_shell/version.h.in: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_WEBVIEW_VERSION_H_ 2 | #define DEMO_WEBVIEW_VERSION_H_ 3 | 4 | #define DEMO_WEBVIEW_VERSION "@VERSION_FULL@" 5 | 6 | #endif // DEMO_WEBVIEW_VERSION_H_ -------------------------------------------------------------------------------- /demo_skia/BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | import("//build/config/ui.gni") 3 | 4 | executable("demo_skia") { 5 | testonly = true 6 | 7 | sources = [ 8 | "demo_skia.cc", 9 | "skia_canvas.cc", 10 | "skia_canvas.h", 11 | "skia_canvas_gl.cc", 12 | "skia_canvas_gl.h", 13 | "skia_canvas_software.cc", 14 | "skia_canvas_software.h", 15 | ] 16 | 17 | deps = [ 18 | "//base", 19 | "//base:i18n", 20 | "//gpu", 21 | "//gpu:gles2", 22 | "//gpu:raster", 23 | "//gpu/command_buffer/client", 24 | "//gpu/command_buffer/client:gles2_cmd_helper", 25 | "//gpu/command_buffer/service", 26 | "//gpu/command_buffer/service:gles2", 27 | "//ui/base", 28 | "//ui/gl", 29 | "//ui/gl/init", 30 | "//ui/events", 31 | "//ui/events/platform", 32 | "//ui/platform_window", 33 | # 直接依赖它会导致和chromium中的变量定义冲突 34 | #"//third_party/skia", 35 | "//skia", 36 | ] 37 | 38 | if (ozone_platform_x11) { 39 | deps += [ 40 | "//ui/events/platform/x11", 41 | "//ui/ozone", 42 | "//ui/base/x", 43 | ] 44 | #configs += [ "//build/config/linux:x11" ] 45 | } 46 | 47 | libs = ["EGL","GLESv2"] 48 | } 49 | -------------------------------------------------------------------------------- /demo_skia/README.md: -------------------------------------------------------------------------------- 1 | # demo_skia 2 | 3 | demo_skia 用于演示在 Linux 系统上使用 Skia 进行软件/硬件渲染。它会创建一个半透明的窗口,你可以用鼠标在上面进行绘画。 4 | 5 | ```c++ 6 | ./out/Default/demo_skia --gl // 使用 GLES2 进行渲染。 7 | ./out/Default/demo_skia // 使用 Software 进行渲染。 8 | ``` 9 | -------------------------------------------------------------------------------- /demo_skia/skia_canvas.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_DEMO_SKIA_SKIA_CANVAS_H 2 | #define DEMO_DEMO_SKIA_SKIA_CANVAS_H 3 | 4 | #include "base/threading/thread.h" 5 | #include "base/timer/timer.h" 6 | #include "third_party/skia/include/core/SkBitmap.h" 7 | #include "third_party/skia/include/core/SkCanvas.h" 8 | #include "third_party/skia/include/core/SkPath.h" 9 | #include "third_party/skia/include/core/SkSurface.h" 10 | #include "ui/gfx/native_widget_types.h" 11 | 12 | namespace demo_jni { 13 | 14 | class SkiaCanvas { 15 | public: 16 | void OnTouch(int action, float x, float y); 17 | virtual ~SkiaCanvas(); 18 | virtual void Resize(int width, int height) {} 19 | 20 | protected: 21 | SkiaCanvas(gfx::AcceleratedWidget widget,int width,int height); 22 | virtual void InitializeOnRenderThread(); 23 | virtual SkCanvas* BeginPaint() = 0; 24 | virtual void OnPaint(SkCanvas* canvas) {} 25 | virtual void SwapBuffer() = 0; 26 | void SetNeedsRedraw(bool need_redraw); 27 | void ShowInfo(std::string info); 28 | 29 | gfx::AcceleratedWidget nativeWindow_; 30 | int width_; 31 | int height_; 32 | base::Thread render_thread_; 33 | scoped_refptr render_task_runner_; 34 | 35 | sk_sp skSurface_ = nullptr; 36 | SkPaint pathPaint_; 37 | SkPaint circlePaint_; 38 | SkPath skPath_; 39 | SkScalar strokeWidth_ = 5.f; 40 | SkColor background_ = SK_ColorBLACK; 41 | std::string tag_; 42 | bool need_redraw_ = false; 43 | bool is_drawing_ = false; 44 | base::TimeDelta total_frame_time_; 45 | base::TimeTicks last_frame_time_; 46 | unsigned int frame_count_ = 0; 47 | base::TimeDelta total_paint_time_; 48 | base::TimeDelta total_swap_time_; 49 | 50 | unsigned int touch_count_ = 0; 51 | base::TimeTicks touch_start_time_; 52 | base::TimeDelta total_touch_time_; 53 | 54 | private: 55 | void OnTouchOnRenderThread(int action, float x, float y); 56 | void OnRenderOnRenderThread(); 57 | void ShowFrameRateOnRenderThread(); 58 | base::RepeatingTimer timer_; 59 | base::RepeatingClosure render_closure_; 60 | base::WeakPtrFactory weak_factory_{this}; 61 | }; 62 | 63 | } // namespace demo_jni 64 | 65 | #endif // DEMO_DEMO_SKIA_SKIA_CANVAS_H 66 | -------------------------------------------------------------------------------- /demo_skia/skia_canvas_gl.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_DEMO_SKIA_SKIA_CANVAS_GL_H 2 | #define DEMO_DEMO_SKIA_SKIA_CANVAS_GL_H 3 | 4 | #include 5 | #include 6 | #ifndef GL_GLEXT_PROTOTYPES 7 | #define GL_GLEXT_PROTOTYPES 8 | #endif 9 | // Chromium 在 gpu/GLES2/gl2chromium_autogen.h 中重定义了所有的 gles2 的方法 10 | // 到 GLES2xxx,这样来对接 command buffer,我们不需要使用 command buffer,因此 11 | // 使用绝对路径绕过这个逻辑 12 | //#include 13 | #include 14 | 15 | #include "demo/demo_skia/skia_canvas.h" 16 | 17 | // #include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h" 18 | #include "third_party/skia/include/core/SkSurface.h" 19 | #include "third_party/skia/include/gpu/GrDirectContext.h" 20 | #include "third_party/skia/include/gpu/gl/GrGLInterface.h" 21 | #include "third_party/skia/include/private/chromium/GrDeferredDisplayListRecorder.h" 22 | 23 | namespace demo_jni { 24 | 25 | class SkiaCanvasGL : public SkiaCanvas { 26 | public: 27 | SkiaCanvasGL(gfx::AcceleratedWidget widget,int width,int height); 28 | void Resize(int width, int height) override; 29 | 30 | ~SkiaCanvasGL() override; 31 | 32 | private: 33 | void InitializeOnRenderThread() override; 34 | SkCanvas* BeginPaint() override; 35 | void OnPaint(SkCanvas* canvas) override; 36 | void SwapBuffer() override; 37 | 38 | EGLDisplay display_; 39 | EGLContext context_; 40 | EGLSurface surface_; 41 | EGLint stencilBits_; 42 | EGLint sampleCount_; 43 | GLenum color_format_; 44 | sk_sp grGLInterface_; 45 | sk_sp grContext_; 46 | bool use_ddl_ = false; 47 | std::unique_ptr recorder_; 48 | }; 49 | 50 | } // namespace demo_jni 51 | 52 | #endif // DEMO_DEMO_SKIA_SKIA_CANVAS_GL_H 53 | -------------------------------------------------------------------------------- /demo_skia/skia_canvas_software.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "demo/demo_skia/skia_canvas_software.h" 3 | 4 | #include "base/trace_event/trace_event.h" 5 | #include "ui/gfx/x/connection.h" 6 | 7 | namespace demo_jni { 8 | 9 | SkiaCanvasSoftware::SkiaCanvasSoftware(gfx::AcceleratedWidget widget,int width,int height) 10 | : SkiaCanvas(widget, width, height) { 11 | background_ = 0x8800DE96; 12 | tag_ = "SkiaCanvasSoftware"; 13 | } 14 | 15 | SkiaCanvasSoftware::~SkiaCanvasSoftware() = default; 16 | 17 | void SkiaCanvasSoftware::InitializeOnRenderThread() { 18 | TRACE_EVENT0("shell", "SkiaCanvasSoftware::InitializeOnRenderThread"); 19 | x11_presenter_ = std::make_unique( 20 | x11::Connection::Get(), nativeWindow_, true); 21 | 22 | // 当 format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4 23 | // 时,一个像素占2个字节,所以x2 24 | // memset(buffer.bits, 0xAA, buffer.stride * buffer.height * 2); 25 | auto* canvas = BeginPaint(); 26 | canvas->clear(background_); 27 | //canvas->drawCircle(20, 20, 20, circlePaint_); 28 | OnPaint(canvas); 29 | SwapBuffer(); 30 | SkiaCanvas::InitializeOnRenderThread(); 31 | } 32 | 33 | void SkiaCanvasSoftware::Resize(int width, int height) { 34 | width_ = width; 35 | height_ = height; 36 | } 37 | 38 | SkCanvas* SkiaCanvasSoftware::BeginPaint() { 39 | x11_presenter_->Resize(gfx::Size(width_, height_)); 40 | return x11_presenter_->GetSkCanvas(); 41 | } 42 | 43 | void SkiaCanvasSoftware::OnPaint(SkCanvas* canvas) { 44 | x11_presenter_->EndPaint(gfx::Rect(width_,height_)); 45 | } 46 | 47 | void SkiaCanvasSoftware::SwapBuffer() { 48 | x11_presenter_->OnSwapBuffers(base::BindOnce([](const gfx::Size&){})); 49 | } 50 | 51 | } // namespace demo_jni 52 | -------------------------------------------------------------------------------- /demo_skia/skia_canvas_software.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_DEMO_SKIA_SKIA_CANVAS_SOFTWARE_H 2 | #define DEMO_DEMO_SKIA_SKIA_CANVAS_SOFTWARE_H 3 | 4 | #include "demo/demo_skia/skia_canvas.h" 5 | 6 | #include "ui/base/x/x11_software_bitmap_presenter.h" 7 | 8 | namespace demo_jni { 9 | 10 | class SkiaCanvasSoftware : public SkiaCanvas { 11 | public: 12 | SkiaCanvasSoftware(gfx::AcceleratedWidget widget,int width,int height); 13 | ~SkiaCanvasSoftware() override; 14 | void InitializeOnRenderThread() override; 15 | void Resize(int width, int height) override; 16 | void OnPaint(SkCanvas* canvas) override; 17 | 18 | private: 19 | SkCanvas* BeginPaint() override; 20 | void SwapBuffer() override; 21 | 22 | std::unique_ptr x11_presenter_; 23 | }; 24 | 25 | } // namespace demo_jni 26 | 27 | #endif // DEMO_DEMO_SKIA_SKIA_CANVAS_SOFTWARE_H 28 | -------------------------------------------------------------------------------- /demo_task/BUILD.gn: -------------------------------------------------------------------------------- 1 | group("demo_task"){ 2 | testonly = true 3 | deps =[ 4 | ":demo_task_executor", 5 | ":demo_task_thread_pool", 6 | ":demo_task_thread", 7 | ] 8 | } 9 | 10 | executable("demo_task_executor"){ 11 | sources = [ 12 | "demo_task_executor.cc" 13 | ] 14 | deps = [ 15 | "//base", 16 | ] 17 | } 18 | 19 | executable("demo_task_thread_pool"){ 20 | sources = [ 21 | "demo_task_thread_pool.cc" 22 | ] 23 | 24 | deps = [ 25 | "//base", 26 | ] 27 | } 28 | 29 | executable("demo_task_thread"){ 30 | sources = [ 31 | "demo_task_thread.cc" 32 | ] 33 | 34 | deps = [ 35 | "//base", 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /demo_task/demo_task_executor.cc: -------------------------------------------------------------------------------- 1 | #include "base/logging.h" 2 | #include "base/run_loop.h" 3 | #include "base/task/single_thread_task_executor.h" 4 | #include "base/task/single_thread_task_runner.h" 5 | // #include "base/threading/thread_task_runner_handle.h" 6 | 7 | struct Test { 8 | int data; 9 | }; 10 | 11 | void Hello() { 12 | LOG(INFO) << "hello,demo!"; 13 | // CHECK(false); 14 | } 15 | 16 | int main(int argc, char** argv) { 17 | logging::LoggingSettings settings; 18 | settings.logging_dest = logging::LOG_TO_STDERR; 19 | logging::InitLogging(settings); 20 | logging::SetLogItems(true, true, true, false); 21 | // 在当前线程中创建消息循环。旧版本的 MessageLoop 被换成了 SingleThreadTaskExecutor 22 | // 详见 commit 636e705be41ed9e7f50cdb13ceb5a9af5e3f4e5c 23 | base::SingleThreadTaskExecutor main_thread_task_executor; 24 | 25 | base::RunLoop run_loop; 26 | 27 | // 创建任务 28 | main_thread_task_executor.task_runner()->PostTask(FROM_HERE, base::BindOnce(&Hello)); 29 | 30 | Test t{0}; 31 | main_thread_task_executor.task_runner()->PostTask(FROM_HERE, 32 | base::BindOnce( 33 | [](Test& t) { 34 | t.data = 100; 35 | DLOG(INFO) << "data1: " << t.data; 36 | }, 37 | std::ref(t))); 38 | 39 | // 获取当前线程的task runner,并使用它创建任务 40 | base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( 41 | FROM_HERE, base::BindOnce(&Hello)); 42 | 43 | // 启动消息循环,即使没有任务也会阻塞程序运行。当前进程中只有一个线程。 44 | // run_loop.Run(); 45 | 46 | // 启动消息循环,当所有的 task 执行完毕后退出 47 | run_loop.RunUntilIdle(); 48 | 49 | DLOG(INFO) << "data2: " << t.data; 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /demo_task/demo_task_thread.cc: -------------------------------------------------------------------------------- 1 | #include "base/check.h" 2 | #include "base/functional/bind.h" 3 | #include "base/functional/callback_forward.h" 4 | #include "base/location.h" 5 | #include "base/logging.h" 6 | #include "base/run_loop.h" 7 | #include "base/task/current_thread.h" 8 | #include "base/task/single_thread_task_executor.h" 9 | #include "base/task/single_thread_task_runner.h" 10 | #include "base/threading/thread.h" 11 | #include "base/threading/thread_restrictions.h" 12 | #include "base/time/time.h" 13 | 14 | std::optional g_quit_closure; 15 | 16 | void LogDelay(base::TimeTicks start_time, int count) { 17 | auto delay_delta = base::TimeTicks::Now() - start_time; 18 | LOG(INFO) << count << " task delay(ms): " << delay_delta.InMilliseconds(); 19 | if (count >= 9) { 20 | CHECK(g_quit_closure); 21 | g_quit_closure->Run(); 22 | return; 23 | } 24 | base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( 25 | FROM_HERE, base::BindOnce(LogDelay, base::TimeTicks::Now(), count + 1), 26 | base::Milliseconds(1)); 27 | } 28 | 29 | int main(int argc, char **argv) { 30 | logging::LoggingSettings settings; 31 | settings.logging_dest = logging::LOG_TO_STDERR; 32 | logging::InitLogging(settings); 33 | logging::SetLogItems(true, true, true, false); 34 | 35 | base::SingleThreadTaskExecutor main_thread_task_executor; 36 | base::RunLoop loop; 37 | g_quit_closure = loop.QuitClosure(); 38 | 39 | base::Thread thread("FooThreadName"); 40 | thread.Start(); 41 | thread.task_runner()->PostDelayedTask( 42 | FROM_HERE, base::BindOnce(LogDelay, base::TimeTicks::Now(), 0), 43 | base::Milliseconds(1)); 44 | 45 | LOG(INFO) << "main start"; 46 | loop.Run(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /demo_task/demo_task_thread_pool.cc: -------------------------------------------------------------------------------- 1 | #include "base/logging.h" 2 | #include "base/task/thread_pool.h" 3 | #include "base/task/thread_pool/thread_pool_instance.h" 4 | 5 | void Hello() { 6 | LOG(INFO) << "hello,demo!"; 7 | // CHECK(false); 8 | } 9 | 10 | int main(int argc, char** argv) { 11 | logging::LoggingSettings settings; 12 | settings.logging_dest = logging::LOG_TO_STDERR; 13 | logging::InitLogging(settings); 14 | logging::SetLogItems(true, true, true, false); 15 | // 初始化线程池,会创建新的线程,在新的线程中会创建消息循环 MessageLoop 16 | base::ThreadPoolInstance::CreateAndStartWithDefaultParams("Demo"); 17 | 18 | // 通过以下方法创建任务,默认在线程池中运行 19 | base::ThreadPool::PostTask(FROM_HERE, {base::TaskPriority::USER_VISIBLE}, base::BindOnce(&Hello)); 20 | 21 | // 或者通过创建新的TaskRunner来创建任务,TaskRunner可以控制任务执行的顺序以及是否在同一个线程中运行 22 | scoped_refptr task_runner_ = base::ThreadPool::CreateTaskRunner({ 23 | base::TaskPriority::USER_VISIBLE, 24 | }); 25 | task_runner_->PostTask(FROM_HERE, base::BindOnce(&Hello)); 26 | 27 | // 由于线程池默认不会阻塞程序运行,因此这里为了看到结果使用getchar()阻塞主线程。 28 | // (depreated)当前进程中共有4个线程,1个主线程,1个线程池Service线程,2个Worker线程。 29 | getchar(); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /demo_tracing/BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | import("//build/config/ui.gni") 3 | 4 | group("demo_tracing") { 5 | testonly = true 6 | 7 | deps = [ 8 | ":demo_tracing_console", 9 | ":demo_tracing_perfetto", 10 | ":demo_tracing_perfetto_content", 11 | ] 12 | } 13 | 14 | executable("demo_tracing_console") { 15 | sources = [ 16 | "demo_tracing_console.cc", 17 | ] 18 | 19 | deps = [ 20 | "//base", 21 | "//components/tracing:startup_tracing", 22 | ] 23 | } 24 | 25 | executable("demo_tracing_perfetto_content") { 26 | testonly = true 27 | 28 | sources = [ 29 | "demo_tracing_perfetto_content.cc" 30 | ] 31 | 32 | deps = [ 33 | "//base", 34 | "//components/tracing:startup_tracing", 35 | "//services/tracing:lib", 36 | "//services/tracing/public/cpp", 37 | "//content/test:test_support", 38 | ] 39 | } 40 | 41 | executable("demo_tracing_perfetto") { 42 | testonly = true 43 | 44 | sources = [ 45 | "demo_tracing_perfetto.cc" 46 | ] 47 | 48 | deps = [ 49 | "//base", 50 | "//components/tracing:startup_tracing", 51 | "//services/tracing:lib", 52 | "//services/tracing/public/cpp", 53 | "//mojo/public", 54 | "//mojo/core/embedder", 55 | "//services/tracing/public/cpp:traced_process", 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /demo_tracing/README.md: -------------------------------------------------------------------------------- 1 | 2 | # demo_tracing 3 | 4 | `vsync_auditor.html` 文件用于处理 `chrome://tracing` 页面上的 `Highlight VSync` 显示: 5 | 6 | ```c++ 7 | // third_party/catapult/tracing/tracing/extras/vsync/vsync_auditor.html 8 | 9 | const VSYNC_SLICE_PRECISIONS = { 10 | // Android. 11 | 'RenderWidgetHostViewAndroid::OnVSync': 5, 12 | // Android. Very precise. Requires "gfx" systrace category to be enabled. 13 | 'VSYNC': 10, 14 | // Linux. Very precise. Requires "gpu" tracing category to be enabled. 15 | 'vblank': 10, 16 | // Mac. Derived from a Mac callback (CVDisplayLinkSetOutputCallback). 17 | 'DisplayLinkMac::GetVSyncParameters': 5 18 | }; 19 | 20 | const BEGIN_FRAME_SLICE_PRECISION = { 21 | 'DisplayScheduler::BeginFrame': 10 22 | }; 23 | ``` 24 | 25 | 当使用以上这些字符串作为 trace name 的时候,`chrome://tracing` 可以显示帧率信息,比如使用以下任意一种 trace 就可以让自己的程序支持在`chrome://tracing`中显示 vsync。 26 | 27 | ```c++ 28 | TRACE_EVENT0("shell", "VSYNC"); 29 | TRACE_EVENT0("shell", "vblank"); 30 | // 这个是 chromium 内部使用的 31 | TRACE_EVENT2("viz", "DisplayScheduler::BeginFrame", "args", args,"now", now); 32 | ``` 33 | -------------------------------------------------------------------------------- /demo_views/BUILD.gn: -------------------------------------------------------------------------------- 1 | import("//build/config/ui.gni") 2 | import("//tools/grit/repack.gni") 3 | 4 | executable("demo_views") { 5 | testonly=true 6 | sources = [ 7 | "demo_views.cc", 8 | ] 9 | 10 | deps = [ 11 | ":pak", 12 | "//base:i18n", 13 | "//base", 14 | "//build/win:default_exe_manifest", 15 | "//components/viz/host", 16 | "//components/viz/service", 17 | "//mojo/core/embedder", 18 | "//skia", 19 | "//third_party/icu", 20 | "//ui/aura", 21 | "//ui/base", 22 | "//ui/base/ime/init", 23 | "//ui/compositor:test_support", 24 | "//ui/compositor", 25 | "//ui/display", 26 | "//ui/events", 27 | "//ui/gfx", 28 | "//ui/gfx/geometry", 29 | "//ui/gl", 30 | "//ui/gl/init", 31 | "//ui/views:test_support", 32 | "//ui/views", 33 | ] 34 | 35 | if (ozone_platform_x11) { 36 | deps += [ "//ui/gfx/x" ] 37 | } 38 | } 39 | 40 | repack("pak") { 41 | testonly = true 42 | sources = [ 43 | "$root_gen_dir/ui/resources/ui_resources_100_percent.pak", 44 | # "$root_gen_dir/ui/resources/webui_resources.pak", 45 | "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak", 46 | "$root_gen_dir/ui/strings/ui_strings_en-US.pak", 47 | ] 48 | 49 | deps = [ 50 | "//ui/resources", 51 | "//ui/strings", 52 | ] 53 | 54 | if (toolkit_views) { 55 | deps += [ "//ui/views/resources" ] 56 | sources += 57 | [ "$root_gen_dir/ui/views/resources/views_resources_100_percent.pak" ] 58 | } 59 | output = "$root_out_dir/demo_views.pak" 60 | } 61 | 62 | -------------------------------------------------------------------------------- /demo_views/README.md: -------------------------------------------------------------------------------- 1 | # demo_views 2 | 3 | demo_views 使用 `//ui/views` 来构建程序界面。 4 | 5 | ## `//ui/views` 6 | 7 | 主要用于桌面端的 UI 开发,比如 Windows/Linux 上的浏览器工具栏,地址栏等。它依赖 cc,aura 和 viz 等底层框架。 8 | 9 | TODO: 完善文档 10 | 11 | Views 在 OnPaint 中将自己所要呈现的内容绘制到 Canvas 中,这个 Canvas 将绘制操作记录到 PaintOpBuffer 中(并不立即进行真实的绘制)。 12 | 13 | 在以下文件中可以查看哪些绘制操作可以被记录,以及如何被记录。 14 | cc/paint/paint_op_buffer.h 15 | -------------------------------------------------------------------------------- /demo_viz/BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | import("//build/config/ui.gni") 3 | 4 | template("viz") { 5 | executable(target_name){ 6 | testonly = true 7 | forward_variables_from(invoker, "*") 8 | 9 | deps = [ 10 | "//base", 11 | "//base:i18n", 12 | "//build/win:default_exe_manifest", 13 | "//components/viz/host", 14 | "//components/viz/client", 15 | "//components/viz/service", 16 | "//components/viz/service/main", 17 | "//mojo/core/embedder", 18 | "//skia", 19 | "//ui/events", 20 | "//ui/events/platform", 21 | "//ui/platform_window", 22 | "//gpu", 23 | "//gpu/ipc/host", 24 | "//components/discardable_memory/service", 25 | "//components/discardable_memory/client", 26 | "//services/viz/public/cpp/gpu", 27 | ] 28 | 29 | if (ozone_platform_x11) { 30 | deps += [ 31 | "//ui/events/platform/x11", 32 | "//ui/ozone", 33 | ] 34 | #configs += [ "//build/config/linux:x11" ] 35 | } 36 | 37 | if (is_win) { 38 | deps += [ 39 | "//ui/platform_window/win:win", 40 | ] 41 | } 42 | 43 | } 44 | } 45 | 46 | group("demo_viz") { 47 | testonly = true 48 | deps = [ 49 | ":demo_viz_gui", 50 | ":demo_viz_offscreen", 51 | ] 52 | if (!is_win) { 53 | # windows暂时编译不过 54 | deps += [ 55 | ":demo_viz_layer_offscreen", 56 | ":demo_viz_layer", 57 | ":demo_viz_gui_gpu", 58 | ] 59 | } 60 | } 61 | 62 | viz("demo_viz_gui") { 63 | sources = [ 64 | "demo_viz_gui.cc" 65 | ] 66 | } 67 | 68 | viz("demo_viz_gui_gpu") { 69 | sources = [ 70 | "demo_viz_gui_gpu.cc" 71 | ] 72 | } 73 | 74 | viz("demo_viz_offscreen") { 75 | sources = [ 76 | "demo_viz_offscreen.cc" 77 | ] 78 | } 79 | 80 | viz("demo_viz_layer") { 81 | sources = [ 82 | "demo_viz_layer.cc" 83 | ] 84 | } 85 | 86 | viz("demo_viz_layer_offscreen") { 87 | sources = [ 88 | "demo_viz_layer_offscreen.cc", 89 | "demo_viz_layer_offscreen_client.cc" 90 | ] 91 | } 92 | -------------------------------------------------------------------------------- /demo_viz/README.md: -------------------------------------------------------------------------------- 1 | # demo_viz 2 | 3 | 演示 viz 相关接口的使用,需要注意的是,所有 demo 都没有处理潜在的资源释放,仅供参考。 4 | 5 | ## demo_viz_offscreen 6 | 7 | demo_viz_offscreen 演示了直接使用 viz 内部的接口来进行离屏渲染。 8 | 9 | ## demo_viz_gui 10 | 11 | demo_viz_gui 演示了使用 viz 提供的 mojo 接口进行 GUI 软件渲染。 12 | 这些 mojo 接口内部包装了 demo_viz_offscreen 所演示的技术并添加了多种 DrawQuad 的使用演示。 13 | 该 demo 还增加了 client raster 以及多 FrameSink 的演示。 14 | 15 | ## demo_viz_gui_gpu 16 | 17 | demo_viz_gui_gpu 在 demo_viz_gui 的基础上添加了对硬件渲染的支持。 18 | 重点在于如何初始化硬件渲染环境以及如何使用GPU资源,项目中需要注意资源的释放。 19 | 20 | TODO: 解决 client 端 raster 的偏色问题。 21 | 22 | ## demo_viz_layer 23 | 24 | demo_viz_layer 添加了用户交互控制,重点在于如何控制 UI 的局部刷新及 UI 没有改变的时候的不刷新。 25 | 同时该 demo 支持使用命令行切换渲染模式以及将渲染结果保存到文件。 26 | 27 | ## demo_viz_layer_offscreen 28 | 29 | demo_viz_layer 演示使用 CopyOutput/SkiaOutputDeviceOffscreen 接口来实现 viz 离屏渲染,然后再将离屏画面渲染到窗口上。 30 | 注意该demo需要先打 patch: patches/0001-*.path 31 | 32 | ## viz 调试技巧 33 | 34 | tracing categories: 35 | 36 | `viz,gpu,ipc,mojom,skia,disabled-by-default-toplevel.flow` 获取详细的 viz 以及 gpu 执行情况。 37 | `disabled-by-default-gpu.service` 获取 commandbuffer decoder的执行情况。 38 | 39 | 命令行参数: 40 | 41 | `--enable-gpu-service-tracing` 启动 gpu service tracing,每一个 GL 调用都会被记录到 Trace 中。 42 | `--use_virtualized_gl_contexts=0` 禁用 virtual GL Context,降低追踪的复杂度。 43 | -------------------------------------------------------------------------------- /demo_viz/demo_viz_layer_offscreen_client.h: -------------------------------------------------------------------------------- 1 | #ifndef DEMO_DEMO_VIZ_DEMO_VIZ_LAYER_OFFSCREEN_CLIENT_H 2 | #define DEMO_DEMO_VIZ_DEMO_VIZ_LAYER_OFFSCREEN_CLIENT_H 3 | 4 | #include "gpu/command_buffer/service/shared_context_state.h" 5 | #include "gpu/config/gpu_preferences.h" 6 | #include "ui/gfx/geometry/size.h" 7 | #include "ui/gfx/native_widget_types.h" 8 | #include "ui/gl/gl_share_group.h" 9 | #include "components/viz/service/gl/gpu_service_impl.h" 10 | 11 | void InitHostMain(gfx::AcceleratedWidget widget, 12 | gfx::Size size, 13 | viz::GpuServiceImpl* gpu_service); 14 | 15 | void Redraw(); 16 | 17 | #endif // DEMO_DEMO_VIZ_DEMO_VIZ_LAYER_OFFSCREEN_CLIENT_H -------------------------------------------------------------------------------- /demo_x11/BUILD.gn: -------------------------------------------------------------------------------- 1 | 2 | import("//build/config/ui.gni") 3 | 4 | executable("demo_x11") { 5 | testonly = true 6 | 7 | sources = [ 8 | "demo_x11.cc", 9 | ] 10 | 11 | deps = [ 12 | "//base", 13 | "//base:i18n", 14 | "//gpu", 15 | "//gpu:gles2", 16 | "//gpu:raster", 17 | "//gpu/command_buffer/client", 18 | "//gpu/command_buffer/client:gles2_cmd_helper", 19 | "//gpu/command_buffer/service", 20 | "//gpu/command_buffer/service:gles2", 21 | "//ui/base", 22 | "//ui/gl", 23 | "//ui/gl/init", 24 | "//ui/events", 25 | "//ui/events/platform", 26 | "//ui/platform_window", 27 | # 直接依赖它会导致和chromium中的变量定义冲突 28 | #"//third_party/skia", 29 | "//skia", 30 | ":demo_x11_glx", 31 | ":demo_x11_egl", 32 | ] 33 | 34 | if (ozone_platform_x11) { 35 | deps += [ 36 | "//ui/events/platform/x11", 37 | "//ui/ozone", 38 | ] 39 | # configs += [ "//build/config/linux:x11" ] 40 | } 41 | 42 | libs = ["EGL","GLESv2"] 43 | } 44 | 45 | executable("demo_x11_glx") { 46 | testonly = true 47 | 48 | sources = [ 49 | "demo_x11_glx.cc", 50 | ] 51 | 52 | deps = [ 53 | "//base", 54 | "//base:i18n", 55 | "//gpu", 56 | "//gpu:gles2", 57 | "//gpu:raster", 58 | "//gpu/command_buffer/client", 59 | "//gpu/command_buffer/client:gles2_cmd_helper", 60 | "//gpu/command_buffer/service", 61 | "//gpu/command_buffer/service:gles2", 62 | "//ui/base", 63 | "//ui/gl", 64 | "//ui/gl/init", 65 | "//ui/events", 66 | "//ui/events/platform", 67 | "//ui/platform_window", 68 | # 直接依赖它会导致和chromium中的变量定义冲突 69 | #"//third_party/skia", 70 | "//skia", 71 | ] 72 | 73 | # configs += [ "//build/config/linux:x11" ] 74 | 75 | libs = ["EGL","GLESv2","X11","GL"] 76 | } 77 | 78 | 79 | executable("demo_x11_egl") { 80 | testonly = true 81 | 82 | sources = [ 83 | "demo_x11_egl.cc", 84 | ] 85 | 86 | deps = [ 87 | "//base", 88 | "//base:i18n", 89 | "//gpu", 90 | "//gpu:gles2", 91 | "//gpu:raster", 92 | "//gpu/command_buffer/client", 93 | "//gpu/command_buffer/client:gles2_cmd_helper", 94 | "//gpu/command_buffer/service", 95 | "//gpu/command_buffer/service:gles2", 96 | "//ui/base", 97 | "//ui/gl", 98 | "//ui/gl/init", 99 | "//ui/events", 100 | "//ui/events/platform", 101 | "//ui/platform_window", 102 | # 直接依赖它会导致和chromium中的变量定义冲突 103 | #"//third_party/skia", 104 | "//skia", 105 | ] 106 | 107 | # configs += [ "//build/config/linux:x11" ] 108 | 109 | libs = ["EGL","GLESv2","X11","GL"] 110 | } 111 | -------------------------------------------------------------------------------- /demo_x11/README.md: -------------------------------------------------------------------------------- 1 | # demo_x11 2 | 3 | 这个目录包含以下几个demo: 4 | 5 | - demo_x11: 演示在 Chromium 中使用 X11 创建透明窗口; 6 | - demo_x11_glx: 演示在透明窗口中使用 glx; 7 | - demo_x11_egl: 演示在透明窗口中使用 egl; 8 | -------------------------------------------------------------------------------- /docs/content.md: -------------------------------------------------------------------------------- 1 | # content 2 | 3 | //content 模块可以分为以下几个相对独立的部分: 4 | 5 | 1. 负责多进程架构通用部分的初始化; 6 | 2. 负责 Browser/Renderer/Gpu/Utility 等进程专有部分的初始化; 7 | 3. Browser 进程负责的功能: 浏览器界面的创建,相关窗口句柄的维护,生成浏览器界面相关的CompositorFrame发送到Gpu进程,WebContents接口的调用,Renderer/Gpu进程的创建及相关通信通道的建立; 8 | 4. Renderer 进程负责的功能: Blink 的初始化,网页的渲染,生成网页相关的CompositorFrame发送到Gpu进程; 9 | 5. Gpu 进程负责的功能: CompositorFrame的渲染,提供Gpu Raster功能; 10 | 11 | TODO: 完善 content 模块的相关文档 12 | -------------------------------------------------------------------------------- /docs/images/2020-01-03-09-53-49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-01-03-09-53-49.png -------------------------------------------------------------------------------- /docs/images/2020-01-03-10-00-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-01-03-10-00-48.png -------------------------------------------------------------------------------- /docs/images/2020-01-03-10-01-55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-01-03-10-01-55.png -------------------------------------------------------------------------------- /docs/images/2020-01-03-13-48-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-01-03-13-48-06.png -------------------------------------------------------------------------------- /docs/images/2020-01-03-13-49-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-01-03-13-49-40.png -------------------------------------------------------------------------------- /docs/images/2020-01-03-14-13-56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-01-03-14-13-56.png -------------------------------------------------------------------------------- /docs/images/2020-01-03-15-10-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-01-03-15-10-02.png -------------------------------------------------------------------------------- /docs/images/2020-01-03-17-09-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-01-03-17-09-31.png -------------------------------------------------------------------------------- /docs/images/2020-05-22-17-09-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/2020-05-22-17-09-02.png -------------------------------------------------------------------------------- /docs/images/chromium-mojo-layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/chromium-mojo-layer.png -------------------------------------------------------------------------------- /docs/images/mojo_interface_pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/mojo_interface_pipe.png -------------------------------------------------------------------------------- /docs/images/mojo_stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/docs/images/mojo_stack.png -------------------------------------------------------------------------------- /docs/startup.md: -------------------------------------------------------------------------------- 1 | # 浏览器启动流程简述 2 | 3 | 以下内容可以参考`demo_shell`的相关代码。 4 | 5 | 浏览器的启动流程可以简单分为以下几个阶段: 6 | 7 | 1. 初始化Content模块; 8 | 2. 初始化Browser进程; 9 | 3. 创建GPU进程; 10 | 4. 创建UI; 11 | 5. 创建Render进程; 12 | 13 | > content初始化相关类图见: 14 | 15 | ## 初始化Content模块(和Browser进程) 16 | 17 | content 通过被 services 模块启动。 18 | 19 | content实现了services 模块提供的接口,并且在 content::ContentMain() 中启动(services模块提供的) service_manager::Main() ,在这个函数中进行一些通用的初始化工作,最后(将content作为services的embedder)启动由content实现的RunEmbedderProcess()方法,至此servcies模块将控制权完全转移到content模块的ContentMainRunner。 20 | 21 | ContentMainRunner会启动ServiceManager,最后通过调用BrowserMain()将控制权转移到browser子模块。 22 | 23 | BrowserMain()通过BrowserMainRunner继续启动,BrowserMainRunner包装了BrowserMainLoop,BrowserMainLoop的主要功能包括: 24 | 25 | 1. 调用BrowserMainParts,以便允许用户的逻辑被执行; 26 | 1. 调用content::BrowserStartupComplete(),以便通知Android初始化完成; 27 | 1. 初始化主线程; 28 | 1. 创建IO线程; 29 | 1. 初始化Mojo; 30 | 1. 初始化音视频/麦克风/触摸屏等设备; 31 | 1. 初始化WebRTC; 32 | 1. 初始化剪切板相关服务; 33 | 1. 根据需求启动GPU进程; 34 | 1. 启动主线程的消息循环; 35 | 36 | BrowserMainParts作为Browser初始化的末端,用户在这里进行扩展,插入创建UI的逻辑。 37 | 38 | ``` 39 | #0 content/public/browser/browser_main_parts.cc:*() 40 | #1 content/browser/browser_main_loop.cc:*() 41 | #2 content/browser/browser_main_runner_impl.cc:*() 42 | #3 content/browser/browser_main.cc:43:BrowserMain() 43 | #4 content/app/content_main_runner_impl.cc529:RunBrowserProcessMain() 44 | #5 content/app/content_main_runner_impl.cc:978:RunServiceManager() 45 | #6 content/app/content_main_runner_impl.cc:878:Run() 46 | #7 content/app/content_service_manager_main_delegate.cc:52:RunEmbedderProcess() 47 | ``` 48 | 49 | 综上,Browser进程的初始化流程如下: 50 | content::ContentMain()->service_manager::Main()->SerivceManagerMainDelegate->ContentMainRunner->content::BrowserMain()->BrowserMainRunner->BrowserMainLoop->BrowserMainParts->(创建UI) 51 | 52 | ## 创建GPU进程 53 | 54 | TODO 55 | 56 | ## 创建UI 57 | 58 | Browser初始化完成之后,会在BrowserMainParts中创建UI。 59 | 60 | > 注意:并不是一定要在这里创建UI,因为创建UI是一个相对独立的过程,可以放在任何业务觉得合适的时机,比如放在用户打开某一个网页的时候再创建。 61 | 62 | 创建UI可以分为以下几步: 63 | 64 | 1. 创建Native窗口; 65 | 2. 创建WebContents,并将WebContents和Native窗口关联; 66 | 67 | 初始化OutputSurface 68 | 69 | ContentViewRenderView 用来显示网页内容,它内部维护了一个SurfaceView/TextureView,并且将他们的Surface传递到Native层,Native层使用它们创建OutputSurface,并且在该OutputSurface上绘制网页内容。 70 | 71 | TODO 72 | 73 | ## 创建Render进程 74 | 75 | Render进程并不会一开始就创建,而是在要打开某一个网页的时候才创建。 76 | 77 | Render进程的启动流程如下: 78 | WebContents->NavigationController->NavigationRequest->RenderFrameHostManager->SiteInstance->RenderProcessHost::Init()->ChildProcessLauncher 79 | 80 | 由于RenderProcess是按需启动的,因此它的启动流程比较复杂。 81 | 82 | TODO 83 | -------------------------------------------------------------------------------- /docs/ui.md: -------------------------------------------------------------------------------- 1 | # UI 2 | 3 | UI 分两部分,一部分是窗口,一部分是控件。 4 | 5 | chromium 中对窗口的包装包括: 6 | 7 | - aura 8 | - PlatformWindow 9 | - X11/Ozone/Windows 10 | 11 | chromium 中对UI控件的包装包括: 12 | 13 | - views 14 | - cc 15 | - viz 16 | 17 | chromium 中对渲染的包装包括: 18 | 19 | - skia 20 | - command buffer 21 | - angle 22 | - egl/opengl(es) 23 | 24 | TODO: 完善文档 25 | 26 | > views 和 WebContents 相关类图见: 27 | -------------------------------------------------------------------------------- /patches/0001-demo_viz_layer_offscreen-add-GetOffscreenTextureId.patch: -------------------------------------------------------------------------------- 1 | From dcf992dac28c1d35803596ea8d59b6a737689ce3 Mon Sep 17 00:00:00 2001 2 | From: keyou 3 | Date: Sat, 1 Aug 2020 11:06:30 +0800 4 | Subject: [PATCH] demo_viz_layer_offscreen: add GetOffscreenTextureId 5 | 6 | --- 7 | .../viz/service/display/skia_output_surface.h | 3 +++ 8 | .../skia_output_device_offscreen.cc | 16 +++++++++++++++- 9 | 2 files changed, 18 insertions(+), 1 deletion(-) 10 | 11 | diff --git a/components/viz/service/display/skia_output_surface.h b/components/viz/service/display/skia_output_surface.h 12 | index 2f06602e9c0d..d014af23bdf2 100644 13 | --- a/components/viz/service/display/skia_output_surface.h 14 | +++ b/components/viz/service/display/skia_output_surface.h 15 | @@ -41,6 +41,9 @@ namespace copy_output { 16 | struct RenderPassGeometry; 17 | } // namespace copy_output 18 | 19 | +#define VIZ_GETOFFSCREENTEXTUREID 20 | +VIZ_SERVICE_EXPORT GrGLuint GetOffscreenTextureId(); 21 | + 22 | // This class extends the OutputSurface for SkiaRenderer needs. In future, the 23 | // SkiaRenderer will be the only renderer. When other renderers are removed, 24 | // we will replace OutputSurface with SkiaOutputSurface, and remove all 25 | diff --git a/components/viz/service/display_embedder/skia_output_device_offscreen.cc b/components/viz/service/display_embedder/skia_output_device_offscreen.cc 26 | index 9d38dda19d9d..721d09e20d97 100644 27 | --- a/components/viz/service/display_embedder/skia_output_device_offscreen.cc 28 | +++ b/components/viz/service/display_embedder/skia_output_device_offscreen.cc 29 | @@ -8,6 +8,7 @@ 30 | 31 | #include "gpu/command_buffer/service/skia_utils.h" 32 | #include "third_party/skia/include/core/SkSurface.h" 33 | +#include "components/viz/service/display/skia_output_surface.h" 34 | 35 | namespace viz { 36 | 37 | @@ -16,9 +17,14 @@ namespace { 38 | // Some Vulkan drivers do not support kRGB_888x_SkColorType. Always use 39 | // kRGBA_8888_SkColorType instead and initialize surface to opaque as necessary. 40 | constexpr SkColorType kSurfaceColorType = kRGBA_8888_SkColorType; 41 | +GrGLuint g_offscreen_texture_id = 0; 42 | 43 | } // namespace 44 | 45 | +GrGLuint GetOffscreenTextureId() { 46 | + return g_offscreen_texture_id; 47 | +} 48 | + 49 | SkiaOutputDeviceOffscreen::SkiaOutputDeviceOffscreen( 50 | scoped_refptr context_state, 51 | bool flipped, 52 | @@ -55,8 +61,16 @@ void SkiaOutputDeviceOffscreen::SwapBuffers( 53 | std::vector latency_info) { 54 | // Reshape should have been called first. 55 | DCHECK(backend_texture_.isValid()); 56 | - 57 | + TRACE_EVENT0("viz", "SkiaOutputDeviceOffscreen::SwapBuffers"); 58 | StartSwapBuffers(std::move(feedback)); 59 | + 60 | + GrBackendTexture skia_texture = 61 | + sk_surface_->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess); 62 | + GrGLTextureInfo gl_texture_info; 63 | + skia_texture.getGLTextureInfo(&gl_texture_info); 64 | + g_offscreen_texture_id = gl_texture_info.fID; 65 | + DCHECK(g_offscreen_texture_id); 66 | + 67 | FinishSwapBuffers(gfx::SwapResult::SWAP_ACK, 68 | gfx::Size(size_.width(), size_.height()), 69 | std::move(latency_info)); 70 | -- 71 | 2.17.1 72 | 73 | -------------------------------------------------------------------------------- /patches/0002-demo_mojo_v8.patch: -------------------------------------------------------------------------------- 1 | diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn 2 | index 9fedd83307439..4ef0925545e31 100644 3 | --- a/chrome/browser/BUILD.gn 4 | +++ b/chrome/browser/BUILD.gn 5 | @@ -1868,6 +1868,8 @@ static_library("browser") { 6 | ] 7 | 8 | public_deps = [ 9 | + # 加入我们的依赖 10 | + "//demo/demo_mojo_v8:browser", 11 | "//base", 12 | "//chrome/common", 13 | "//chrome/common:buildflags", 14 | diff --git a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc 15 | index 5feac0c791c70..7cbd4bb5d9e31 100644 16 | --- a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc 17 | +++ b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc 18 | @@ -73,6 +73,8 @@ 19 | #endif 20 | #endif 21 | 22 | +#include "demo/demo_mojo_v8/browser/demo_impl.h" 23 | + 24 | namespace { 25 | 26 | // Helper method for ExposeInterfacesToRenderer() that checks the latest 27 | @@ -134,6 +136,10 @@ void ChromeContentBrowserClient::ExposeInterfacesToRenderer( 28 | service_manager::BinderRegistry* registry, 29 | blink::AssociatedInterfaceRegistry* associated_registry, 30 | content::RenderProcessHost* render_process_host) { 31 | + 32 | + // 注册 DemoImpl 33 | + demo::DemoImpl::Initialize(registry); 34 | + 35 | // The CacheStatsRecorder is an associated binding, instead of a 36 | // non-associated one, because the sender (in the renderer process) posts the 37 | // message after a time delay, in order to rate limit. The association 38 | diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn 39 | index cd4395923de75..a739f6e632fa3 100644 40 | --- a/chrome/renderer/BUILD.gn 41 | +++ b/chrome/renderer/BUILD.gn 42 | @@ -145,6 +145,8 @@ static_library("renderer") { 43 | public_deps = [ "//components/contextual_search:buildflags" ] 44 | 45 | deps = [ 46 | + #加入我们的依赖 47 | + "//demo/demo_mojo_v8:renderer", 48 | "//base/allocator:buildflags", 49 | "//build:chromeos_buildflags", 50 | "//chrome:resources", 51 | diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc 52 | index ceb29f83a9dc1..c7fe313e195fc 100644 53 | --- a/chrome/renderer/chrome_content_renderer_client.cc 54 | +++ b/chrome/renderer/chrome_content_renderer_client.cc 55 | @@ -234,6 +234,8 @@ 56 | #include "chrome/renderer/supervised_user/supervised_user_error_page_controller_delegate_impl.h" 57 | #endif 58 | 59 | +#include "demo/demo_mojo_v8/renderer/demo_render_frame_observer.h" 60 | + 61 | using autofill::AutofillAgent; 62 | using autofill::AutofillAssistantAgent; 63 | using autofill::PasswordAutofillAgent; 64 | @@ -467,6 +469,11 @@ void ChromeContentRendererClient::ExposeInterfacesToBrowser( 65 | 66 | void ChromeContentRendererClient::RenderFrameCreated( 67 | content::RenderFrame* render_frame) { 68 | + 69 | + // 创建 Observer 并监听 70 | + // 这不会导致内存泄漏,因为 render_frame 会通知它释放自己的内存 71 | + new demo::DemoRenderFrameObserver(render_frame); 72 | + 73 | ChromeRenderFrameObserver* render_frame_observer = 74 | new ChromeRenderFrameObserver(render_frame, web_cache_impl_.get()); 75 | service_manager::BinderRegistry* registry = render_frame_observer->registry(); 76 | -------------------------------------------------------------------------------- /wechat.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keyou/chromium_demo/489185ebad7deb2a3155e1d4abdfdf8bf62eb0bd/wechat.jpeg --------------------------------------------------------------------------------